How to fix add to cart functionality in django? - django

I'm building an ecommerce platform and I want to create the add to cart functionality in the website. But for some reason the Product Id is showing null.
Here's the codes:
models.py
class Products(models.Model):
user = models.ForeignKey(User, on_delete = models.CASCADE)
title = models.CharField(max_length = 255)
product_category = models.CharField(choices = CATEGORY_CHOICES, max_length = 100)
description = models.TextField()
price = models.FloatField(max_length= 5)
class Cart(models.Model):
user = models.ForeignKey(User, on_delete = models.CASCADE)
products = models.ForeignKey(Products, on_delete = models.CASCADE)
views.py
def add_cart(request):
product_id = Products.id
new_product = Cart.objects.get_or_create(id=product_id, user=request.user)
return redirect('/')
templates
<div class="product-wrapper">
<h1 style="font-size:24px">{{product.title}}</h1>
<div class="product-price">
<p style="text-decoration-line:line-through;">$ {{product.price}}</p>
<a href="{% url 'add-product' product.product_id %}">Add to cart<a>
</div>
When I try to click this link it gives me this error: Field 'id' expected a number but got <django.db.models.query_utils.DeferredAttribute object at 0x000002468A4F8550>.
Any suggestion will be really helpful. Thank you

Finally, I've fixed this.
view.py
def add_to_cart(request, slug):
products = Products.objects.get(slug=slug)
ncart = Cart.objects.create(user=request.user, products=products)
ncart.save()
return redirect('/')
template
<div class="product-wrapper">
<h1 style="font-size:24px">{{product.title}}</h1>
<div class="product-price">
<p style="text-decoration-line:line-through;">$ {{product.price}}</p>
<a href="{% url 'add-to-cart' product.slug %}">Add to cart<a>
</div>
urls.py
path('cart/add/<slug:slug>', views.add_to_cart, name = 'add-to-cart')

Considering you've got Products instance already, in that case
Query directly like:
new_product = Cart.objects.get_or_create(products=Products)
If you want to query from the product_id, do it like that:
product_id = Products.pk
new_product = Cart.objects.get_or_create(products_id=product_id)
In addition:
request.user contains a dictionary, you can't pass it directly to query. And the user field has name buyer, so change that query like that:
product_id = Products.pk
new_product = Cart.objects.get_or_create(products=Products, buyer_id=request.user['pk'])

Related

django eccomerce prodcut name not showing in file

i am creating a new django eccomorce website now in product detail page here is my code
the problem is i cant see product name correct in html page problem with first()
when i use first then only product name showing but all products have same name i have 8 producs in my page eight product name same to first just like overwriting also i cant use for loop with first()
i will add some pics
urls.py
path('collection/<str:cate_slug>/<str:prod_slug>',views.product_view,name="productview"),
views.py
def product_view(request,cate_slug,prod_slug):
if (Category.objects.filter(slug=cate_slug, status=0)):
if (Products.objects.filter(slug=prod_slug, status=0)):
products = Products.objects.filter(slug=prod_slug, status=0).first()
context = {'products':products}
else:
messages.error(request,"no such product found")
return redirect("collection")
else:
messages.error(request,"no such category found")
return redirect("collection")
return render(request,"product_view.html",context)
models.py
class Products(models.Model):
category = models.ForeignKey(Category,on_delete=models.CASCADE)
slug = models.CharField(max_length=150, null=False, blank=False)
product_name = models.CharField(max_length=150, null=False, blank=False)
product_image = models.ImageField( upload_to=get_image,null=True,blank=True)
description = models.TextField(max_length=500,null=False,blank=False)
original_price = models.IntegerField(null=False,blank=False)
selling_price = models.IntegerField(null=False,blank=False)
status = models.BooleanField(default=False,help_text="0=default , 1=Hidden")
trending = models.BooleanField(default=False,help_text="0=default , 1=Trending")
meta_title = models.CharField(max_length=150,null=False,blank=False)
meta_keyword = models.CharField(max_length=150,null=False,blank=False)
meta_description = models.CharField(max_length=400,null=False,blank=False)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.product_name
productview.html
{% block content %}
<h1>{{ products.product_name }} </h1>
{% endblock %}
i just want correct product name for every category i stucked here in morning helping are appreciated thank you all for helping till now
I think you need to loop through your produckts:
{% for product in products %}
<h1>{{ product.product_name }}</h1>
{% endfor %}
view:
def product_view(request,cate_slug,prod_slug):
if (Category.objects.filter(slug=cate_slug, status=0).exists()):
if (Products.objects.filter(slug=prod_slug, status=0).exists()):
products = Products.objects.filter(slug=prod_slug, status=0)
context = {'products':products}
else:
messages.error(request,"no such product found")
return redirect("collection")
else:
messages.error(request,"no such category found")
return redirect("collection")
return render(request,"product_view.html",context)
Note that usually the model name is singular, so it should be class Products(models.Model):

How to get my image gallery into my product.html in Django with Class based view DetailView

I am using model Product and Images. my goal is to display in my singe item page a gallery of item related pictures coming from model "Images"
How can i change the following code to filter by item slug and only show gallery specific to the slug.
Item class
class Item(models.Model):
title = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
image = models.ImageField(, upload_to='catalog/images/', blank=True)
slug = models.SlugField()
Images class
class Images(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
title = models.CharField(blank=True, max_length=50)
image = models.ImageField(upload_to='catalog/images/', blank=True)
Product detail view
class ProductDetailView(DetailView):
model = Item
template_name = 'product.html'
context_object_name = 'item'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['image_gallery'] = Images.objects.all()
return context
product.html page
<div class="row wow fadeIn">
{% for img in image_gallery %}
<div class="col-lg-4 col-md-12 mb-4">
<img src="{{img.image.url}}" class="img-fluid" alt="">
</div>
You can access the instance of image with self.object, then you just need to filter the images you want to pass to the view with the foreign key relationship.
class ProductDetailView(DetailView):
model = Item
template_name = 'product.html'
context_object_name = 'item'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['image_gallery'] = Images.objects.filter(item=self.object)
return context
You need to use .filter() not .get()
image = Images.objects.all()
image.image will give you the image
This is Django 3 you need to convert it to whatever version you are using

How to get a single model object with a relation to the template in Django

I am working on this project that I can add two or more forms in a template. I am able to get the two forms in the template but when I submit the form, I get the objects for the rentalproperty model and not the contract model. I have created two different solution but the two doesn't solve the problem.
The first solution below display both objects multiple times in the detailview but what I want is to display the two model objects just once. The second solution display the rentalproperty object once but the contract objects multiple times. Could someone point me in the right direction? Thanks.
First solution:
views.py
class DetailView(generic.DetailView):
model = RentalProperty
template_name = 'rental/detail.html'
context_object_name = 'property'
def new_rental(request, pk):
if request.method == 'POST':
rental_form = NewRentalPropertyForm(request.POST, request.FILES, prefix = "rentals")
contract_form = NewContractForm(request.POST, prefix = "contracts")
if rental_form.is_valid() and contract_form.is_valid():
print ("all validation passed")
rentalproperty = rental_form.save()
contract_form.cleaned_data["rentalproperty"] = rentalproperty
print(contract_form)
contract = contract_form.save(commit=False)
contract.rentalproperty = rentalproperty
contract = contract_form.save()
return HttpResponseRedirect(reverse("home"))
else:
messages.error(request, "Error")
contract = Contract.objects.get(pk=pk)
else:
rental_form = NewRentalPropertyForm(prefix = "rentals")
contract_form = NewContractForm(prefix = "contracts")
contract = Contract.objects.get(pk=pk)
return render(request, 'rental/new_rental.html', {
#'rentalproperty': rentalproperty,
'rental_form': rental_form,
'contract_form': contract_form,
'contract': contract,
})
detail.html
<h1>This is the detail view</h1>
<h3>From landlord</h3>
<p>Landlord: {{property.created_by}}</p>
<p>address: {{property.landlord.address}}</p>
<h3>From Rental property</h3>
<ul>
{% for rental in property.landlord.rentalpropertys.all %}
<br>
<li>Title: {{property.title}}</li>
<img src="{{property.image.url}}" height="200" alt=""/>
<li>created at: {{property.created_at}}</li>
<li>Type of property: {{property.type_of_property_listing}}</li>
<li>Street: {{property.street}}</li>
<li>Borough: {{property.borough}}</li>
<ul>
{% for contract in rental.contracts.all %}
<li> Insurance required: {{contract.insurance_required}}</li>
<li> other terms: {{contract.other_terms}}</li>
{% endfor %}
</ul>
{% endfor %}
</ul>
Second solution:
views.py
class DetailView(generic.DetailView):
model = RentalProperty
template_name = 'rental/detail.html'
context_object_name = 'property'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['landlord']= Landlord.objects.all()
context['contract']= Contract.objects.filter(rentalproperty__title=title).order_by('created_at')
return context
The post function is the same.
detail.html
<h1>This is the detail view</h1>
<h3>From landlord</h3>
<p>Landlord: {{property.created_by}}</p>
<p>address: {{property.landlord.address}}</p>
<h3>From Rental property</h3>
<ul>
<li>Title: {{property.title}}</li>
<img src="{{property.image.url}}" height="200" alt=""/>
<li>created at: {{property.created_at}}</li>
<li>Type of property: {{property.type_of_property_listing}}</li>
<li>Street: {{property.street}}</li>
<li>Borough: {{property.borough}}</li>
</ul>
<ul>
{% for data in contract %}
<li> insurance : {{data.insurance_required}}</li>
<li> other terms: {{data.other_terms}}</li>
{% endfor %}
</ul>
My model:
class Landlord(models.Model):
user = models.OneToOneField(UserModel, on_delete=models.CASCADE)
address = models.CharField(max_length=255)
def __str__(self):
return str(self.address)
class RentalProperty(models.Model):
landlord = models.ForeignKey("Landlord", related_name='rentalpropertys', on_delete=models.CASCADE)
created_by = models.ForeignKey(UserModel, related_name='rentalpropertys', on_delete=models.CASCADE)
title = models.TextField(unique=True)
created_at = models.DateTimeField(auto_now_add=True)
PROPERTY_LISTING_CHOICES = Choices(
('APARTMENT', _('Apartment')),
('HOLIDAY_HOME', _('Holiday home')),
('SINGLE_FAMILY_HOME', _('Single family home')),
('COMMERCIAL', _('Commercial')),
)
type_of_property_listing = models.CharField(
max_length = 50,
choices = PROPERTY_LISTING_CHOICES,
default = PROPERTY_LISTING_CHOICES.APARTMENT,)
street = models.CharField(max_length=255)
borough = models.CharField(max_length=255)
image = models.ImageField(upload_to='images/', null=True, blank=True,)
def __str__(self):
return str(self.title)
class Contract(models.Model):
rentalproperty = models.ForeignKey("RentalProperty", related_name='contracts', on_delete=models.CASCADE)
insurance_required = models.BooleanField(default=True)
other_terms = models.TextField(blank=True)
def __str__(self):
return str(self.insurance_required)
first solution output:
address: Helsinki
title: build apps
insurance: Yes
- This repeats itself multiple times.
Second solution output:
address: Helsinki
title: build apps
insurance: Yes
- insurance repeats itself multiple times
What I expect:
address: Helsinki
title: build apps
insurance: Yes
Thanks for your time :)
With the help of #Timmy O'Mahony answer, I did {% for contract in property.contracts.all %} in my template using the first solutions and it works. The contracts is the related name to the rental property. Thanks all.

Cannot assign "<QuerySet [<Contact: zak>]>": "Booking.contact" must be a "Contact" instance

I have an issue, I created a form where users can make a reservation (in detail view) of a unique product. So one user can have multiples booking. The form used contain email and username. This form is in my detail.html with include variable.
{% include 'store/list.html' with list_title=name %}
So, When I run my server, go to the reservation page, put an username, email and submit, I have an error instead to redirect to an another page.
models.py:
from django.db import models
class Contact(models.Model):
email = models.EmailField(max_length=100)
name = models.CharField(max_length=200)
def __str__(self):
return self.name
class Marque(models.Model):
name = models.CharField(max_length=200, unique=True)
def __str__(self):
return self.name
class Model(models.Model): #Plusieurs models pour une marque
reference = models.IntegerField(null=True)
created_at = models.DateTimeField(auto_now_add=True)
available = models.BooleanField(default=True)
name = models.CharField(max_length=200)
picture = models.URLField()
marque = models.ForeignKey(Marque, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Booking(models.Model): #plusieurs réservation pour un contact
created_at = models.DateTimeField(auto_now_add=True)
contacted = models.BooleanField(default=False)
marque = models.OneToOneField(Marque, on_delete=models.CASCADE)
model = models.OneToOneField(Model, on_delete=models.CASCADE)
contact = models.ForeignKey(Contact, on_delete=models.CASCADE)
def __str__(self):
return self.contact.name
views.py:
...
def detail(request, model_id):
model = get_object_or_404(Model, pk=model_id)
#marques = [marque.name for marque in model.marque.all()]
#marques_name = " ".join(marques)
if request.method == 'POST':
email = request.POST.get('email')
name = request.POST.get('name')
contact = Contact.objects.filter(email=email)
if not contact.exists():
#If a contact is not registered, create a new one
contact = Contact.objects.create(
email = email,
name = name
)
#If no album matches the id, it means the form must have been tweaked
#So returning a 404 is the best solution
model = get_object_or_404(Model, pk=model_id)
booking = Booking.objects.create(
contact = contact,
model = model
)
#Make sure no one can book the model again
model.available = False
model.save()
context = {
'model_name': model.name
}
return render(request, 'store/merci.html', context)
message = "Le model est {}. Conçu par la marque {}".format(model.name, model.marque)
context = {
"model_name" : model.name,
"model_marque" : model.marque,
"model_id": model.id,
"thumbnail" : model.picture
}
return render(request, 'store/detail.html', context)
search_form.html inside of detail.html:
<div class="container">
<div class="col-lg-12 detail-separator">
<form class="col-md-6 col-md-offset-3 text-center" action="{% url 'store:search' %}" method="get" accept-charset="utf-8">
<div class="form-group">
<label for="searchForm">Chercher un Model</label>
<input id="searchForm" class="form-control" name="query">
</div>
<span class="help-block" id="helpBlock">Trouvez le model de voiture de vos rêves !</span>
</form>
</div>
</div>
You contact query returns a queryset:
contact = Contact.objects.filter(email=email)
You then try to use contact as if it were a single Contact object:
booking = Booking.objects.create(
contact = contact,
model = model
)
This is why Django complains that it got a Queryset instead of a Contact.
You need to select one Contact even if the Queryset only contains one single object. E.g.
contacts = Contact.objects.filter(email=email)
if contacts.exists():
contact = contacts[0]
else:
#If a contact is not registered, create a new one
contact = Contact.objects.create(
email = email,
name = name
)
Or, preferably:
try:
contact = Contact.objects.get(email=email)
except DoesNotExist:
contact = Contact.objects.create(
email = email,
name = name
)

Django form throws select valid choice

I have read every answer for this question but none of them solved my problem completely. I hope someone can help me understand what is wrong in my code. I have a field in my model and I want all the values in that field to be displayed in a dropdown in my form. I was able to achieve that but when I try to save, it says "Select a valid choice. That choice is not one of the available choices." Any help would be greatly appreciated.
models.py
class Item(models.Model):
Product = models.ForeignKey("Product", related_name = "Items")
Name = models.CharField(max_length=1000, blank=True, null=True)
Tag = models.CharField(max_length=1000, blank=True, null=True)
forms.py
class ItemForm(ModelForm):
items = Item.objects.values_list('Name', flat=True)
item_choices = [(item, item) for item in items]
Name = forms.ModelChoiceField(items, widget=forms.Select())
class Meta:
model = Item
fields = ['Name', 'Tag']
views.py
def newknowledgebase(request):
itemformset = modelformset_factory(Item, form=ItemForm, extra=2)
items = itemformset(queryset=Item.objects.none(), prefix='items', )
if request.method=='POST':
items = itemformset(request.POST, queryset=Item.objects.none(), prefix='items', )
item = request.POST.get('items')
for form in items:
form.fields['Name'].choices = [(item, item)]
if items.is_valid():
items.save()
context = {
'items':items,
}
return render(request, 'newknowledgebase.html', context )
html file
<div id="items" class="panel-collapse collapse">
<table class="table table-bordered">
<tbody>
{{ items }}
</tbody>
</table>
</div>
Try this
Name = forms.ChoiceField(item_choices, widget=forms.Select())