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.
Related
In my pervious question I asked how I can automatically save the user submitting the form. I found the form_valid method to be the best in that case. However in my models I also have a user profile model like this
models.py
....
class Profile(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
title = models.CharField(max_length=24)
first_name = models.CharField(max_length=35)
last_name = models.CharField(max_length=35)
email = models.EmailField(max_length=64)
phone_number = models.CharField(max_length=12)
department = models.ForeignKey(Department,null=True,on_delete=models.SET_NULL)
supervisor = models.ForeignKey('self',blank=True,null=True,on_delete=models.SET_NULL)
...
As you can see I used the One to One method to make my UserProfile
As before in my models.py I have my reports model
...
class Report(models.Model):
id = models.UUIDField(primary_key=True,default=uuid.uuid1,editable=False)
department = models.ForeignKey(Company,null=True,on_delete=models.SET_NULL)
user= models.ForeignKey(User,on_delete=models.PROTECT)
submission_date= models.DateField(auto_now=True) #invisible to user
submission_time = models.TimeField(auto_now=True) #invisible to ,user
date = models.DateField(default=now,blank=False)
time = models.TimeField(default=now,blank=False,help_text="hh:mm:ss")
location = PlainLocationField()
building = models.ForeignKey(bld,null=True,on_delete=models.SET_NULL)
size = models.PositiveIntegerField()
notes = models.TextField(blank=True)
def __str__(self):
return f'{self.date} {self.time} ({self.department})
...
My question how I can make it so that the department field will load from the user profile? I would hope to eventually make it possible for users in the same department to be able to view and update each others Reports.
As before:
form.py
class ReportForm(forms.ModelForm):
class Meta:
model = Report
fields = '__all__'
location = PlainLocationField()
def redirect():
return redirect("Report")
views.py
class ReportCreate(LoginRequiredMixin,CreateView):
Template = "templates\reports\Report.html"
model = Report
fields = '__all__'
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.save()
return super(ReportCreate, self).form_valid(form)
def get_success_url(self):
return reverse('Report')
def get_absolute_url(self):
return reverse('Report', kwargs={'pk':self.pk})
I advise you to use related_name in your ForeignKeys. Set the department field of both models as following:
class Profile(models.Model):
...
department = models.ForeignKey(Department, null=True, on_delete=models.SET_NULL, related_name='profiles')
...
class Report(models.Model):
...
department = models.ForeignKey(Department, null=True, on_delete=models.SET_NULL, related_name='reports')
...
From now on, Department objects that are related to User.Profile you can access like that:
Department.profiles.all() # it returns QuerySet of all related to Department Profile objects
Department.reports.all() # it returns QuerySet of all related to Department Report objects
And you can use it in making QuerySet for user:
Report.objects.filter(department=self.request.user.profile.department)
# it returns all Report objects, that have exactly the same department as the user
Or using our new relationship:
department = self.request.user.profile.department
reports_for_user = department.reports.all()
But I can see one problem. You are using Company model for ForeignKey in Report. It has to be the same Department model for both Profile and Report models for such easy option to work. Also you definitely should not mix naming in single project. You can set relation with Company as another field:
company = models.ForeignKey(Company, null=True, on_delete=models.SET_NULL)
Here are some steps to help you autofill some fields:
Get the user from self.request.user. How to access current user in Django class based view
Get the profile: get user profile in django
Pass the required fields as context variables: https://www.geeksforgeeks.org/how-to-pass-additional-context-into-a-class-based-view-django/
Pass it into javascript. How can I pass my context variables to a javascript file in Django?
Set the value like this: Set the value of an input field
DONE!
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.
I want to show a validation message like "This Project already exists" in my django admin whenever i create a project with same name.
I keep getting an IntegrityError at my Name. Isn't Django supposed to validate this and give an ValidationError if I use unique_together=((,)) in my model? Or do I have to Try and Catch the IntegrityError myself?
Also i have made two users and gave permissions to them from main admin user. so i want that one user1 cannot have projects with same name like proj1 while the user2 can have name of project as proj1.
Can anyone tell me a best practice for validating unique users inside a form/model.
models.py
class Project(models.Model):
name = models.CharField(max_length=200)
added_by = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True, default=None)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
unique_together = (("name", "added_by"),)
def __str__(self):
return self.name
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")
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?