Relational database - Django Rest Framework - python

I am trying to build relations with my database tables. Im having a tutorial lesson at the moment with 3 tables. for example (auth_user table, partyEvent table, friends table).
Now a user should be able to create just one partyEvent. Friends can join any number of partyEvent created by the users.
The owner id in the Friends model tells the partyEvent and User 'the friend' belongs to.
I am able to restrict the users to create only one partyEvent. But when i try to register friends to a partyEvent, the owner's id is not sent. Instead the default value in:
owner = models.OneToOneField('auth.User', related_name = 'party', on_delete=models.CASCADE, default='1')
is rather sent. Why is that happening?
models
class PartyEvent(models.Model):
name = models.CharField(max_length=100, blank=False)
location = models.CharField(max_length=100, blank=False)
owner = models.OneToOneField('auth.User', related_name = 'party', on_delete=models.CASCADE, default='1')
class Friends(models.Model):
name = models.CharField(max_length=100, blank=False)
owner = models.ForeignKey('auth.User',related_name = 'friends', on_delete=models.CASCADE, default='1')
serializers
class FriendsSerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.ReadOnlyField(source='owner.id')
class Meta:
model = Friends
fields = ('id','name','owner')

You can set current user by assigning serializers.CurrentUserDefault() as your serializer field default. Here is an example from the doc:
owner = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)

Related

Django How to organize models so there is only one owner

I have two models Company and User:
class Company(models.Model):
name = CharField("Name", max_length=60)
owner = OneToOneField(
"Employee", related_name='owner', on_delete=SET_NULL, null=True)
class BaseUser(AbstractBaseUser, PermissionsMixin):
objects = CustomUserManager()
join_date = DateTimeField(default=timezone.now)
name = CharField("Name", max_length=60)
email = EmailField(('Email'), unique=True)
company = ForeignKey(Company, on_delete=models.CASCADE)
I need to have only one User as owner. I made it so two models point to each other which doesn't seem right. Is there a way to fix it and still have only one possible owner? I know standard way would be to add is_owner = Boolean to User but it allows other Users to be owners.
A ForeignKey from the Company to the BaseUser is sufficient:
class Company(models.Model):
name = CharField("Name", max_length=60)
owner = ForeignKey(
'Employee',
related_name='companies'
)
class BaseUser(AbstractBaseUser, PermissionsMixin):
objects = CustomUserManager()
join_date = DateTimeField(default=timezone.now)
name = CharField("Name", max_length=60)
email = EmailField(('Email'), unique=True)
# no company
Here we thus link a Company to one user. Two Companys can have the same owner, and it is possible that the BaseUser has no, one, or more Companys where he is the owner.
You can obtain all the companies for which a BaseUser is the owner with:
myuser.companies.all()
If two companies should always point to two different users, you can make use of the OneToOneField [Django-doc].

How to access data using reverse foreign key reference in django

I have a model named UserProfile and a model PersonalInformation. I would like to fetch all the data of PersonalInformation using UserProfile model when the user is logged into the webiste but i have a foreign key refernce in the PersonalInformation model with the UserProfile model so how do i fetch the personal information using UserProfile model?
User Profile Model :
class UserProfile(models.Model):
"""Represents a user's model inside our system"""
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
profile_picture = models.ImageField(upload_to='photos/%y/%m/%d/')
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
highest_degree_earned = models.CharField(max_length=255, blank=False)
college_name = models.CharField(max_length=255, blank=False)
graduation_year = models.IntegerField(default=2020, blank=False)
Personal Information Model :
class PersonalInformation(models.Model):
"""Represents a user's personal Infromation inside our system"""
user = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
mobile = models.CharField(max_length=10 ,blank=True)
bio = models.TextField(max_length=200, blank=True)
college_university = models.CharField(max_length=100, blank=False)
course = models.CharField(max_length=100, blank=False)
First of all, in the code, you are showing you have the names of the models wrong. The UserProfile model name is set as PersonalInformation, change it or the migrations won't work (it's not accepted on the database no matter which one you're using).
Referent to the question you're asking, to fetch the related instance of PersonalInformation of a certain UserProfile instance you should just query the next:
user = UserProfile.objects.get(id='') #Introduce the id of the user you want to fetch its personal information.
user.personalinformation_set.all() # This will return you a QuerySet with all the related instances of PersonalInformation class.
user.personalinformation_set.get(id='') #To get a specific one or you may use a filter to get a filtered QS.
If you want, you can use the related_name attribute for ForeignKey class in order to set a different name from personalinformation_set.
I recommend you too to read the Django documentation, it's really well explained and clear I think:
https://docs.djangoproject.com/en/2.2/topics/db/examples/many_to_one/
As I've seen in a comment, you may also think to use a OneToOne relation instead of ForeignKey if you only expect one instance of PersonalInformation per User. The documentation is at:
https://docs.djangoproject.com/en/2.2/topics/db/examples/one_to_one/

Django Models Relationship Confusions

I have the following models:
class UserPost(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
class User(AbstractUser):
MALE = 'M'
FEMALE = 'F'
GENDER_CHOICES = (
(MALE, 'Male'),
(FEMALE, 'Female')
)
posts = models.ManyToManyField(Post, through='UserPost')
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Post(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
content = models.TextField()
status = models.CharField(max_length=100)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
When I run python manage.py makemigrations, it raises the following error:
users.User.posts: (fields.E303) Reverse query name for 'User.posts' clashes with field name 'Post.user'.
HINT: Rename field 'Post.user', or add/change a related_name argument to the definition for field 'User.posts'.
There is a many-to-many relationship between User and Post models. Each user can like many posts and each post can be liked by many users.
There is also a many-to-one relationship between User and Post models. Each user can write many posts and each post can be written by only one user.
Shouldn't reverse query name for 'User.posts' be user_set by default. If so, why is this name clashing with field name 'Post.user'? Can someone explain the meaning of this error? Thanks.
Do you need the UserPost model? It looks to have all the same fields as Post, and if you're after efficient querying, Django automatically creates database indexes on foreign keys. Here's a simple setup that should work pretty well:
class User(AbstractUser):
# Your fields go here, but you might not need the posts field
class Post(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='posts')
This would let you do a user.posts.all() to get all of the Post instances that belong to that user.

Many to Many or One to Many Django

I have the following two models in Django. One is basically an extension of the base Django user class and the other is a company model. I want to say that a user can belong to one or more companies and that a company can also have one or more contacts = "Users". Would this be a correct setup? How should I represent the tie between user and company?
User Profile model:
class Profile(models.Model):
user = models.OneToOneField(User)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
Company model:
class Company(models.Model):
name = models.CharField(max_length=120)
account_name = models.CharField(max_length=10, default="")
sales_rep = models.ForeignKey(User, related_name="%(app_label)s_%(class)s_sales", default="")
csr = models.ForeignKey(User, related_name="%(app_label)s_%(class)s_csr", default="")
class CompanyContact(models.Model):
name = models.CharField(max_length=40, default="")
email = models.CharField(max_length=50, default="")
user = models.ForeignKey(User)
company = models.ForeignKey(Company)
First, is there a reason to extend the User model? The default model already includes a first_name and last_name field, so you don't need an additional model just for that data. Similarly, you don't really need CompanyContact because the User model also contains email and name (again, through first_name and last_name) fields.
You can add in your contacts as a ManyToManyField. If you want to use the custom Profile model instead of User, just replace User (in the ManyToManyField) with Profile.
class Company(models.Model):
name = models.CharField(max_length=120)
account_name = models.CharField(max_length=10, default="")
sales_rep = models.ForeignKey(User, related_name="%(app_label)s_%(class)s_sales", default="")
csr = models.ForeignKey(User, related_name="%(app_label)s_%(class)s_csr", default="")
contacts = models.ManyToManyField(User) # or Profile
This allows each company to have many contacts and each user to be a contact of many companies – thus many-to-many.
Now, if you wanted extra data to describe the many-to-many relationship, you can have another model for that. For example, you may want to keep a record if the contact is still active or what their role is. So, you may have a CompanyContact model that is similar to:
class CompanyContact(models.Model):
active = models.BooleanField(default=False)
role = models.CharField(max_length=50, default="")
user = models.ForeignKey(User) # or Profile
company = models.ForeignKey(Company)
Then, declare the ManyToManyField relationship to use this new model:
class Company(models.Model):
...
contacts = models.ManyToManyField(User, through="CompanyContact")
# or contacts = models.ManyToManyField(Profile, through="CompanyContact")

Django: Lookup User OnetoOne Field using username with Model View Sets (Django Rest API)

My task is for an administrator in my application to be able to create and update an employee's details. Given that django's user model simplifies authentication, I used it as a OnetoOneField in my Employee Model, representing the key as the employee ID (username).
My Model -
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50, unique=True)
date_of_join = models.DateField(blank=True, null=True)
date_of_birth = models.DateField(blank=True, null=True)
designation = models.CharField(max_length=255, null=True)
mobile = models.CharField(max_length=255, null=True)
personal_email = models.CharField(max_length=255, blank=True, null=True)
official_email = models.CharField(max_length=255, blank=True, null=True)
current_station = models.CharField(
max_length=255, default="Chennai", null=True)
def __str__(self):
return self.name
Serializers -
class EmployeeSerializer(serializers.ModelSerializer):
class Meta:
model = Employee
fields = ('user', 'name', 'date_of_join', 'date_of_birth',
'designation', 'mobile', 'landline', 'personal_email',
'official_email', 'current_station')
My Model View Set:
class EmployeeListSet(viewsets.ModelViewSet):
lookup_field = 'user'
serializer_class = EmployeeSerializer
queryset = Employee.objects.all()
Browsable API of a specific Employee filtered by user ID
As shown in the image, the user field shows me pk instead of user.username.
I am able to see the username in the HTML Form for POST in the browsable API, however the json does not return the username by default and rather returns pk.
I want to be able to lookup and update an employee's details based on the username (employee ID).
What I have tried -
I have tried redefining the user field as a SerializedMethodField that returns user.username, but lookup and POST method still requires the pk instead of username, so it doesn't solve the problem for me.
Nesting serialziers makes the nested serializer have to be read only, which again makes my task of updating employee details undesirable.
How can I lookup an employee object based on user.username instead of pk?
How can I associate an existing User object with an employee object during creation with the User object's username using modelviewsets? Is there a way to solve this without having to override or write my own create and update functions for the modelviewset?

Categories

Resources