I have a moderately complicated Django project with a variety of different apps (app1, app2 etc), each with their own models. I am building a MetaApp app to track info about each app, with a MetaApp class in models.py, and fields such as appname and modelname
MetaApp drives an index view that summarizes various aspects of each project. I would like to include a count of the database records for each app. This means that I need to programmatically access models from other apps. If I I know the appname and modelname, how do I programmatically access these models?
projects = MetaApp.objects.all()
projects[0].appname[0].modelname.ojects.all()
This code results in an attribute error, because I am storing the appname and modelname as unicode strings. What is the workaround?
Use the django.db.models.loading.get_model() function:
from django.db.models.loading import get_model
model = get_model(app_name, model_name)
object_list = model.objects.all()
Related
If I have a PostgresDB that contains both Django models and other SQL tables, is it possible to register these other SQL tables in the Django admin panel?
More details about the setup:
I have a docker-compose setup where Django is running in one container, a Postgres DB in another, and a slack-app in a third container. Django is connected to the DB and the models are registered in the admin panel. This works as intended. The slack-app is also connected to the same DB and has some tables there that are not Django-models. I would like to also access these through the Django admin panel in order to have everything in one place. Is this possible?
You can define unmanaged models in Django. These models will not construct migrations, but will only query the database to select, insert, etc.
Django offers a tool inspectdb [Django-doc] to inspect the database and write the corresponding unamanged models. You thus can use this with:
python3 manage.py inspectdb table1 table2 tablen
It will then write the corresponding models for these tables to the standard output channel, and you thus can copy these in the models.py. In the Meta of these models it will add a managed = False to denote that Django will not migrate these models.
Once you registered these models, you can register a ModelAdmin with:
from django.contrib import admin
from app_name.models import Model1, Model2, Modeln
admin.site.register(Model1)
admin.site.register(Model2)
admin.site.register(Modeln)
I was referring this link : Django: Get model from string?
. And, I found there is a way to do this by using apps.get_model. But,In my scenario, the model can be from other apps. So, I can't actually name the app_name here. Is there any way to do this ?
If you don't care which app the model comes from, you can do it the following way:
from django.apps import apps
def get_model_from_any_app(model_name):
for app_config in apps.get_app_configs():
try:
model = app_config.get_model(model_name)
return model
except LookupError:
pass
model = get_model_from_any_app('SomeModelName')
But in Django models in different apps can have the same name, i.e. your project can have model Post in your blog app and model Post in your news app etc.
So this way you can end up with not the model you expect, if they have duplicate names across apps (i.e. you probably should not do it this way, just think why in the world would you want a semi-random model?).
Docs which explain the code:
https://docs.djangoproject.com/en/2.0/ref/applications/#django.apps.apps.get_app_configs
https://docs.djangoproject.com/en/2.0/ref/applications/#django.apps.AppConfig.get_model
Just a simple question.
After I connect my django app to a remote database, I don't need to use Model.py to create tables in the database, then what is the function for Model.py at that moment?
If you want to use the Django ORM, you'll need to create models in the models.py file that match your remote database. If you don't want django creating or deleting tables on this DB, the managed=False option needs to be set for each model.
https://docs.djangoproject.com/en/1.11/ref/models/options/#managed
As you said after running migrations all tables in models.py file will be created. Later on, if you want to do some database operations, you may be using Django ORM. If you don't have models.py you won't be able to do such operations.
For example:
To create an entry to the table MyModel.
from your_app.models import MyModel
MyModel.objects.create(<field_name>=<value>)
I hope this gives you some idea.
I have extended the User model, but now the new user model is in an app called "account" which gives all models inside this app the app label "account". The Django model "Groups" still has the app label "Auth", so now models which all has something to do with auth is in separate apps in the admin site. Is it possibly to change the app label for "Groups"?
Try this:
from django.db.models.loading import get_models
get_models(django.contrib.auth.models)[1]._meta.app_label = 'group' #or whatever
If you need still more flexibility in the admin you could try django-admin-tools. It makes it easy to reorder and group models in different layouts (tabs, collapsible boxes, etc.) and also add dashboard-like features.
Just in case anyone needs this in Django 3.0+:
from django.apps import apps
apps.get_model('auth', 'Group')._meta.app_label = 'group' #or whatever, but have to be a registered app
Please not that this will mess with django internal model handling, e.g. generate migrations in contrib.auth sitepackage and so on
How would you go about making a pluggable django app, that can accept data from any model and then perfom some action with that data (i.e Save to DB, Send email). This functionality should be generic and should not be tied to a specific model.
It depends on what functionality your app would provide and in what way you'd expect users of your app to use it's api. For interacting with other models you don't know about there are a few ways, depending on what your reusable app does. You can make forms, views etc that would accept a model class or instance as a property or parameter. The other way would be for the users of your app to specify their relevant models in settings.py much like auth deals with user profiles. For example if your app needs to know about a model class that provides info about gadgets the user would specify:
#user's settings.py
GADGETS_MODEL='myapp.CustomSuperFunGadgets'
To get the class for the user specified model you would do:
from django.core.exceptions import ImproperlyConfigured
from django.conf import settings
if not getattr(settings, 'GADGETS_MODEL', False):
raise ImproperlyConfigured('You need to set GADGETS_MODEL'
'in your project settings')
try:
app_label, model_name = settings.GADGETS_MODEL.split('.')
except ValueError:
raise ImproperlyConfigured('app_label and model_name should'
' be separated by a dot in the GADGETS_MODEL set'
'ting')
try:
model = models.get_model(app_label, model_name)
if model is None:
raise ImproperlyConfigured('Unable to load the gadgets '
'model, check GADGETS_MODEL in your project sett'
'ings')
except (ImportError):
raise ImproperlyConfigured('Unable to load the gadgets model')
#at this poing model will hold a reference to the specified model class
Another way of interacting with models you don't know about is your app to provide custom model fields or managers or special properties that would just attach signal handlers to the model they are attached to.
As I said it all depends on what problem your reusable app is trying to solve, and the approach you should take is always based on that.