What is this User parameter in Django? - python

What is the User model we are importing here? What does it do
here?
from django.contrib.auth.models import User
class Customer(models.Model):
user=models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE)
name=models.CharField(max_length=200, null=True)
phone=models.CharField(max_length=200, null=True)
email=models.CharField(max_length=200, null=True)
profile_pic=models.ImageField(default="profile2.png",null=True,blank=True)
def __str__(self):
return self.name

user=models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE)
Above line is making a one-to-one relationship with the default Django User model with the customer model. This means, every User instance in your database can be associated with atmost 1 Customer instance.
The default User model contains standard user fields like username, email, first_name, last_name etc. Take a look here to learn more about the User model.
Read this to learn more about one-to-one relationships.

Related

Django User model with same fields

I saw tutorial on how to extend django model by giving 1-to-1 relationship to the django user model.
My question is, if we have same fields on both User and profile(extend from user) model i.e email and username.
When the user register on our site using User model, does the profile model will inherit the same username and email from User model?
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(
User, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=200, blank=True, null=True)
email = models.EmailField(max_length=500, blank=True, null=True)
location = models.CharField(max_length=200, blank=True, null=True)
When the user register on our site using User the model, does the Profile model will inherit the same username and email from User model?
No, you do not inherit from the user model, you simply create a new model that refers to a user, and it happens to have some fields that are the same. It would also be bad from a software design point-of-view. Imagine that you later add a field to your user model and somehow it is the same as the Profile, then all of a sudden the data should be different?
There is no need to store the data an extra time in the Profile. If you have a Profile object like my_profile, you can access the email address stored in the related user with:
my_profile.user.email
You can also make properties that will obtain it from the user, like:
from django.conf import settings
class Profile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
null=True,
blank=True
)
location = models.CharField(max_length=200, blank=True, null=True)
#property
def name(self):
if self.user_id is not None:
return self.user.username
#property
def email(self):
if self.user_id is not None:
return self.user.email
Storing the same data is a form of data duplication and often makes software harder to maintain: it means that for every update of the User model, or the Profile model, you will need to synchronize with the other model. This can easily go wrong, resulting in the fact that the Profile can have a different email address than the related User and vice versa, resulting in a lot of problems where one sends emails to the wrong email address, etc.
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Query on a model field? Is it possible in models.py? [duplicate]

This question already has an answer here:
How to query related models in django models.py
(1 answer)
Closed 3 years ago.
I have a model called StudentProfile:
class StudentProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
class_advisor = models.CharField(max_length=50)
year = models.OneToOneField(YearLevel, on_delete=models.SET_NULL, null=True)
section = models.OneToOneField(Section, on_delete=models.SET_NULL, null=True)
what I want to happen is, class_advisor to only return and accpet User with is_teacher = True.
by the way here's my User model:
class User(AbstractUser):
email = models.EmailField(
max_length=254,
unique=True,
verbose_name='Email Address',
blank=True
)
is_student = models.BooleanField(default=False, verbose_name='Student')
is_superuser = models.BooleanField(default=False, verbose_name='Administrator')
is_teacher = models.BooleanField(default=False, verbose_name='Teacher')
is_staff = models.BooleanField(default=False, verbose_name='Staff')
is_registrar = models.BooleanField(default=False, verbose_name='Registrar')
Yes, however at the moment, something is wrong with your modeling. You should make class_advisor a ForeignKey to the user model. Imagine that you store the username (or whatever unique attribute of that user) in your model. If later that teacher changes that username, then it will refer to a non-existing user, or later to a different user that picked the username.
You can set the limit_choices_to=... parameter [Django-doc]:
from django.db.models import Q
from django.contrib.auth import get_user_model
class StudentProfile(models.Model):
user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE, primary_key=True, related_name='studentprofile')
class_advisor = models.ForeignKey(get_user_model(), limit_choices_to=Q(is_teacher=True), related_name='students')
year = models.OneToOneField(YearLevel, on_delete=models.SET_NULL, null=True)
section = models.OneToOneField(Section, on_delete=models.SET_NULL, null=True)
If you use forms, etc. It will limit the options to Users that are teachers, and do validation on this.
It is better to use get_user_model() [Django-doc] here to refer to your user model, since if you later alter it, the ForeignKey (and OneToOneField will refer to the new model).
Try this:
StudentProfile.objects.filter(user__is_teacher=True)
StudentProfile.objects.filter(user__is_teacher=True).values('class_advisor')

How can I access column in model?

How can I access income in NewUser model?
I wanna filter Car model's data by user's income data.My ideal system is car name is shown in car.html if NewUser's income = Car income.
I wrote in models.py
class NewUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
income = models.CharField(max_length=20, null=True, default=None)
class Car(models.Model):
name = models.CharField(max_length=100, null=True, default=None)
income = models.CharField(max_length=20, null=True, default=None)
in views.py
from app.models import Car
from django.shortcuts import render
def car(request):
car_data = Car.objects.all().filter(income=request.user.income)
return render(request, 'car.html', {'car_data': car_data})
When I access car method,AttributeError at /app/car/
'User' object has no attribute 'income' error happens.I really cannot understand why such a error happens.I inherit User model in NewUser,so I think I can access income in request.user.How should I fix this?What is wrong in my codes?
You get that error because the User table doesn't have an income column. It is the NewUser model which has it.
Since there is a OneToOneField between NewUser and User, all you need to do:
car_data = Car.objects.all().filter(income=request.user.newuser.income)
Also, you state that you inherit User model in NewUser, but that is not true, NewUser inherits models.Model.

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