I have a view which adds the items to the cart, but when I try to add the items to the cart Item model rising an error NOT NULL constraint failed: cart_item.product_id
I have created a model Item to capture the selected items
Here is my models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Product(models.Model):
product_title = models.CharField(null=True, blank=True,max_length=200)
product_price = models.IntegerField(null=True, blank=True,)
product_image = models.ImageField(upload_to='cart/products/', null=True, blank=True)
def __str__(self):
return self.product_title
class Cart_Bucket(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
create_date = models.DateTimeField(null=True, blank=True,verbose_name='create_date', auto_now=True)
checked_out = models.BooleanField(default=False, verbose_name='checked_out')
def __unicode__(self):
return unicode(self.create_date)
class Item(models.Model):
cart = models.ForeignKey(Cart_Bucket, verbose_name='cart', on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(verbose_name='quantity')
product = models.ForeignKey(Product, verbose_name='product', related_name='product', on_delete=models.CASCADE)
def __str__(self):
return u'%d units' % (self.quantity)
Views.py
def add_to_cart(request):
user = request.user
if not user.is_authenticated:
chars = string.ascii_uppercase + string.digits
user_name = ''.join(random.choice(chars) for _ in range(9))
password = '1234567a'
user = User.objects.create(username=user_name, first_name='guest', last_name='guest', email='guest#gmail.com', is_active=True, is_staff=True)
user.set_password(password)
user.save()
user = authenticate(username=user_name, password=password)
if user:
login(request, user)
product_id = request.GET.get('product_id')
cart = Cart_Bucket.objects.filter(checked_out=False, user=user)
cart = cart[0] if cart else ''
if not cart:
cart = Cart_Bucket.objects.create(user=user)
Item.objects.create(cart=cart, product_id=product_id, quantity=1)
print(Item.objects.all)
return render(request, 'products/products.html')
my products.html
{% extends 'home/base.html' %}
{% block body %}
<div class="row">
{% for products in product %}
<div class="col-md-6 col-centered">
<img src="{{ products.product_image.url }}" style="width: 30%;display:block;margin:0 auto;">
<div class="row">
<div class="col-md-2"></div>
<div class="col-md-6">
<br>
<p>{{ products.product_title }} Price : $ {{ products.product_price }} </p>
</div>
<div class="col-md-6"></div>
<div class="col-md-4">
Add to Cart
</div>
<div class="col-md-2"></div>
</div>
<hr>
</div>
{% endfor %}
</div>
{% endblock %}
I want to see the add_to_cart items on the cart page
I think that raises the problem because Item.objects.create() tries to save the model to the database first, before parsing all arguments. Based on Django documentation, .save() method has some advantages over create() method. This problem should be resolved if you change your code like:
newItem = Item()
newItem.cart = cart
newItem.product_id = product_id
newItem.quantity = 1
newItem.save()
Related
My vews.py:
if you want me to share another piece of information feel free to ask!
I just have a problem with the bidding system !!, I tried the bidding but when I add the new number into the input field and click the place bid button the page just reloads which means the function doesn't work!!
I have another problem when I try to close the bid I git this Django error
ValueError at /bidding/26
The view auctions.views.bidding didn't return an HttpResponse object.
It returned None instead.
The code:
def viewList(request, id):
# check for the watchlist
listing = Post.objects.get(id=id)
user = User.objects.get(username=request.user)
if listing.watchers.filter(id=request.user.id).exists():
is_watched = True
else:
is_watched = False
if not listing.activate:
if request.POST.get('button') == "Close":
listing.activate = True
listing.save()
else:
price = request.POST.get('bid', 0)
bids = listing.bids.all()
if user.username != listing.creator.username:
if price <= listing.price:
return render(request, 'auctions/item.html', {
"listing": listing,
'form': BidForm(),
"message": "Error! Your bid must be largest than the current bid!",
'comment_form': CommentForm(),
'comments': listing.get_comments.all(),
'is_watched': is_watched,
})
form = BidForm(request.POST)
if form.is_valid():
bid = form.save(commit=False)
bid.user = user
bid.save()
listing.bids.add(bid)
listing.bid = price
listing.save()
else:
return render(request, 'acutions/item.html', {'form'})
context = {
'listing': listing,
'comment_form': CommentForm(),
'comments': listing.get_comments.all(),
'is_watched': is_watched,
'form': BidForm()}
return render(request, 'auctions/item.html', context)
models.py
class Bid(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
bid = models.DecimalField(max_digits=10, decimal_places=2)
time = models.DateTimeField(default=timezone.now)
class Post(models.Model):
# data fields
title = models.CharField(max_length=64)
textarea = models.TextField()
# bid
price = models.FloatField(default=0)
currentBid = models.FloatField(blank=True, null=True)
imageurl = models.CharField(max_length=255, null=True, blank=True)
category = models.ForeignKey(
Category, on_delete=models.CASCADE, default="No Category Yet!", null=True, blank=True)
creator = models.ForeignKey(
User, on_delete=models.PROTECT, related_name="all_creators_listings")
watchers = models.ManyToManyField(
User, blank=True, related_name='favorite')
date = models.DateTimeField(auto_now_add=True)
# for activated the Category
activate = models.BooleanField(default=False)
bids = models.ManyToManyField(Bid, )
def __str__(self):
return f"{self.title} | {self.textarea} | {self.date.strftime('%B %d %Y')}"
item.html
<div class="card-body">
<ul class="list-group">
<div class="info">
<li class="list-group-item mb-2">Description:<br>{{listing.textarea}}</li>
<li class="list-group-item mb-2">category: {{listing.category.name}}</li>
<li class="list-group-item mb-2"><h5>Start bid: {{listing.price}}$</h5></li>
</div>
<div class="newbid">
<p>{{ message }}</p>
<form action="{% url 'viewList' listing.id %}" method="POST">
{% csrf_token %}
<div class="form-group">
<label for="bid">{{ listing.bids.count }} bid(s) so far. Your bid is the current bid</label>
</div>
<div class="form-group">
{{ form }}
</div>
<div class="form-group">
<input type="submit" name="button" class="btn btn-primary" value="Place Bid">
</div>
</form>
{% if listing.activate %}
<li><strong>Winner: </strong>{{ listing.bids.last.user.username }}</li>
{% endif %}
{% if user.username == listing.creator.username and not listing.activate %}
<form action="{% url 'viewList' listing.id %}" method="POST">
{% csrf_token %}
<button type="submit" name="button" class="btn btn-danger" value="Close">Close</button>
</form>
{% endif %}
</div>
</ul>
</div>
inside this view, I added a punch of my project requirement (comments/watchlist(bookmark)/and the last thing(that what I have a lot of problem with it) is the system of Bid) that lets users add bids on such posts and let the creator of that post the ability to close it.... please help I am sticking in this zone, I tried many times to understand!
Note I am new at Back-end Development!
There is the two problem in you code first one is hi-lighted by Husam
user = User.objects.get(username=request.user.username)
and the other one is in the return statement in the else part
render(request, 'acutions/item.html', {'form'}) instead of context object you pass the string in which is consider as set object in python and thats why you are getting None type error.
here is the refactored code :-
def viewList(request, id):
# check for the watchlist
listing = Post.objects.get(id=id)
user = User.objects.get(username=request.user.username)
form = BidForm()
is_watched = listing.watchers.filter(id=request.user.id).exists():
context = {}
if not listing.activate:
if request.POST.get('button') == "Close":
listing.activate = True
listing.save()
else:
price = request.POST.get('bid', 0)
bids = listing.bids.all()
if user.username != listing.creator.username:
if price <= listing.price:
context.update({'message':"Error! your bid must be largest than the current bid !"})
else:
form = BidForm(request.POST)
if form.is_valid():
bid = form.save(commit=False)
bid.user = user
bid.save()
listing.bids.add(bid)
listing.bid = price
listing.save()
else:
return render(request, 'acutions/item.html', {'form': form})
context.update({'listing': listing,
'comment_form': CommentForm(),
'comments': listing.get_comments.all(),
'is_watched': is_watched,
'form': form})
return render(request, 'auctions/item.html', context)
The error you face in bidding view and the view you have shared is view list, it would be better if you shared the bidding view and highlight the error line/s
Anyway I have noticed that this line has one mistake:
user = User.objects.get(username=request.user)
Which suppose to be :
user = User.objects.get(username=request.user.username)
Hope this can help you little bit
How to properly user prefetch_related with ManyToMany relation
my model:
class Subject(models.Model):
subject_name = models.CharField(max_length=150)
subject_code = models.CharField(max_length=50)
year = models.ForeignKey(YearLevel, null=True, on_delete=models.SET_NULL)
units = models.CharField(max_length=10)
def __str__(self):
return self.subject_name + ' ' + '(' + self.subject_code + ')'
class Student(models.Model):
student = models.ForeignKey(settings.AUTH_USER_MODEL, limit_choices_to= Q(is_student=True), on_delete= models.CASCADE)
enrolled_subject = models.ManyToManyField(Subject)
my view:
def home(request):
verses = VerseOfTheDay.objects.all()
news = Announcement.objects.all()
student_grade_form = AddStudentGradeForm()
students = Student.objects.all().prefetch_related('subject_set')
context = {
"verse": verses,
'news': news,
'form': student_grade_form,
'students': students,
}
return render(request, 'sample.html', context)
my html:
{% for student in students %}
<p>
<a class="btn btn-primary" data-bs-toggle="collapse" href="#collapse{{forloop.counter}}" role="button" aria-expanded="false" aria-controls="collapse{{forloop.counter}}">
{{student.student}}
</a>
</p>
<div class="collapse" id="collapse{{forloop.counter}}">
<div class="card card-body">
{% for subject in student.subject_set.all %}
{{subject.subject}}
{% endfor %}
</div>
</div>
{% endfor %}
I am getting an error:
AttributeError at /
Cannot find 'subject_set' on Student object, 'subject_set' is an invalid parameter to prefetch_related()
Change this line
students = Student.objects.all().prefetch_related('subject_set')
to
students = Student.objects.all().prefetch_related('enrolled_subject')
So I'm trying to make an search option where users can search via categories and name but only name worked, when i used icontains on category it just gave me an error but did not give me an error with name also categories just does not load in HTML. Categories are supposed to load in <select> tag but it is not working, searchall function handles the page I'm talking about and search.html is the page.
this is the complete error
views.py
def searchall(request):
getobject = request.GET['search']
getcategory = request.GET['category']
if getcategory == 'All':
getcategory = ""
search = Book.objects.filter(name__icontains=getobject, category__icontains=getcategory)
oof = CartItem.objects.filter(user=request.user).values_list('book', flat=True)
lmao = OrderItem.objects.filter(user=request.user).values_list('book', flat=True)
hehe = CartItem.objects.filter(user=request.user)
category = Category.objects.all()
fianlprice = 0
for item in hehe:
fianlprice += item.book.price
books = Book.objects.all()
return render(request, 'main/search.html', {'books':search, 'price':fianlprice, 'cart':oof, 'order':lmao, 'category':category})
search.html
<h1>search</h1>
<h1>{{ error }}</h1>
<h1>Your cart currently costs ${{ price }}</h1>
<form method="GET" action="">
<input type="text" placeholder="Search here" name="search" id="search">
<button type="submit">Search</button>
</form>
{% for book in books %}
<h3>{{ book.name }}</h3>
<img src= "/media/{{ book.image }}" alt="">
<p>{{ book.description }}</p>
{% if book.id in cart %}
<form method="POST" action="/removefromcartforproducts/">
{% csrf_token %}
<button type="submit" name="removeid" value="{{ book.id }}">remove item from cart</button>
</form>
{% elif book.id in order %}
<h3>You already own this</h3>
{% else %}
<form method="POST" action="/addtocartforproducts/">
{% csrf_token %}
<button type="submit" name="bookid" value="{{ book.id }}">Add to cart</button>
</form>
{% endif %}
{% endfor %}
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Meta:
verbose_name = 'Category'
verbose_name_plural = 'Categories'
class Book(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
image = models.ImageField()
price = models.IntegerField()
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.name
class OrderItem(models.Model):
order_id = models.CharField(max_length=10)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
book = models.ForeignKey(Book, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.user.username
class CartItem(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
book = models.ForeignKey(Book, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.user.username
In your searchall method, you are trying to filter category. But, as your Book model have category property which is object not a string. So, you have to go further inside it and compare the name of that category.
So:
def searchall(request):
getobject = request.GET['search']
getcategory = request.GET['category']
if getcategory == 'All':
getcategory = ""
search = Book.objects.filter(name__icontains=getobject, category__name__icontains=getcategory)
oof = CartItem.objects.filter(user=request.user).values_list('book', flat=True)
lmao = OrderItem.objects.filter(user=request.user).values_list('book', flat=True)
hehe = CartItem.objects.filter(user=request.user)
category = Category.objects.all()
fianlprice = 0
for item in hehe:
fianlprice += item.book.price
books = Book.objects.all()
return render(request, 'main/search.html', {'books':search, 'price':fianlprice, 'cart':oof, 'order':lmao, 'category':category})
Refs on span relationship lookups(__).
With the below code i am adding reviews for some particular product in the database and it is doing good but the problem is while displaying the reviews for the selected product.I get confused how can i display the all reviews of some product and which review done by which user at what time?
models.py
class Product(models.Model):
name = models.CharField(max_length=250)
description = models.TextField(blank=True)
featured = models.BooleanField(default=False)
def __str__(self):
return self.name
class Review(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
review = models.TextField()
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.review
views.py
def detail(request,pk):
product = College.objects.get(pk=pk)
form = ReviewForm()
return render(request,'products/detail.html',{'product':product,'form':form})
#login_required(login_url='products:signin')
def review(request,pk):
if request.method == "POST":
form = ReviewForm(request.POST)
if form.is_valid():
review = form.save(commit=False)
review.product = Product.objects.get(pk=pk)
review.user = request.user
review.save()
messages.success(request, "Review saved")
return redirect('products:detail',pk)
else:
messages.error(request,'error in form')
return redirect('products:detail', pk)
detail.html
<h3>All reviews(total.no. of reviews?)</h3>
# Here i want to display all reviews and which is done by which user and at what time
<div class="col-lg-6 col-md-6 mb-6">
<form method="post" action="{% url 'products:review' product.pk %}">
{% csrf_token %}
{% form.as_p %}
<input type="submit" class="btn btn-success">
</form>
</div>
You can do it like this using reverse relation:
<h3>All reviews {{ product.review_set.count }}</h3>
{% for review in product.review_set.all %}
{{ review.review }}
{{ review.date }}
{% endfor %}
I have 2 models: UserProfile and User_Details and I want to display the details for one user.I think the problem is at the filter and I don't know how to filter after a string,I'm new to django.How can I fix this?
class ShowProfile(APIView):
renderer_classes = [TemplateHTMLRenderer]
template_name = 'profile.html'
def get(self, request, pk, format=None):
details=User_Details.objects.all().filter(user=request.user.username)
serializer = ProfileSerializer2(details, many=True)
pprint.pprint(json.loads(JSONRenderer().render(serializer.data)))
return Response({'fields ': serializer})
def post(self, request):
serializer = CreatePostSerializer(data=request.data)
if not serializer.is_valid():
return Response({'fields': serializer })
user = UserProfile.objects.filter(username=request.user.username).first()
serializer.save(user=user)
pprint.pprint(json.loads(JSONRenderer().render(serializer.data)))
return redirect('mainPage')
Models:
class UserProfile(AbstractUser):
pass
class User_Details(models.Model):
user = models.OneToOneField(UserProfile, on_delete=models.CASCADE)
first_name = models.CharField(max_length=50, blank = True)
last_name = models.CharField(max_length=50, blank=True)
gender = models.CharField(max_length=6, blank=True, default='')
public_info=models.CharField(max_length=100, blank=True, default='')
Template:
{% extends 'base2.html' %}
{% load rest_framework %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-3 ">
<div class="list-group ">
Profile
My Posts
</div>
</div>
{% for d in fields %}
{{d.firs_name }}<h1>a</h1>
{% endfor %}
{% endblock %}