Django: Get model from string?
In Django, you can specify relationships like: author = ForeignKey('Person') And then internally it has to convert the string "Person" into the model Person. Where's the function that does this? I want to use it, but I can't find it.
As of Django 1.7 the
django.db.models.loadingis deprecated (to be removed in 1.9) in favor of the the new application loading system.
— Scott Woodall
Found it. It’s defined here:
from django.db.models.loading import get_model
def get_model(self, app_label, model_name, seed_cache=True):
Django 1.7 docs give us the following instead:
>>> from django.apps import apps >>> User = apps.get_model(app_label='auth', model_name='User') >>> print(User) <class 'django.contrib.auth.models.User'>
just for anyone getting stuck (like I did):
from django.apps import apps model = apps.get_model('app_name', 'model_name')
app_name should be listed using quotes, as should
model_name (i.e. don’t try to import it)
get_model accepts lower case or upper case ‘model_name’
Most model “strings” appear as the form “appname.modelname” so you might want to use this variation on get_model
from django.db.models.loading import get_model your_model = get_model ( *your_string.split('.',1) )
The part of the django code that usually turns such strings into a model is a little more complex This from
try: app_label, model_name = relation.split(".") except ValueError: # If we can't split, assume a model in current app app_label = cls._meta.app_label model_name = relation except AttributeError: # If it doesn't have a split it's actually a model class app_label = relation._meta.app_label model_name = relation._meta.object_name # Try to look up the related model, and if it's already loaded resolve the # string right away. If get_model returns None, it means that the related # model isn't loaded yet, so we need to pend the relation until the class # is prepared. model = get_model(app_label, model_name, seed_cache=False, only_installed=False)
To me, this appears to be an good case for splitting this out into a single function in the core code. However, if you know your strings are in “App.Model” format, the two liner above will work.
The blessed way to do this in Django 1.7+ is:
import django model_cls = django.apps.apps.get_model('app_name', 'model_name')
So, in the canonical example of all framework tutorials:
import django entry_cls = django.apps.apps.get_model('blog', 'entry') # Case insensitive
In case you don’t know in which app your model exists, you can search it this way:
from django.contrib.contenttypes.models import ContentType ct = ContentType.objects.get(model='your_model_name') model = ct.model_class()
Remember that your_model_name must be lowercase.
I’m not sure where it’s done in Django, but you could do this.
Mapping the class name to the string via reflection.
classes = [Person,Child,Parent] def find_class(name): for clls in classes: if clls.__class__.__name__ == name: return clls
Another rendition with less code for the lazy. Tested in Django 2+
from django.apps import apps model = apps.get_model("appname.ModelName") # e.g "accounts.User"
Here is a less django-specific approach to get a class from string:
mymodels = ['ModelA', 'ModelB'] model_list = __import__('<appname>.models', fromlist=mymodels) model_a = getattr(model_list, 'ModelA')
or you can use importlib as shown here:
import importlib myapp_models = importlib.import_module('<appname>.models') model_a = getattr(myapp_models, 'ModelA')
- Database Administration Tutorials
- Programming Tutorials & IT News
- Linux & DevOps World
- Entertainment & General News
- Games & eSport