How to search objects in django using an instance of choicefield? - django

This is my model:
class Profile(models.Model):
date = models.DateTimeField(auto_now_add=True)
full_name = models.CharField(max_length=32,blank=True)
user_types = (
('Business User','Business User'),
('Professional','Professional'),
)
user_type = models.CharField(max_length=32,choices=user_types,default='Business User',blank=False)
user= models.OneToOneField(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
e_mail = models.EmailField(max_length=70,blank=True)
As you can see the are two types of user in my Profile model Business User and Professional. So I want to make a query in django which will search only for the Professional users.
I have tried this in my views:
query = request.GET.get('q')
if query:
if Profile.objects.filter(user_type__icontains='Professional'):
result = Profile.objects.filter(Q(user__username__icontains=query) | Q(e_mail__icontains=query) | Q(full_name__icontains=query))
else:
result = Profile.objects.filter(user_type__icontains='Professional').order_by('id')
In my template:
<form method='GET' class="form-horizontal" id="search-form" action="{% url 'userprofile:search' %}">
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-6">
<input class="form-control" name="q" value="{{request.GET.q}}" placeholder="Search">
</div>
<div >
<span class="input-group-btn">
<button type="submit" class="btn btn-info pull-right">Go</button>
</span>
</div>
</form>
But when I search for a Professional user it gives me list of all the user associated with that name.
Can anyone provide me with suitable solution for this.
Thank you

Solved It
Done the following in my view and it worked:
user_profile = Profile.objects.filter(user_type__icontains='Professional')
query = request.GET.get('q')
if query:
result = user_profile.filter(Q(user__username__icontains=query) | Q(e_mail__icontains=query) | Q(full_name__icontains=query))
else:
result = Profile.objects.filter(user_type__icontains='Professional').order_by('id')

Related

I am trying to get POST request but django response with GET request

I am trying to get the post request and i have tried everything it is still getting me get requests.
Please Help.
I have tried using that i saw in other problems displayed here. but it is not working for me.
{% csrf_token%}
Item name
{{form.item_name}}
Quantity
{{form.quantity}}
<div class="form-group">
<label for="address">Address</label>
{{form.address}}
</div>
<div class="modal-footer d-flex justify-content-center">
<button type="submit" id="submit" class="btn btn-success" data-dismiss="modal" >Donate</button>
</div>
</form>
This is my view file
#this is my view
#login_required(login_url='loginPage')
def home(request):
form = DonateForm()
print(request.user.id)
get_user = user_info.objects.get(id=request.user.id)
print('Inside Home View')
print(get_user)
print(request)
if request.method == 'POST':
form = DonateForm(request.POST)
print('Inside Home Page')
if form.is_valid():
print('Form is valid!!')
user = form.save()
Donate.objects.create(user_name = user,item_name=form.cleaned_data['item'],quantity=form.cleaned_data['itemquantity'])
else:
messages.add_message(request,messages.INFO,'Your details are Incorrect!!')
else:
print('No Post Request!!')
return render(request,'donate/home.html',{'form':form,'get_user':get_user})
Here is my Models.py
class Donate(models.Model):
user_name = models.ForeignKey(user_info,on_delete=models.CASCADE)
item_name = models.CharField(max_length=30,null=False , blank=False, default ="None")
quantity = models.IntegerField(null=False,blank=False,default=0)
address = models.CharField(max_length=100 , null=False , blank= False, default="None")
def __str__(self):
return f"{self.user_name.user.username} donated {self.item_name}"
Please try to add the method in the <form>, like this:
<form method="post" action="#">
{% csrf_token %}
......
<button type="submit" id="submit" class="btn btn-success" data-dismiss="modal" >Donate</button>
</form>

Django objection creation failing due to FOREIGN KEY constraint failure (IntegrityError )

My website has a comment section where user can leave comments on a product . The comments on the product page will be stored in a model called 'ProductReview'. Here is the code for the model :
class ProductReview(models.Model):
product = models.ForeignKey(Product, related_name='reviews', on_delete=models.CASCADE)
name = models.CharField(blank=True,max_length=20)
stars = models.IntegerField()
content = models.TextField(blank=True)
date_added = models.DateTimeField(auto_now_add=True)
created_by = models.OneToOneField(User, on_delete=models.CASCADE)
Now the view associated with the model are as follows Note:The entire view isnt relevant to the error. The part relevant to the saving comment is the second 'request.POST' which I have denoted with a python
comment using # :
def product(request, category_slug, product_slug):
cart = Cart(request)
product = get_object_or_404(Product, category__slug=category_slug, slug=product_slug)
if request.method == 'POST':
form = AddToCartForm(request.POST)
if form.is_valid():
quantity = form.cleaned_data['quantity']
cart.add(product_id=product.id, quantity=quantity, update_quantity=False)
messages.success(request, 'The product was added to the cart')
return redirect('product', category_slug=category_slug, product_slug=product_slug)
similar_products = list(product.category.products.exclude(id=product.id))
# this part is for saving of the user comments to productreview model
if request.method == 'POST':
stars = request.POST.get('stars', 3)
content = request.POST.get('content', '')
name = request.POST.get('name', '')
created_by = request.user
review = ProductReview.objects.create(product=product, name=name, stars=stars, content=content, created_by=created_by)
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
# this marks the end of the code relevant to saving the user comment
if len(similar_products) >= 4:
similar_products = random.sample(similar_products, 4)
user_type = 0
if request.user.is_authenticated:
user_type = UserType.objects.filter(created_by=request.user.id).values_list('user_type', flat=True)
user_type = int(user_type[0])
return render(request, 'product.html', {'product': product, 'similar_products': similar_products, 'user_type': user_type})
And finally the relevant part of the template 'product.html' which is referenced in the view
{% if request.user.is_authenticated %}
{% if user_type == 2 %}
<div class="notification space-below">
<form method="post" action=".">
{% csrf_token %}
<div class="field">
<label>Name</label>
<div class="control">
<input class="text" name="name" value="{{ request.user }}" readonly>
</div>
</div>
<div class="field">
<label>Stars</label>
<div class="control">
<div class="select">
<select name="stars">
<option value="1">1</option>
<option value="2">2</option>
<option value="3" selected>3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
</div>
</div>
</div>
<div class="field">
<label>Content</label>
<div class="control">
<textarea class="textarea" name="content"></textarea>
</div>
</div>
<div class="field">
<div class="control">
<button class="button is-success">Submit</button>
</div>
</div>
</form>
</div>
{% else %}
<div>sign in with a buyer account to leave review</div>
{% endif %}
{% endif %}
Now when I try to fill the form in the product.html page and try to submit it ,I get the following error:
FOREIGN KEY constraint failed
IntegrityError at /smartwatch/apple-watch/
Can anyone tell what exactly is the issue with my code?
Pretty sure this all comes to your model, especially to this single line:
created_by = models.OneToOneField(User, on_delete=models.CASCADE)
You are using OneToOneField. This means a single user will be able to leave a single review in your entire application. You are getting integrity errors probably because this user you've selected already has a review on a different product.
If this isn't what you want, use normal ForeignKey instead.
I think your intention was to ensure that a single user can leave only one review per product. In that case, you should try setting UniqueConstraint between the product and created_by fields

How to get the current object / product from the class based detail view in django?

'''Models Code'''
# Product Model
class Products(models.Model):
name = models.CharField(max_length=50)
img = models.ImageField(upload_to='productImage')
CATEGORY = (
('Snacks','Snacks'),
('Juice','Juice'),
)
category = models.CharField(max_length=50, choices=CATEGORY)
description = models.TextField()
price = models.FloatField()
# Rating Model
class Rating(models.Model):
product = models.ForeignKey(Products, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
stars = models.IntegerField(validators=[MinValueValidator(1),MaxValueValidator(5)], blank=True, null=True)
comment = models.TextField(blank=True,null=True)
''' Views Code '''
class ProductListView(ListView):
model = Products
template_name = 'products.html'
context_object_name ='Products'
class ProductDetailView(LoginRequiredMixin,DetailView):
login_url = '/accounts/login'
model = Products
# Using this function I want to take the rating and comment, but how can I access the cuurent object for which the comment and rating is being send by the user.
def review(request,slug):
star=request.POST.get('rating')
comment=request.POST.get('comment')
user = request.user
productId = request.POST.get('productsid') # How to get the Product
product = Products.objects.get(id=productId)
review = Rating(product=product,user=user,stars=star,comment=comment)
review.save()
return redirect('/')
# Urls code
urlpatterns = [
path('',views.home,name='Home'),
path('products',ProductListView.as_view(),name='Products'),
path('product/<int:pk>',ProductDetailView.as_view(),name='Product-Details'),
path('contact',views.contact,name='Contact'),
path('review',views.review,name='review')
#Templates Code
<form method="POST" action="review">
{% csrf_token %}
<input type="hidden" id="rating-value" name="rating">
<textarea style="margin-top:5px;" class="form-control" rows="3" id="comment" placeholder="Enter your review" name="comment"></textarea>
<button type="submit" style="margin-top:10px;margin-left:5px;" class="btn btn-lg btn-success">Submit</button>
</form>
How to fetch the current object from the deatailed view page in the review function?
I have added the code here. In Product detailed view page it is rendering the page through which I want to take rating and comment for the product . Is there any other way through which I can get the product, user , star, and rating field value and store it in the data base?
I can point out some ways to retrieve the product_id in your review function.
First approach:
You can pass the product_id as a URL parameter. In this case, I hope the review view is called from the product detail page.
So, your url should be something like:
path('review/<int:product_id>', views.review, name="review),
Your view:
def review(request, *args, **kwargs):
star=request.POST.get('rating')
comment=request.POST.get('comment')
user = request.user
productId = kwargs.get('product_id') # change is here
product = Products.objects.get(id=productId)
review = Rating(product=product,user=user,stars=star,comment=comment)
review.save()
return redirect('/')
Your template:
<form method="POST" action="{% url 'review' object.pk %}">
{% csrf_token %}
<input type="hidden" id="rating-value" name="rating">
<textarea style="margin-top:5px;" class="form-control" rows="3" id="comment" placeholder="Enter your review" name="comment"></textarea>
<button type="submit" style="margin-top:10px;margin-left:5px;" class="btn btn-lg btn-success">Submit</button>
</form>
In the template, the object is the object_name you have given to the product object. You can change the object name by adding:
context_object_name = product
in your ProductDetailView.
Second approach:
Pass the product_id as a form data. You can create a hidden input in your template that will contain the product_id as value. For example:
In your template:
<form method="POST" action="review">
{% csrf_token %}
<input type="hidden" id="rating-value" name="rating">
<input type="hidden" name="product_id" value="{{ object.pk }}"> # add a hidden input field
<textarea style="margin-top:5px;" class="form-control" rows="3" id="comment" placeholder="Enter your review" name="comment"></textarea>
<button type="submit" style="margin-top:10px;margin-left:5px;" class="btn btn-lg btn-success">Submit</button>
</form>
Where object is what I mentioned previously.
Then you can retrieve the product_id in view as:
def review(request,slug):
star=request.POST.get('rating')
comment=request.POST.get('comment')
user = request.user
productId = int(request.POST.get('product_id')) # here
product = Products.objects.get(id=productId)
review = Rating(product=product,user=user,stars=star,comment=comment)
review.save()
return redirect('/')

how to save many to many field using django custom forms

how can i save many courses to the student table .I want to keep my design like this.This code is not saving the many to many field(courses) through AddStudentForm.It returns an error with courses variable.If i used CharField instead of ManyToManyField in models for courses then the code works perfectly,but when i use ManyToManyField then it is not working.
it throws courses when i used form.errors .If i didn't use form.errors then it doesn't give any error neither saves the data.
how can i save many courses to the student table .I want to keep my design like this.This code is not saving the many to many field(courses) through AddStudentForm.It returns an error with courses variable.
models.py
class Course(models.Model):
title = models.CharField(max_length=250)
price = models.IntegerField(default=0)
duration = models.CharField(max_length=50)
def __str__(self):
return self.title
class Student(models.Model):
name = models.CharField(max_length=100)
courses = models.ManyToManyField(Course)
email = models.EmailField()
image = models.ImageField(upload_to='Students',blank=True)
def __str__(self):
return self.name
forms.py
class AddStudentForm(forms.ModelForm):
# courses = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Course.objects.all())
class Meta:
model = Student
fields = ['name','courses','email','image']
def __init__(self, *args, **kwargs):
super(AddStudentForm, self).__init__(*args, **kwargs)
self.fields["courses"].widget = CheckboxSelectMultiple()
self.fields["courses"].queryset = Course.objects.all()
views.py
def addstudent(request):
courses = Course.objects.all()
if request.method == 'POST':
form = AddStudentForm(request.POST,request.FILES)
if form.is_valid():
student = form.save(commit=False)
course = form.cleaned_data['courses']
student.courses = course
student.save()
# student.courses.add(course)
# student.save_m2m()
# student.courses.set(course) # this method also didn't helped me
messages.success(request, 'student with name {} added.'.format(student.name))
return redirect('students:add_student')
else:
# messages.error(request,'Error in form.Try again')
return HttpResponse(form.errors) # this block is called and returns courses
else:
form = AddStudentForm()
return render(request,'students/add_student.html',{'form':form,'courses':courses})
add_student.html
<form action="{% url 'students:add_student' %}"
method="post"
enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
<h5>Full Name <span class="text-danger">*</span>
</h5>
<div class="controls">
<input type="text" name="name" class="form-
control" > </div>
</div>
<div class="form-group">
<h5>Courses<span class="text-danger">*</span>
</h5>
<div class="controls">
{% for course in courses %}
<input name ="courses" type="checkbox" id="course-
{{course.id}}" value="{{course.title}}">
<label for="course-{{course.id}}">{{course.title}}
</label>
{% endfor %} # i think the problem is here.
</div>
</div>
<div class="form-group">
<h5>Email <span class="text-danger">*</span></h5>
<div class="controls">
<input type="text" name="email" class="form-
control" required> </div>
</div>
</div>
<div class="form-group">
<h5>Image <span class="text-danger">*</span></h5>
<div class="controls">
<input type="file" name="image" class="form-control" > </div>
</div>
<div class="text-xs-right">
<button type="submit" class="btn btn-info">Add</button>
</div>
</form>
You need to save first before you can assign m2m, the system needs the primary key of the Student model before it can insert into the m2m table.
if form.is_valid():
student = form.save(commit=False)
course = form.cleaned_data['courses']
student.save()
# this will save by itself
student.courses.set(course)

how to write join query in django?

I have googled several hours but couldn't understand how to write sql join(raw or ORM) related queries.
Below is my model with two tables sandBox1 and licenseType where they will have common item "email" on which join will be performed
class sandBox1(models.Model):
email = models.EmailField(unique=True)
name = models.CharField(max_length=200)
website = models.TextField(validators=[URLValidator()])
comment = models.TextField(default='-')
gender = models.CharField(max_length=6)
def __str__(self):
return self.email
class licenseType(models.Model):
#1=other, 2=two-wheeler 4=four-wheeler
licenseId = models.IntegerField()
email = models.EmailField()
template file : index.html
<html><form id="form1" method="post" action="{% url "sandbox" %}">
{% csrf_token %}
Name: <input type="text" name="name" >
<br><br>
E-mail: <input type="text" name="email">
<br><br>
Website: <input type="text" name="website" >
<span class="error"></span>
<br><br>
Comment: <textarea name="comment" rows="5" cols="40"></textarea>
<br><br>
Gender:
<input type="radio" name="gender" value="female">Female
<input type="radio" name="gender" value="male">Male
<hr>Check the license type you have:-<br>
<input type="checkbox" name="license[]" value=2 > 2 wheeler<br>
<input type="checkbox" name="license[]" value=4 > 4 wheeler<br>
<input type="checkbox" name="license[]" value=1 > Other <br>
<br>
<input type="submit" name="submit" value="Submit">
</form>
<div>
{% for obj in sandBoxObj %}
<p>
{{ obj.name }}<br>
{{ obj.email }}<br>
{{ obj.website }}<br>
{{ obj.gender }}<br>
{{ obj.comment }}<br>
{% endfor %}
</div>
</html>
here is a view file that needs correction. I want to show the result of this sql query:
select sandBox1.email,sandBox1.name,licenseType.licenseId from sandBox1
innerjoin licenseType on sandBox1.email=licenseType.email;
View file
def sandbox(request):
template_name='domdom.html'
sandBoxObj = sandBox1.objects.all()
context = { 'sandBoxObj':sandBoxObj }
print request.POST
if request.method == 'POST':
website=request.POST.get('website','')
comment=request.POST.get('comment','')
name=request.POST.get('name','')
gender=request.POST.get('gender','')
email=request.POST.get('email', '')
license=request.POST.getlist('license[]')
for id in license:
licInst = licenseType(licenseId=id,email=email)
licInst.save()
sbinstance = sandBox1(website=website,comment=comment,name=name,gender=gender,email=email)
sbinstance.save()
return render(request,template_name,context)
Raw sql method/ but im still confused on ORM method
def sandbox(request):
template_name='domdom.html'
sandBoxObj = sandBox1.objects.all()
con = sqlite3.connect('/home/user1/PycharmProjects/djrest/invoicesproject/db.sqlite3') #sqlite database file location
cursor = con.cursor()
cursor.execute(''' select todos_sandBox1.email,todos_sandBox1.name,todos_sandBox1.website,todos_sandBox1.comment,todos_sandBox1.gender,todos_licenseType.licenseId from todos_sandBox1
join todos_licenseType on todos_sandBox1.email=todos_licenseType.email
''') #it looks like django appends app name to table eg. appname = todos
result = cursor.fetchall()
#https://www.youtube.com/watch?v=VZMiDEUL0II
context = { 'result':result }
print request.POST
if request.method == 'POST':
website=request.POST.get('website','')
comment=request.POST.get('comment','')
name=request.POST.get('name','')
gender=request.POST.get('gender','')
email=request.POST.get('email', '')
license=request.POST.getlist('license[]')
for id in license:
licInst = licenseType(licenseId=id,email=email)
licInst.save()
sbinstance = sandBox1(website=website,comment=comment,name=name,gender=gender,email=email)
sbinstance.save()
return render(request,template_name,context)
Sorry if this answers the wrong question, but you may want to consider a different data model/ architecture. You are hardcoding SANDBOX1 which implies that there might be multiple Sandboxes and you are listing email fields which aren't tied to the User object. Some basic abstractions may simplify the work. Maybe something like:
from django.contrib.auth.models import User
...
class LicenseTypes(models.Model):
name = models.CharField(max_length=500)
class Customer(models.Model):
name = models.CharField(max_length=500)
license = models.ForeignKey(LicenseType)
class RegisteredUser(models.Model):
customer = models.ForeignKey(Customer, on_delete = models.CASCADE)
user = models.ForeignKey(User)
I like this architecture better because it uses a lot more native django functionality. And makes joins really basic. Check this out in a view:
def django_view(request):
registered_user = RegisteredUser(user=request.user)
#example of how to use the join implicitly/ directly
license = registered_user.customer.license.name