Monday, May 22, 2017

Re: Problem with CircularDependency Model

Thank you very much for the great answer!
You are correct, I didn't had a clear understanding of the RelatedObject Principle. I think I added this when I was fiddling with the rest framework.
Of course, I also had thought about making MasterUser a boolean, but I need to ensure that there is only one MasterUser. I thought about doing it in the Code, but I thought it might be better to enforce it at Database Level. However, I think your solution is much better.
I also thought having a separate Table for the MasterUser Relationship, like you suggested. I tried to some find some suggestions on how to model a relationship like that. I think, I will go for the boolean field but my intuitive assumption would be to overwrite the pre_save method. post_save kinda sounds like it is too late at that point.

Anyway, thanks a lot for you recommendations!

On Friday, May 19, 2017 at 5:50:42 PM UTC+2, Melvyn Sopacua wrote:

 

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')


--

Melvyn Sopacua

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/8c82ccfa-769f-4218-bff5-5adb7d851f97%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment