Django get models by model name - python-3.x

In Django I know that there is one and only one model with name foo, but I don't know the app that this model is registered with! How can I get the model with only model_name?

As the answers to Django: Get model from string? show, you need either the app_name string or an AppConfig object to get a model from model_name.
However, you can use apps.get_app_configs() to iterate over AppConfig instances, so something like this is possible:
from django.apps import apps
for app_conf in apps.get_app_configs():
try:
foo_model = app_conf.get_model('foo')
break # stop as soon as it is found
except LookupError:
# no such model in this application
pass
Note that this iterable will include base django apps that are in INSTALLED_APPS like admin, auth, contenttypes, sessions, messages and staticfiles.

Related

How to access user details in all pages in django?

After login I want to access User details when ever I want (Particularly in navigation bar).
I did not use user model provided in django. I created my own model like this for authentication.
My database is stored in mysql on phpmyadmin(Xampp).
AdminUser Model
class adminUser(models.Model):
username=models.CharField(max_length=50)
firstname=models.CharField(max_length=50)
department=models.CharField(max_length=50)
name=models.CharField(max_length=50)
mail=models.CharField(max_length=50)
id=models.IntegerField(primary_key=True)
password=models.CharField(max_length=200)
class Meta:
db_table="admin_users"
admin_users.py
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username is not None and password is not None:
user=adminUser.objects.get(username=username)
hashed_password = user.password
is_check = bcrypt.checkpw(password.encode('utf8'),hashed_password.encode('utf8'))
print(is_check)
if is_check==True:
return redirect(reverse('faq_index'))
else:
return render(request,'AdminUsers/login.html')
return render(request,'AdminUsers/login.html')
During the login User Details can be only access by login function but I want to access user details in all pages for navigation bar and also want to find out whether user is authenticated or not. As I am not using User Model defined in django so I can not use user.is_authenticated(). So How do I do this?
First, inherit your user model from AbstractBaseUser. It gives you some features like is_authenticated, set_password and etc
Then define your custom user model as AUTH_USER_MODEL in your settings.py
After these, django treats to your custom user as its default user
models.py
from django.contrib.auth.base_user import AbstractBaseUser
class CustomUser(AbstractBaseUser):
...
settings.py
AUTH_USER_MODEL = 'myapp.MyUser'
Docs in https://docs.djangoproject.com/en/3.2/topics/auth/customizing/
I'm gonna recommend you take a step back, and extend the built-in User model instead of creating your own.
As mentioned by #Amin, you can extend the AbstractBaseUser class to create a custom User model, and override the AUTH_USER_MODEL in settings.py.
However, you can easily add a Profile model that has a one-to-one relationship with the built-in User model that does not require any overrides (which method is better escapes me at the moment, but I use the following method without issue):
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models
UserModel = get_user_model()
class Profile(models.Model):
user = models.OneToOneField(UserModel, on_delete=models.CASCADE)
# add your desired fields here
department=models.CharField(max_length=50)
Then, in the same folder as contains your models.py, create a file called signals.py, and add the following code:
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Profile
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_user_settings(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
This will trigger the creation of a new Profile object whenever a User object is created.
Then, add the following to the same folder's apps.py (Assuming the app's name is users... make it match the name of the app that contains your Profile model):
from django.apps import AppConfig
class UsersConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'users'
def ready(self):
import users.signals
Now, after you run your migrations, you will be able to use the built-in User model, and add additional fields to it as desired in the Profile model.
The only downside is that it will require a little extra work if you want to modify the User model and the Profile model on the same page (ie. you won't just be able to specify the model name in an UpdateView).
I don't remember where I found this method. I believe it was adapted from this page on simpleisbetterthancomplex.com, but I'm not 100% sure.
At any rate, Django automatically creates a primary key id for you, so you probably don't need to manually define that in your model.

default value of model.UUIDField() doesnt seem to be called in django graphene

I am trying to build an application with django and graphene and I want to set a default value for one of the fields in my model. The mutation is really straight forward. I've passed all the required arguments as objects and the optional ones with **kwargs.
Django's docs on **options for models.UUIDField() says that if None type object is sent to the model field, default value will be used.
When I try to use my mutation without passing any values/ passing None as a value to the argument, I get graphql.error.located_error.GraphQLLocatedError: NOT NULL constraint failed: games_game.groupid error is raised.
Here is a pastebin for Tracebacks, models.py and schema.py to my project.
A developer from django made me regular constructor rules apply on django models as well!
here is a simple fix to my problem for anyone in the future.
groupid = kwargs.get('groupid', None)
gid_extra = {'groupid': groupid} if groupid else {}
game = Game(name=name, price=price, datereleased=datereleased,
description=description, **gid_extra)
game.save()

Run Flask on demand to visualize computed data

Using Python 3.7, I made a CLI utility which prints some results to stdout. Depending on an option the results should be visualized in a browser (single user, no sessions). Flask seems to be a good choice for this. However, this is not a standard usecase described in the docs or in tutorials.
I am looking for a best practise way to pass the data (e.g. a Python List) to the Flask app so that I can return it from view functions. Basically it would be immutable application data. The following seems to work but I don't like to use globals:
main.py:
import myapp
result = compute_stuff()
if show_in_browser:
myapp.data = result
myapp.app.run()
myapp.py:
from flask import Flask
from typing import List
app = Flask(__name__)
result: List
#app.route("/")
def home():
return f"items: {len(result)}"
Reading the Flask docs I get the impression I should use an application context. On the other hand, its lifetime does not span across requests and I would not know how to populate it. Reading other questions I might use a Flask config object because it seems to be available on every request. But this is not really about configuration. Or maybe I should use Klein, inspired by this answer?
There does not seem to be a best practice way. So I am going with a modification of my original approach:
class MyData:
pass
class MyApp(Flask):
def __init__(self) -> None:
super().__init__(__name__)
self.env = "development"
self.debug = True
def getData(self) -> MyData:
return self._my_data
def setMyData(self, my_data: MyData) -> None:
self._my_data = my_data
app = MyApp()
This way I can set the data after the app instance was already created - which is necessary to be able to use it in routing decorators defined outside of the class. It would be nice to have more encapsulation: use app methods for routing (with decorators) instead of module global functions accessing a module global app object. Apparently that is not flaskic.

Django viewflow: not receiving flow_finished signal

I'm trying to catch the flow_finished signal from django viewflow like this
flow_finished.connect(function)
but it's not working. The function isn't called even if the flow finishes.
Any help please, I'm pretty lost.
In my app's init.py I added this
from django.apps import AppConfig
default_app_config = 'test.TestConfig'
class TestConfig(AppConfig):
name = 'test'
verbose_name = 'Test'
def ready(self):
import viewflow.signals
First, you need to ensure that you properly configured you app config, and the ready method really been called. Check your installed apps that you properly included your TestConfig, or if you use shortcuts, check you test/__init__.py default_app_config value
from viewflow.signals import flow_finished
def receiver(sender, **kwargs):
print('hi')
class TestConfig(AppConfig):
name = 'test'
def ready(self):
flow_finished.connect(receiver)
But generally, using signals to weave your codebase is a bad taste. To call an action before flow.End you can explicitly add flow.Handler. That's the recommended solution.

Mocking in Odoo environment?

Does anyone know how can you write mock tests for Odoo objects?
I have these classes and methods:
my_module:
from odoo import models
class MyModel(models.Model):
_name = 'my.model'
def action_copy(self):
IrTranslation = self.env['ir.translation']
for rec in self:
if rec.translate:
IrTranslation.force_translation(rec)
my_module_2:
from odoo import models
class IrTranslation(models.Model):
_inherit = 'ir.translation'
def force_translation(self, rec):
# do stuff
When I call it, I want to test if IrTranslation.force_translation was called in action_copy method and how many times.
But this method is not imported directly, it is referenced through env.
If let say force_translation would be imported like:
from my_module_2.IrTranslation import force_translation
def action_copy(self):
# do stuff.
force_translation()
Then I could try doing something like this:
from unittest import mock
from my_module import action_copy
def test_some_1(self):
with mock.patch('my_module.my_module_2.IrTranslation') as mocked_translation:
action_copy()
mocked_translation.force_translation.assert_called_once()
But because modules in Odoo are not imported directly (like you do it in plain Python), I don't understand how to specify methods in Odoo environment to be mocked.
P.S. I also did not see any mocked tests in standard Odoo, except for base classes that do not inherit Model class -> which then you need to use its _inherit attribute instead of importing class and passing it to be inherited on another class.
Testing in Odoo does not use the concept of mocking. Instead, tests are derived from standard base classes. The standard class TransactionalTest opens a transaction and never commits it, but rolls it back to undo any changes.
This is obviously not the same as regular mocking in that you can't replace other methods or classes to return fixed/expected values and/or avoid other side effects apart from persisting changes in the database, like sending emails or calling a remote web service.
It can be done. I do it all the time since Odoo 8.0 (until 15.0 now). The key is to know where to patch. Odoo adds odoo.addons to your module's package when its imported so in your case, you may do the following:
from odoo import tests
from mock import patch
from odoo.addons.my_module_2.models.ir_translations import IrTranslation
class TestMyModule2(tests.TransactionCase):
def some_test_1(self):
my_model = self.env['my.model'].create({})
with patch.object(IrTranslation, 'force_translation') as mocked_translation:
my_model.action_copy()
mocked_translation.assert_called_once()
Or using just patch, then no need to import:
with patch('odoo.addons.my_module_2.models.ir_translations.IrTranslation.force_translation') as mocked_translation:
my_model.action_copy()
This patches your specific method in your specific class. This way you can also target the method of a super class.
If you need to patch a method and you don't care where it is or where it's overriden, just patch using Python's type() (then no need to import class):
with patch.object(type(self.env['ir.translation']), 'force_translation') as mocked_translation:
my_model.action_copy()
Some additional notes to save you some headaches:
If you use pyCharm, don't mock socket objects. It messes with
pyCharm's mechanismes. Better to put your calls to socket into a one line
method and mock that method instead.
datetime.datetime.now() cannot be mocked, as all builtin types, but fields.Datetime.now() can.

Resources