Friday, May 19, 2017

Re: Problem with CircularDependency Model

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

No comments:

Post a Comment