class User(AbstractBaseUser, PermissionsMixin):
# account-related information
institute = models.ForeignKey(Institute, blank=True, null=True, on_delete=models.SET(get_default_institute))
username = ...
....
This is the model in another app for the institutes
class Institute(models.Model):
master_user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='master_user')
name = models.CharField(max_length=255)
def members(self):
UserModel = apps.get_model('play', 'User') # need to avoid circular import
return UserModel.objects.filter(institute=self)
def members(self):
return Institute.user_set.all()
def members(self):
return self.user_set.all()
On Friday 05 May 2017 05:41:52 Tobias Dacoir wrote:
> I am trying to build a model (in two separate apps) which has the
> following constraints:
>
> - There can be many institutes
> - there can many users
> - each user is a member of exactly one institute
> - each institute has exactly one master user
>
> However I am running into CircularDependency errors when trying to
> create this model and database. Of course this model is a bit
> problematic because you can't have an institute without master user,
> but also you can't create a user without some default institute. How
> do I fix this? Should I be more lean on the model side and allow for
> a lot of blanks and null values and make all the exception handling
> somewhere else?
>
> Please tell me how to improve my model.
>
> >> class User(AbstractBaseUser, PermissionsMixin):
> > # account-related information
> > institute = models.ForeignKey(Institute, blank=True, null=True,
institute = models.ForeignKey('mycoolapp.Institute', ....)
This uses a promise and resolves the model at init stage (rather then class declaration). Make sure you remove the import of Institute or it won't help.
If you're interested in the topic of resolving models at runtime, take a loot at django.apps.Apps, specifically get_model. But all the work for foreign keys is already done for you.
--
Melvyn Sopacua
self.ensure_not_cyclic(target, lambda x: (parent.key for parent in self.node_map[x].parents))
File "/Users/no68tuh2/.virtualenvs/ihearu/lib/python2.7/site-packages/django/db/migrations/graph.py", line 370, in ensure_not_cyclic
raise CircularDependencyError(", ".join("%s.%s" % n for n in cycle))
django.db.migrations.exceptions.CircularDependencyError: play.0001_initial, portal.0001_initial
Ah, now I see!
This has nothing to do with *model* dependencies. Two *migrations* depend on each other: play and port, both 0001_initial.
Do you have any idea how you got into that jam? Did you fiddle with django_migrations table? Maybe run --fake?
--
Melvyn Sopacua
On Friday 19 May 2017 00:19:04 Tobias Dacoir wrote:
> No, I am trying to deploy it locally. I have no sqlite DB and no
> migrations. For some strange reason I used to just run manage.py
> makemigrations and would create the initial migrations for all Apps.
> This doesn't work for some reason anymore. So I have to to
> makemigrations APPname for each app and when I run to migrate to
> create the intial database schema, it doesn't work. So I figured my
> Data Model is crap.
Yep, let me see if I got it right:
- The User model is defined as AUTH_USER_MODEL in settings.py
- User points to institute
- Institute points to User
So it is in fact a circular dependency on the model level as well. And one you don't need.
From the way you defined the related_name it is also clear you don't get the RelatedObject principle of Django.
A ForeignKey creates a bridge between two models: you can travel in both directions. Using your models:
class User(AbstractBaseUser, PermissionsMixin):
username = ...
class Institute(models.Model):
master_user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='institute')
members = models.ManyToManyField(settings.AUTH_USER_MODEL)
Because of the ForeignKey on Institute, Django creates an attribute on User, called 'institute'. It uses institute, because I specified that as related_name. You could use a different name there, but it has to be a name that can be used on the model you point to.
However, this isn't a good representation of realitity, given your own description.
So this is a better way to do it:
class User(AbstractBaseUser, PermissionsMixin):
institute = models.ForeignKey('port.Institute', related_name='members')
is_master_user = models.BooleanField(default=False)
class Institute(models.Model)
name = models.CharField(max_length=255)
# members is now created by the foreign key
@property
def master_user(self):
return self.members.get(is_master_user=True)
This model is much simpler. All you need to do is to verify that when someone is made master user, that all other members of the institute are *not* master user.
You can do this in a post_save signal or in the clean method of User , both with its own caveats.
Another way would be to define a MasterUser model, which is easier to maintain in the admin:
class MasterUser(models.Model):
# Assume one person can be master user of many institutes
# if not, this also has to be a OneToOneFIeld
user = models.ForeignKey(settings.AUTH_USER_MODEL)
institute = models.OneToOneField(Institute, related_name='master_user')
> On Wednesday, May 17, 2017 at 5:41:41 PM UTC+2, Melvyn Sopacua wrote:
> > On Wednesday 17 May 2017 05:57:57 Tobias Dacoir wrote:
> > > Thanks Melvyn,
> > >
> > >
> > >
> > > I used promises before, when I use a foreign key for a class that
> > > is
> > >
> > > not yet defined, however it didn't change anything for my problem.
> > > I
> > >
> > > can make migrations, but not migrate. I am starting with a new
> > >
> > > database from scratch.
> > >
> > > self.ensure_not_cyclic(target, lambda x: (parent.key for parent in
> > >
> > > self. node_map[x].parents))
> > >
> > > File
> > >
> > > "/Users/no68tuh2/.virtualenvs/ihearu/lib/python2.7/site-packages/d
> > > jang
> > >
> > > o/db/migrations/graph.py" , line 370, in ensure_not_cyclic
> > >
> > > raise CircularDependencyError(", ".join("%s.%s" % n for n in
> > >
> > > cycle)) django.db.migrations.exceptions.CircularDependencyError:
> > >
> > > play.0001_initial, portal.0001_initial
> > >
> > >
> > >
> > > This CircularDependencyError is driving me crazy.
> >
> > Ah, now I see!
> >
> > This has nothing to do with *model* dependencies. Two *migrations*
> > depend on each other: play and port, both 0001_initial.
> >
> >
> >
> > Do you have any idea how you got into that jam? Did you fiddle with
> > django_migrations table? Maybe run --fake?
> >
> >
> > Melvyn Sopacua
--
Melvyn Sopacua
--
Melvyn Sopacua