django: creating two models depends on each other - django

trying to solve quite simple problem, but I'm a little lost.
class Person(models.Model):
created_by = models.ForeignKey(User)
class User(models.Model):
person = models.ForeignKey(Person)
User is user who use system, log in, create persons, etc.
Each Person has info who create it.
Each User should be just one Person also, but able to create unlimited Persons
So the question how to properly create User (on registration) and assign Person?
I can't save Person without user, also can't save User without Person.
I think use person.models.ForeignKey(Person, null=True) in User model is not good design, because User has to have Person.
Any suggestion?
Thank you

It looks like User should just inherit from the Person model, since every User is a Person. Incidentally this would also resolve your problem - creating User would create an associated Person automatically.
You should probably read about multi-table inheritance to fully understand how this would work.
Furthermore, the created_by field should have null=True specified, since the first Person wouldn't be created by anyone, so the first object need to have the Null value there.
class Person(models.Model):
created_by = models.ForeignKey('User', null=True)
class User(Person):
person = models.ForeignKey('Person')
Also, since you want the User model to by used as the AUTH_USER_MODEL you should read about requirements for such models.

Related

Add a unique "intermediary" model to all my Django ManyToManyField()

Hello Awesome People!
Such a question that I have made a lot of searches for it. I am done building a website two(2) months ago, but today The team decides to track every time an instance has been added to a Model in ManyToManyField() fields.
I was thinking using the through argument to point to the model that will act as an intermediary may work but not at all in my case (70%). Just Because I want to have a unique intermediary model that will record for all ManyToManyField()
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateTimeField(auto_now_add=True)
Ah! Something is required. I need to explicitly specify foreign keys to the models that are involved in the many-to-many relationship.
Django ContentType may anticipate for all my models, but it's not working, I wonder why? it also contains ForeignKey (the one required by an intermediary model).
Do I really need to edit all my ManyToManyField fields and create Model as much as ManytoManyField? is there a way to record date_joined without creating an intermediary model for each?
Are you perhaps looking for something like django admin's LogEntry model?
LogEntry contains the ContentType of the model instance that has changed, the id of the instance, the type of change and an abstract change message. With all of that you can retrace changes made to instances.
In django admin, the views take care of adding records to LogEntry via three methods log_change/addition/deletion: click.

Automatic creation of database view from Django

Maybe this question also is similar to something like "automatic execution of raw SQL code just before creating exact one special model in models.py with managed=False".
For example, I have 3 models in models.py (default User, UserTypes and relation between them):
from django.contrib.auth.models import User
class UserTypes(models.Model):
type = models.TextField(unique=True)
class Meta:
db_table = 'user_types'
class UsersHaveTypes(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
type = models.ForeignKey(UserTypes, on_delete=models.CASCADE)
class Meta:
db_table = 'users_have_types'
unique_together = (("user", "type"), )
I have few types of users one of which is clients. Now I want to create endpoints "/clients", which will work as a usual model (CRUD).
Right now, I just add this in models.py:
class Clients(models.Model):
first_name = models.TextField(blank=True, null=True)
last_name = models.TextField(blank=True, null=True)
# all another fields from User model, which duplicated in the database view
class Meta:
managed = False
db_table = 'clients'
and then I make this by hand in my database backend:
Create database view
Create a function to make Insert, Update
and Delete
Create a trigger to trigger this functions.
It's a bunch of code and there is nothing special, all worked fine.
This all is to make working CRUD on "/clients" endpoint, so, for example, on "Creation", it will create User and automatically add a correct row to users_have_types table, which marks this user as "client".
Is there some more elegant and automatical way to make this? I move my Django project, and I need to create view, function, and trigger in the database backend again, which takes a lot of time (all by hand for every "type of users") and is an ugly decision.
I'm surprised, that nobody asked this question before, cause it's a good style of code database to make some views, and hide real table behind them. I know that Django can't create database view by self, but there must be a way to describe custom SQL code, which is used to create a table in the database. Maybe something with managers, I don't know (I'm a newbie in Django). Of course, it will be specific only for one database backend, but it's fine.

Django - Multiple User Profiles

Initially, I started my UserProfile like this:
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
verified = models.BooleanField()
mobile = models.CharField(max_length=32)
def __unicode__(self):
return self.user.email
Which works nicely along with AUTH_PROFILE_MODULE = 'accounts.UserProfile' set in settings.py.
However, I have two different kinds of users in my website, Individuals and Corporate, each having their own unique attributes. For instance, I would want my Individual users to have a single user only, hence having user = models.OneToOneField(User), and for Corporate I would want them to have multiple users related to the same profile, so I would have user = models.ForeignKey(User) instead.
So I thought about segregating the model into two different models, IndivProfile and CorpProfile, both inheriting from UserProfile while moving the model-specific attributes into the relevant sub-models. Seems like a good idea to me and would probably work, however I would not be able to specify AUTH_PROFILE_MODULE this way since I'm having two user profiles that would be different for different users.
I also thought about doing it the other way around, having UserProfile inherit from multiple classes (models), something like this:
class UserProfile(IndivProfile, CorpProfile):
# some field
def __unicode__(self):
return self.user.email
This way I would set AUTH_PROFILE_MODULE = 'accounts.UserProfile' and solve its problem. But that doesn't look like it's going to work, since inheritance in python works from left to right and all the variables in IndivProfile will be dominant.
Sure I can always have one single model with IndivProfile and CorpProfile variables all mixed in together and then I would use the required ones where necessary. But that is just doesn't look clean to me, I would rather have them segregated and use the appropriate model in the appropriate place.
Any suggestions of a clean way of doing this?
You can do this in following way. Have a profile which will contains common fields which are necessary in both profiles. And you have already done this by creating class UserProfile.
class UserProfile(models.Model):
user = models.ForeignKey(User)
# Some common fields here, which are shared among both corporate and individual profiles
class CorporateUser(models.Model):
profile = models.ForeignKey(UserProfile)
# Corporate fields here
class Meta:
db_table = 'corporate_user'
class IndividualUser(models.Model):
profile = models.ForeignKey(UserProfile)
# Individual user fields here
class Meta:
db_table = 'individual_user'
There is no rocket science involved here. Just have a keyword which will distinguish between corporate profile or individual profile. E.g. Consider that the user is signing up. Then have a field on form which will differentiate whether the user is signing up for corporate or not. And Use that keyword(request parameter) to save the user in respective model.
Then later on when ever you want to check that the profile of user is corporate or individual you can check it by writing a small function.
def is_corporate_profile(profile):
try:
profile.corporate_user
return True
except CorporateUser.DoesNotExist:
return False
# If there is no corporate profile is associated with main profile then it will raise `DoesNotExist` exception and it means its individual profile
# You can use this function as a template function also to use in template
{% if profile|is_corporate_profile %}
Hope this will lead you some where. Thanks!
I have done it this way.
PROFILE_TYPES = (
(u'INDV', 'Individual'),
(u'CORP', 'Corporate'),
)
# used just to define the relation between User and Profile
class UserProfile(models.Model):
user = models.ForeignKey(User)
profile = models.ForeignKey('Profile')
type = models.CharField(choices=PROFILE_TYPES, max_length=16)
# common fields reside here
class Profile(models.Model):
verified = models.BooleanField(default=False)
I ended up using an intermediate table to reflect the relation between two abstract models, User which is already defined in Django, and my Profile model. In case of having attributes that are not common, I will create a new model and relate it to Profile.
Could be worth to try using a through field. The idea behind it is to use the UserProfile model as through model for the CorpProfile or IndivProfile models. That way it is being created as soon as a Corp or Indiv Profile is linked to a user:
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.ForeignKey(User)
profile = models.ForeignKey(Profile, related_name='special_profile')
class Profile(models.Model):
common_property=something
class CorpProfile(Profile):
user=models.ForeignKey(User, through=UserProfile)
corp_property1=someproperty1
corp_property2=someproperty2
class IndivProfile(Profile):
user=models.ForeignKey(User, through=UserProfile, unique=true)
indiv_property1=something
indiv_property2=something
I think that way it should be possible to set AUTH_PROFILE_MODULE = 'accounts.UserProfile', and every time you create either a CorpProfile or a IndivProfile that is linked to a real user a unique UserProfile model is created. You can then access that with db queries or whatever you want.
I haven't tested this, so no guarantees. It may be a little bit hacky, but on the other side i find the idea quite appealing. :)

one-to-many relationships with django

I intend to create a teaming system, where each team may contain multiple contestants. The contestants is actually auth.User. Something similar to:
Team:
Contestant1
Contestant2
.
.
ContestantN
Since a contestant is actually a user which I cannot modify to have a foreignkey to team. What is the best way to achieve this?
The ways I though was:
Create a OneToOne profile for user which points to a team.
Define a ManyToMany relationship between user and team where user has to be unique.
A Pause
I am redesigning the structure of my application, so I will rephrase the question again
Thanks for your replies, I will consider them and see if one of them fits.
You can do this:
class Team(models.Model):
contestants = models.ManyToManyField(User, through='Contestant')
class Contestant(models.Model):
team = models.ForeignKey(Team)
user = models.ForeignKey(User)
[here go Contestant data fields]
This allows one user to take part in different teams, but if you don't want to allow this, you can add unique=True to Contestant.user.
The best way would be to extend the functionality of default accounts and create a new user model. The new user model can then have a foreign key to team. Like this.
class UserExtended(models.Model):
def __unicode__(self):
return self.user.username
user = models.OneToOneField(User, unique=True)
team = models.ForeignKey(Team)
User.profile = property(lambda u: UserExtended.objects.get_or_create(user=u)[0])
Now you can use the "UserExtended" in place of normal User.
I would create a contestants field on the Team model like so:
from django.contrib.auth.models import User
contestants = models.ManyToManyField(User)
You can't specify unique=True on a ManyToManyField. The good news is that it won't add the same contestant to the same team twice so you won't need to check if the contestant is unique.
I would say your best bet is to create a Contestant model. You'll probably end up needing to store more information about a contestant that is team-specific but separate from a player (such as whether the contestant is a starter, the contestant's number, and so on). Creating a Contestant model allows you to store that information separate from the User, and you would have a ForeignKey in the Contestant model referencing Users, and another ForeignKey in the Contestant model referencing Teams.

Django profile - user adding some objects

I want to have django user profile where the user can add some objects (he can add more than one) e.g. his addresses, his products and their descriptions and so on. I've no idea how to do that.
The best way to do this is to extend the user model via AUTH_PROFILE_MODULE. There's a great tutorial (doing part of what you want) on James Bennett's blog.
Create a new model (say UserProfile) with a ForeignKey to the User model.
class UserProfile(models.Model):
address = models.TextField()
products = models.TextField()
user = models.ForeignKey(User, unique=True)