Get the user instance from a profile model - python

Hella everyone, Alright I'm building an ecommerce website and stuck at a certain point, I got two models Seller and Product, as follows:
class Seller(models.Model):
seller = models.OneToOneField(User, on_delete=models.CASCADE)
city = models.CharField(max_length=30)
country = models.CharField(max_length=30)
phone_number = PhoneNumberField()
email = models.EmailField(max_length=300)
def __str__(self):
return self.seller.username
class Product(models.Model):
STATUS_CHOICES = [
('New', 'New'),
('New', 'Used'),
]
image = models.ImageField(default='dev1.jpg', upload_to='images/')
condition = models.CharField(choices=STATUS_CHOICES, max_length=10)
seller = models.ForeignKey(Seller, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
description = models.TextField()
price = models.CharField(max_length=15)
location = models.CharField(max_length=30)
posted_on = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
Now I have a form to save new Product as:
class SellProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ('image', 'condition', 'title', 'description', 'price', 'location', )
The problem is in views.py:
#login_required
def sell(request):
form = SellProductForm()
if request.method == 'POST':
form = SellProductForm(request.POST)
if form.is_valid():
print('Ok')
instance = form.save(commit=False)
instance.seller = request.user
instance.save()
return redirect('index')
context = {
'form': form,
}
return render(request, 'myapp/sell.html', context)
At the end, I get the ERROR:
"Product.seller must be a Seller instance."
I understand the demand but I can't get myself to imagine the code and come up with a solution, for I'm giving it a User instance not a seller instance.

Since it is a OneToOneField you can obtain the related Seller model of a User object with user.seller, so in this case:
instance.seller = request.user.seller
This will raise an AttributeError if no Seller is linked to the logged in user.

Related

How to get the username of the current user and assign it to a certain field in a form in django?

This is my models.py file
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Book(models.Model):
category_choices =(
#("Undefined","Undefined"),
("Action", "Action"),
("Romance", "Romance"),
("Horror", "Horror"),
("Comedy", "Comedy"),
("Adventure", "Adventure"),
("Dramatic", "Dramatic"),
("Crime","Crime"),
("Fantasy","Fantasy"),
)
name = models.CharField(max_length=100)
author = models.CharField(max_length=100, null=True)
content = models.TextField()
price = models.DecimalField(max_digits=5, decimal_places=2)
image = models.ImageField(upload_to= 'photos/%y/%m/%d', blank = True)
category = models.CharField(
max_length = 20,
choices = category_choices,
#default = 'Undefined'
)
publication_year = models.CharField(max_length=4, null=True)
ISBN = models.CharField(max_length=13, null=True, unique=True)
active = models.BooleanField(default= True)
def __str__(self):
return self.name
class Borrow(models.Model):
name = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
book = models.OneToOneField(Book, null=True, on_delete= models.SET_NULL)
period = models.PositiveIntegerField(default=0)
id = models.IntegerField(primary_key=True)
def __str__(self):
return str(self.book)
and this is my forms.py file
from django import forms
from .models import Borrow
class BorrowForm(forms.ModelForm):
class Meta:
model = Borrow
fields = ('name', 'book', 'period')
and this is the function in my views.py file that renders the form
#login_required
def borrowing(request):
momo = BorrowForm()
if request.method == 'POST':
momo = BorrowForm(request.POST)
if momo.is_valid():
instacne = momo.save(commit=False)
instacne.user = request.user.username
instacne.save()
return redirect('profile')
return render(request, 'books/book.html', {'momo': momo})
The role of this function is to render that form and to save the data that user will enter and automatically assign the username of the current user to the field 'name' in form.
I tried alot of things to get the username of the current user and assign it to the field 'name' but nothing works and that field stays blank.
You're using a models.ForeignKey(User) so that table will store a user id, not a username. I'd call this field user and not name, personally.
Therefore you need to provide a user instance to it like this;
#login_required
def borrowing(request):
initial = {}
if request.user.is_authenticated:
initial.update({'name': request.user})
momo = BorrowForm(initial=initial)
if request.method == 'POST':
momo = BorrowForm(request.POST)
if momo.is_valid():
instance = momo.save(commit=False)
instance.user = request.user
instance.save()
If you wanted to easily get the username for a Borrow instance you could do this;
class Borrow(models.Model):
name = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
book = models.OneToOneField(Book, null=True, on_delete= models.SET_NULL)
period = models.PositiveIntegerField(default=0)
id = models.IntegerField(primary_key=True)
def __str__(self):
return str(self.book)
#property
def username(self):
return self.name.username
If you want the form to offer users by username, you can either have the str method of your user model return username, or create custom choices as a tuple of user ID & username in the form __init__

How do I filter values according to logged in user in Django forms?

I have Rank, UserProfile and Company models. These classes are connected with foreign keys. A user with Rank "Lead" can create new users from his dashboard. I want to filter Rank models according to UserProfile's company. In the sign up form there will be dropdown list to choose Rank for new user. There should only be ranks that belong to UserProfile's company. These are my models:
class CompanyProfile(models.Model):
comp_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
comp_name = models.CharField(max_length=200)
country = models.CharField(max_length=200, default='')
def __str__(self):
return self.comp_name
class Rank(models.Model):
rank_name = models.CharField(max_length=200)
company = models.ForeignKey(CompanyProfile, on_delete=models.CASCADE, null=True, unique=False)
def __str__(self):
return self.rank_name
class UserProfile(AbstractUser):
company = models.ForeignKey(CompanyProfile, on_delete=models.CASCADE, null=True, unique=False)
user_id = models.UUIDField(default=uuid.uuid4(), editable=False, unique=True)
username = models.CharField(max_length=500, unique=True)
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
password = models.CharField(max_length=250)
email = models.EmailField(max_length=254)
rank = models.ForeignKey(Rank, on_delete=models.CASCADE, null=True, unique=False)
image = models.ImageField(upload_to='profile_image', blank=True, null= True, default='profile.png')
def __str__(self):
return self.username
This is my form:
class SignUpForm(forms.ModelForm):
password1 = forms.CharField(max_length=250)
password2 = forms.CharField(max_length=250)
class Meta:
model = UserProfile
fields = (
'username', 'first_name', 'last_name', 'email', 'password1', 'password2','rank', 'image')
And this is views.py:
#user_passes_test(is_lead)
#login_required
def signup(request):
form_class = SignUpForm
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid() :
user = form.save()
user.refresh_from_db() # load the profile instance created by the signal
user.is_active = False
if form.cleaned_data['password1'] != "":
user.set_password(form.cleaned_data['password1'])
user.save()
return redirect('home')
else:
form = form_class()
return render(request, 'signup.html', {'form': form})
You'll need to override rank in your SignUpForm.
Something along the lines of:
choices = [(rank.id, rank.name) for rank in Rank.objects.filter(company=...)]
rank = models.CharField(
max_length=200,
choices=choices,
)
I assume you're passing the company into the form somehow so you'll need to adjust the filter to filter for the company you're creating the profile for.

Cannot assign "<QuerySet []>": " must be a "" instance

I am trying to save this field from Forms.py, which seems to be causing this error: Cannot assign "<QuerySet [Vehicles: Toyota]>": "Group.vehicles" must be a "Vehicle" instance.
Everything saves correctly through the admin page but not through the form.
class GroupForm(forms.ModelForm):
vehicles = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple(), queryset=Vehicles.objects.all())
class Meta:
model = Group
Models.py:
class Vehicles(models.Model):
Vehicles = models.CharField(max_length=30, null=True, blank=True)
MaxRange = models.DecimalField(null=True, max_digits=20, decimal_places=3, default=Decimal('0.000'))
Speed = models.DecimalField(null=True, max_digits=20, decimal_places=3, default=Decimal('0.000'))
def __str__(self):
return self.Vehicles
class Group(models.Model):
group = models.CharField(max_length=30, blank=True)
vehicles = models.ForeignKey(Vehicles, null=True, on_delete=models.CASCADE)
def __str__(self):
return self.group
'Group' consists of one type of vehicle.
views.py:
def home(request):
group = Group.objects.all()
form = GroupForm()
if request.method == 'POST':
form = GroupForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.vehicles = form.cleaned_data['vehicles']
obj.save()
return redirect('/')
context = {'group': group, 'form': form}
return render(request, 'calculator/Input.html', context)
Thanks you for any input
Nevermind, didn't need a checkbox widget. I deleted the line: "vehicles = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple(), queryset=Vehicles.objects.all())" and just left 'vehicle' as a field in Forms.py under class Meta: It saves/ users can only select one option now.

Select particular instance of a model with Foreign Key to another model

I have these models
class Review(models.Model):
# SET_NULL ensures that when a company is deleted, their reviews remains
company = models.ForeignKey(Company, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
# SET_NULL ensures that when a user is deleted, their reviews get deleted too
review_text = models.TextField(max_length=500, verbose_name='Your Review: (Maximum of 200 Words)')
rating = Int_max.IntegerRangeField(min_value=1, max_value=5)
date_added = models.DateField('Review Date', auto_now_add=True)
def __str__(self):
return self.review_text
class Response(models.Model):
user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
review = models.ForeignKey(Review, on_delete=models.CASCADE)
response = models.TextField(max_length=200, verbose_name='Your Response')
date_added = models.DateField('Response Date', auto_now_add=True)
def __str__(self):
return self.response
class ResponseReply(models.Model):
user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
response = models.ForeignKey(Response, on_delete=models.CASCADE)
review = models.ForeignKey(Review, on_delete=models.CASCADE)
reply = models.TextField(max_length=200, verbose_name="Your Reply")
date_added = models.DateField('Response Date', auto_now_add=True)
def __str__(self):
return self.reply
How to I select ResponseReply belonging to a particular response which also has a foreign key to a particular review.
My view rather returns a list instead of an object of the Review Model since there are more than one review. Below is my view:
def profile_company(request):
print(request.user)
company = get_object_or_404(Company, user=request.user)
review = get_object_or_404(Review, company=company)
responses = get_list_or_404(Response, review=review)
response = get_object_or_404(Response, review=review)
responses = get_list_or_404(Response, review=review)
reply = get_object_or_404(Response, response=response)
company_reviews = company.review_set.all()
total_reviews = len(company_reviews)
print(company.average_rating)
form = ResponseForm()
if request.method == "POST":
form = ResponseForm(request.POST or None)
if form.is_valid:
data = form.save(commit=False)
data.user = request.user
data.review = review
data.save()
return redirect('profile_company')
context = {
'company': company,
'company_reviews': company_reviews,
'total_reviews': total_reviews,
'form': form,
'responses': responses,
'reply': reply,
}
return render(request, 'companyusers/profile_company.html', context)
The problem is when I call response = get_object_or_404(Response, review=review) it fails since the review can be more than one. How do I select a particular response belonging to a particular review. To enable me select associated replies.
Thank you so much!

Django Foreign key field validation in a forms or models ( getting info created by only that user from foreign key)

I'm trying to build courses and add lessons to a course later and the problem I encounter is that every user can choose to add courses to another person created courses.
Like if you create some courses, another user will see as an option to add his lesson to it
views.py
def creatingLessonsForm(request):
form = CreatingLessonsForm(request.POST or None)
if form.is_valid():
post = form.save(commit=False)
post.CreatedBy = request.user
post.save()
form = CreatingLessonsForm()
context = {'form': form}
return render(request, 'courses/creatingLessonsForm.html', context)
models.py
class CreatingCourses(models.Model):
NameOfTheCourses = models.CharField("Name of the courses", max_length=60, blank=False)
Category = models.ForeignKey(Subject, on_delete=models.CASCADE)
CreatedBy = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
Document = models.ForeignKey(Document, on_delete=models.SET_NULL, verbose_name= "Select document for courses introduction", blank=True , null=True)
IncludeTest = models.ForeignKey(GenaratedTest, on_delete=models.SET_NULL, verbose_name= "Include test for courses", blank=True , null=True)
AdditionalInfo = models.TextField("Additional info for courses introduction", max_length=300, blank=False)
Note = models.TextField("Notes", max_length=180, blank=True)
Show_the_courses = models.BooleanField(verbose_name= "Show the courses for everyone?",default=True)
def __str__(self):
return str(self.NameOfTheCourses) if self.NameOfTheCourses else ''
class CreatingLessons(models.Model):
Courses = models.ForeignKey(CreatingCourses, on_delete=models.SET_NULL, null=True)
NameOfTheLesson = models.CharField(max_length=60, verbose_name= "Name of the lesson", blank=False)
Document = models.ForeignKey(Document, on_delete=models.SET_NULL, verbose_name= "Document for lesson", blank=True , null=True)
CreatedBy = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
Lesson = models.TextField(max_length=250, verbose_name= "Lesson", blank=False)
Note = models.TextField("Notes", max_length=100, blank=True)
Show_the_lesson = models.BooleanField(verbose_name= "Show the lesson inside courses?",default=True)
forms.py
class CreatingCoursesForm(forms.ModelForm):
class Meta:
model = CreatingCourses
fields = ['NameOfTheCourses', 'Category', 'IncludeTest', 'Document' , 'AdditionalInfo', 'Note', 'Show_the_courses' ]
class CreatingLessonsForm(forms.ModelForm):
class Meta:
model = CreatingLessons
fields = ['Courses', 'NameOfTheLesson', 'Document', 'Lesson', 'Note', 'Show_the_lesson']
Image of webpage:
You need to pass the user when you initialize the form and then filter the queryset for the available courses that can be selected
class CreatingLessonsForm(forms.ModelForm):
def __init__(self, data=None, user=None, **kwargs):
super().__init__(data, **kwargs)
self.fields['Courses'].queryset = CreatingCourses.objects.filter(CreatedBy=user)
And then when you initialize the form pass the user
# When rendering the initial form
form = CreatingLessonsForm(user=request.user)
# When passing POST data to the form
form = CreatingLessonsForm(request.POST, user=request.user)
One option would be to modify your to filter the courses by user.
class CreatingLessonsForm(forms.ModelForm):
...
def __init__(self, *args, **kwargs):
request_user = kwargs.pop('request_user')
super().__init__(*args, **kwargs)
self.fields['Courses'].queryset = self.fields['Courses'].queryset.filter(
CreatedBy=request_user)
For that to work you will need to pass in the user of the request to the form, maybe like this:
def creatingLessonsForm(request):
data = request.POST.copy()
data['request_user'] = request.user
form = CreatingLessonsForm(data)
...

Categories