190

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.

10 Answers 10

202

As of Django 1.11 to 4.0 (at least), it's AppConfig.get_model(model_name, require_ready=True)

As of Django 1.9 the method is django.apps.AppConfig.get_model(model_name).
-- danihp

As of Django 1.7 the django.db.models.loading is 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

Defined as:

def get_model(self, app_label, model_name, seed_cache=True):
Sign up to request clarification or add additional context in comments.

9 Comments

This solution is deprecated in Django 1.7, see this other answer for the solution: stackoverflow.com/a/26126935/155987
Hi @mpen, I suggest to you to update your answer. On django 1.9 get_model is defined on AppConfig: from django.apps import AppConfig
In Django 1.7+ it is better to use get_model() on the Django app registry, which is available via django.apps.apps.get_model(model_name). AppConfig objects are intended for a different purpose, and require you to create an AppConfig instance in order to call get_model().
Django 1.11 needs the answer provided by @luke_aus
Latest (2020) solution: from django.apps import apps then: apps.get_model('app_name', 'Model') stackoverflow.com/questions/38443628/…
|
185

django.db.models.loading was deprecated in Django 1.7 (removed in 1.9) in favor of the the new application loading system.

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'>

2 Comments

I used to use pydoc's "locate" function...not sure of the difference here, but in order to stay within Django i've switch to this method. Thanks.
optional form apps.get_model("appName.ModelName")
93

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'

Comments

34

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 django/db/models/fields/related.py:

    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.

2 Comments

I think the 2nd line should be: your_model = get_model(*your_string.rsplit('.', 1)). App label sometimes is dotted format, however model name is always a valid identifier.
Looks like this isn't necessary in the new apps.get_model. "As a shortcut, this method also accepts a single argument in the form app_label.model_name."
24

2020 solution:

from django.apps import apps

apps.get_model('app_name', 'Model')

per your eg:

apps.get_model('people', 'Person')

per: Import Error :cannot import name get_model

Comments

19

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

Comments

15

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.

Comments

9

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"

1 Comment

great answer, btw, the string doesn't need to be capitalised, appname.modelname also works.
4

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

1 Comment

Is it clls.__class__.__name__ or just clls.__name__?
3

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')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.