Sarius
Sarius

Reputation: 145

Django models - Circular-Import-Issue

My Django-Project uses Three Apps, chat, user, sowi. Every App having models structured in the following way. I'm getting an error when starting the Server, i think it is because i have circular Imports. How do i fix this issue?

chat/models.py

from user.models import User

class Chat(models.Model):
    name = models.CharField(max_length=100, default="private")


class Message(models.Model):
    sender = models.ForeignKey(User, on_delete=models.CASCADE)
    receiver = models.ForeignKey(Chat, on_delete=models.CASCADE)

user/models.py

from chat.models import Chat
from sowi.models import Sowi

class User(AbstractUser):
    chats = models.ManyToManyField(Chat, blank=True)
    subscriptions = models.ManyToManyField(Sowi, related_name="subscriptions", blank=True)
    memberships = models.ManyToManyField(Sowi, related_name="memberships", blank=True)
    blocked = models.ManyToManyField("self", related_name="blocked", blank=True)

sowi/models.py

from chat.models import Chat, Message
from user.models import User

class Sowi(models.Model):
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    chat = models.OneToOneField(Chat, blank=True, null=True, on_delete=models.CASCADE)

Error Message:

File "*/sowi/models.py", line 9, in <module>
    from chat.models import Chat, Message
  File "*/chat/models.py", line 4, in <module>
    from user.models import User
  File "*/user/models.py", line 5, in <module>
    from chat.models import Chat
ImportError: cannot import name 'Chat' from 'chat.models'

Thanks in Advance!

Upvotes: 0

Views: 3076

Answers (2)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476604

It is better to refer to models with string literals, than to refer to it with references to the model class. Django can handle this and will automatically resolve these:

# chat/models.py

from django.db import models

class Chat(models.Model):
    name = models.CharField(max_length=100, default="private")

class Message(models.Model):
    sender = models.ForeignKey('user.User', on_delete=models.CASCADE)
    receiver = models.ForeignKey(Chat, on_delete=models.CASCADE)

# user/models.py

from django.db import models

class User(AbstractUser):
    chats = models.ManyToManyField(Chat, blank=True)
    subscriptions = models.ManyToManyField('sowi.Sowi', related_name="subscriptions", blank=True)
    memberships = models.ManyToManyField('sowi.Sowi', related_name="memberships", blank=True)
    blocked = models.ManyToManyField("self", related_name="blocked", blank=True)

# sowi/models.py

from django.db import models

class Sowi(models.Model):
    owner = models.ForeignKey('user.User', on_delete=models.CASCADE)
    chat = models.OneToOneField('chat.Chat', blank=True, null=True, on_delete=models.CASCADE)

It is even better when you reference the user model [Django-doc] to set the AUTH_USER_MODEL setting [Django-doc], and use this setting, such that if you later change your mind, you can more conveniently change this:

# chat/models.py

from django.conf import settings
from django.db import models

class Chat(models.Model):
    name = models.CharField(max_length=100, default="private")

class Message(models.Model):
    sender = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    receiver = models.ForeignKey(Chat, on_delete=models.CASCADE)

# user/models.py

from django.db import models

class User(AbstractUser):
    chats = models.ManyToManyField(Chat, blank=True)
    subscriptions = models.ManyToManyField('sowi.Sowi', related_name="subscriptions", blank=True)
    memberships = models.ManyToManyField('sowi.Sowi', related_name="memberships", blank=True)
    blocked = models.ManyToManyField("self", related_name="blocked", blank=True)

# sowi/models.py

from django.conf import settings
from django.db import models

class Sowi(models.Model):
    owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    chat = models.OneToOneField('chat.Chat'

Upvotes: 6

Sajad
Sajad

Reputation: 524

try:

class User(AbstractUser):
    chats = models.ManyToManyField('chat.Chat', blank=True)
    subscriptions = models.ManyToManyField('sowi.Sowi', related_name="subscriptions", blank=True)
    memberships = models.ManyToManyField('sowi.Sowi', related_name="memberships", blank=True)
    blocked = models.ManyToManyField("self", related_name="blocked", blank=True)

The problem with your code is that you're importing Chat and Sowi in user models.py, and then you're trying to import user models in Chat and Sowi. You see the Circular Import there?

Upvotes: 3

Related Questions