181

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.

mpen
  • 272,448
  • 266
  • 850
  • 1,236

10 Answers10

198

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):
tony
  • 870
  • 7
  • 16
mpen
  • 272,448
  • 266
  • 850
  • 1,236
  • 15
    This solution is deprecated in Django 1.7, see this other answer for the solution: http://stackoverflow.com/a/26126935/155987 – Tim Saylor Jun 30 '15 at 22:26
  • 4
    Hi @mpen, I suggest to you to update your answer. [On django 1.9 get_model is defined on AppConfig](https://docs.djangoproject.com/es/1.9/ref/applications/#django.apps.AppConfig.get_model): `from django.apps import AppConfig` – dani herrera Apr 20 '16 at 14:18
  • @danihp Thanks, added a note. – mpen Apr 20 '16 at 21:24
  • 1
    django.apps.AppConfig is a generator type that can not work like model object. – Neeraj Kumar Sep 20 '16 at 18:15
  • 3
    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()`. – zlovelady Nov 24 '17 at 04:51
  • 3
    Django 1.11 needs the answer provided by @luke_aus – Georg Zimmer Feb 08 '18 at 15:47
  • as for Django 2.2 its from factory.django import get_model – DorZ Apr 27 '20 at 12:04
  • @DorZ Isn't that for `factory_boy`? Is factory boy part of Django core? – mpen Apr 28 '20 at 01:32
  • 7
    Latest (2020) solution: `from django.apps import apps` then: `apps.get_model('app_name', 'Model')` https://stackoverflow.com/questions/38443628/import-error-cannot-import-name-get-model – Williams Jul 25 '20 at 22:47
  • 2022: from `django.apps import apps` then: `apps.get_model('app_name.model_name')` also works – C.K. Nov 09 '22 at 11:27
174

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'>
shad0w_wa1k3r
  • 12,955
  • 8
  • 67
  • 90
Scott Woodall
  • 10,456
  • 6
  • 39
  • 37
87

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'

Kevin
  • 1,132
  • 2
  • 13
  • 24
lukeaus
  • 11,465
  • 7
  • 50
  • 60
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.

Anentropic
  • 32,188
  • 12
  • 99
  • 147
Ch'marr
  • 1,284
  • 11
  • 8
  • 3
    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. – Rockallite May 21 '14 at 07:58
  • 1
    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`." – Ryne Everett Nov 20 '15 at 14:06
23

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

Williams
  • 4,044
  • 1
  • 37
  • 53
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
Craig Labenz
  • 2,489
  • 3
  • 22
  • 17
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.

Ola Nguyen Van
  • 441
  • 4
  • 6
8

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"
Glycerine
  • 7,157
  • 4
  • 39
  • 65
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
jbcurtin
  • 1,793
  • 2
  • 14
  • 23
2

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')
Community
  • 1
  • 1
Schubisu
  • 21
  • 3