181

I'm really not getting this, so if someone could explain how this works I'd very much appreciate it. I have two applications, Accounts and Theme... here is my settings list:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'accounts',
    'themes',
)

In accounts, I am trying to do this:

from themes.models import Theme

class Account(models.Model):
    ACTIVE_STATUS = 1
    DEACTIVE_STATUS = 2
    ARCHIVE_STATUS = 3
    STATUS_CHOICES = (
        (ACTIVE_STATUS, ('Active')),
        (DEACTIVE_STATUS, ('Deactive')),
        (ARCHIVE_STATUS, ('Archived')),
    )

    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=250)
    slug = models.SlugField(unique=True, verbose_name='URL Slug')
    status = models.IntegerField(choices=STATUS_CHOICES, default=ACTIVE_STATUS, max_length=1)
    owner = models.ForeignKey(User)
    enable_comments = models.BooleanField(default=True)
    theme = models.ForeignKey(Theme)
    date_created = models.DateTimeField(default=datetime.now)

And in my theme model:

class Theme(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=250)
    slug = models.SlugField(unique=True, verbose_name='URL Slug')
    date_created = models.DateTimeField(default=datetime.now)

class Stylesheet(models.Model):
    id = models.AutoField(primary_key=True)
    account = models.ForeignKey(Account)
    date_created = models.DateTimeField(default=datetime.now)
    content = models.TextField()

Django is kicking out the following error:

from themes.models import Theme
ImportError: cannot import name Theme

Is this some kind of circular import issue? I've tried using a lazy reference, but that doesn't seem to work either!

2
  • 1
    It does look like an issue with circular imports. Why do you need to import Account from the module where Theme is defined? Commented Dec 7, 2010 at 16:34
  • Sorry, I did not paste my Themes model correctly, I have updated my post. I am using it in the Stylesheet class.
    – Hanpan
    Commented Dec 7, 2010 at 16:35

6 Answers 6

332

Remove the import of Theme and use the model name as a string instead.

theme = models.ForeignKey('themes.Theme')
3
  • 14
    Actually that needs to be 'themes.Theme', as it's in a different app. Commented Dec 7, 2010 at 16:45
  • Ahh, that worked, I was trying just 'Theme' before and it didn't work. Thanks. Is there any kind of performance hit for doing it this way? I'd like to keep my lookups non lazy if possible :)
    – Hanpan
    Commented Dec 7, 2010 at 16:47
  • @Daniel: Updated. @Hanpan: A small one, yes. But only once. Commented Dec 7, 2010 at 16:51
93

Upto Django 1.7:

Use get_model function from django.db.models which is designed for lazy model imports.:

from django.db.models import get_model
MyModel = get_model('app_name', 'ModelName')

In your case:

from django.db.models import get_model
Theme = get_model('themes', 'Theme')

Now you can use Theme

For Django 1.7+:

from django.apps import apps
apps.get_model('app_label.model_name')
2
  • 14
    Use apps.get_model(app_label, model_name) or apps.get_model('app_label.model_name') in Django 1.7+
    – phoibos
    Commented May 13, 2015 at 8:53
  • @phoibos I can confirm this is still correct in Django 3.2+.
    – Harlin
    Commented Feb 5, 2023 at 16:33
60

Something I haven't seen mentioned anywhere in sufficient detail is how to properly formulate the string inside ForeignKey when referencing a model in a different app. This string needs to be app_label.model_name. And, very importantly, the app_label is not the entire line in INSTALLED_APPS, but only the last component of it. So if your INSTALLED_APPS looks like this:

INSTALLED_APPS = (
...
    'path.to.app1',
    'another.path.to.app2'
)

then to include a ForeignKey to a model in app2 in an app1 model, you must do:

app2_themodel = ForeignKey('app2.TheModel')

I spent quite a long time trying to solve a circular import issue (so I couldn't just from another.path.to.app2.models import TheModel) before I stumbled onto this, google/SO was no help (all the examples had single component app paths), so hopefully this will help other django newbies.

0
53

Since Django 1.7 correct way is to go like this:

from django.apps import apps

YourModel = apps.get_model('your_app_name', 'YourModel')

See: https://docs.djangoproject.com/ja/1.9/ref/applications/#django.apps.apps.get_model

1
  • 6
    There's also a single-arg shortcut syntax: apps.get_model('your_app_name.YourModel') convenient for use in a map etc. Commented Feb 13, 2017 at 4:45
0

I had the same problem but on using MyModel = get_model('app_name', 'ModelName') I got a new error 'raise AppRegistryNotReady("Models aren't loaded yet.")'

I tried all the other methods on this page but none worked for me. The way I fixed it was to use: MyModel = get_model('app_name', 'ModelName') but actually in the class rather than outside of it.

2
  • Could you please elaborate? Commented Apr 8, 2022 at 15:01
  • In models.py from django.apps import apps I then defined a save method which inside has: Cart = apps.get_model(app_label='Carts', model_name='Cart') This allows me to import another django model from elsewhere.
    – ryansl39
    Commented Apr 10, 2022 at 13:04
-2

This is how I fix the circular issue by specifying 'app_name.model_name' and TYPE_CHECKING

profile app's models.py
   from typing import TYPE_CHECKING
   if TYPE_CHECKING:
     from team.models import Team

   team = models.ForeignKey('team.Team',...)

team app's models.py  
  Class Team
    name = models.CharField(...) 
    head = models.ForeignKey('profile.Profile',...)
1
  • can you elaborate on TYPE_CHECKING? I just don't understand how this works...
    – benzkji
    Commented Mar 13 at 14:47

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.