I am using Class Based views and want to display data on a webpage using ListView. Am using for loop to display many objects data. In my models, the items have a category field which is ForeignKey where the category is either Bags, Tshirts or Shoes. I want to display items whose Category is Shoes only. I have tried using the if condition which isnt working with the ForeignKey field. How do I filter the Category field to display Bags only?
models.py
from django.db import models
# Create your models here.
class Category(models.Model):
title = models.CharField(max_length=30)
createdtime = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Meta:
verbose_name_plural = "Categories"
class Product(models.Model):
mainimage = models.ImageField(upload_to='product')
name = models.CharField(max_length=264)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='category')
previewtext = models.TextField(max_length=200, verbose_name='Preview Text')
detailstext = models.TextField(max_length=1000, verbose_name='Description')
price = models.FloatField()
oldprice = models.FloatField(default=0.00)
createddate = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Meta:
ordering = ['-createddate',]
views.py
from django.shortcuts import render
from django.views.generic import ListView, DetailView
from shopapp.models import Product
# Create your views here.
class Home(ListView):
model = Product
template_name = 'shopapp/home.html'
html file
<div class="container my-5">
<h2 class="my-5">Handbags</h2>
<div class="row">
{% for product in object_list %}
{% if product.category == 'Bags' %}
<div class="col-md-6 col-sm-12 col-lg-3">
<figure class="card card-product">
<div class="img-wrap">
<img src="/media/{{ product.mainimage }}" style="width:100%; height:300px;">
</div>
<figcaption class="info-wrap">
<h6 class="title">{{ product.name }}</h6>
<div class="action-wrap">
<div class="price-wrap h5">
<span class="price-new">${{ product.price|floatformat:2 }}</span>
<span class="price-old"><strike>${{ product.oldprice|floatformat:2 }}</strike></span>
</div>
</div>
</figcaption>
</figure>
</div>
{% endif %}
{% endfor %}
</div>
</div>
In your code use product.category.title like so:
...
{% if product.category.title == 'Bags' %}
...
You are comparing a Category object with the string Bags.
//edit
I also recommend filtering the data in the view, if you only need that data in the view. There is no need to fetch all the products from your database and send them to the view, just to render a portion of it.
Related
I have a few categories and I would like to list the products per category in the format below (categories is an FK to products):
Category 1
bunch of products
....
Category N
bunch of products
I have tried many ways but so far I only get the categories but not the products to show in my HTML.
I m new in django cant find the solution
in models.py:
from django.utils import timezone
from distutils.command.upload import upload
from email.policy import default
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Main_Category(models.Model):
name=models.CharField(max_length=100)
def __str__(self):
return self.name
class Sub_Category(models.Model):
main_category=models.ForeignKey(Main_Category,on_delete=models.CASCADE)
name=models.CharField(max_length=100)
def __str__(self):
return self.name
class Product(models.Model):
Status=('publish','publish'),('draft','draft')
product_id=models.AutoField
name=models.CharField(max_length=50)
category=models.ForeignKey(Main_Category,on_delete=models.CASCADE,null=True,default="")
sub_category=models.ForeignKey(Sub_Category,on_delete=models.CASCADE,null=True,default="")
price=models.IntegerField(default=0)
des=models.CharField(max_length=2000)
status=models.CharField(choices=Status,max_length=200)
delivery=models.IntegerField(null=True)
date=models.DateTimeField()
image=models.ImageField(upload_to="shop/images",default="Status")
slug=models.CharField(max_length=150)
def __str__(self):
return self.name
#property
def get_products(self):
return Product.objects.filter(categories__title=self.name)
class Orders(models.Model):
user=models.ForeignKey(User,on_delete=models.CASCADE)
amount=models.CharField(max_length=55)
Order_id=models.AutoField(primary_key=True)
name=models.CharField(max_length=55)
email=models.CharField(max_length=30)
address=models.CharField(max_length=200)
phone=models.CharField(max_length=15)
city=models.CharField(max_length=20)
state=models.CharField(max_length=20)
zip_code=models.CharField(max_length=10)
date=models.DateTimeField(default=timezone.now)
def __str__(self):
return self.user.username
class OrderItem(models.Model):
order=models.ForeignKey(Orders,on_delete=models.CASCADE)
product=models.CharField(max_length=200)
image=models.ImageField(upload_to="shop/images/cust_image")
quantity=models.CharField(max_length=20)
price=models.CharField(max_length=15)
total=models.CharField(max_length=1000)
def __str__(self):
return self.order.user.username
Views.py
from django.shortcuts import redirect, render
from .models import Main_Category, Product,Sub_Category,Orders,OrderItem
from django.core.paginator import Paginator
from django.contrib.auth.decorators import login_required
from cart.cart import Cart
from django.contrib.auth.models import User,auth
from django.contrib import messages
# Create your views here.
def index(request):
allproduct=Product.objects.all() ###filter(publish)which product you want to display in homepage
main_category=Main_Category.objects.all().order_by('-id')
categoryID = request.GET.get('main_category')
if categoryID:
allproduct=Product.objects.filter(sub_category=categoryID)
else:
allproduct=Product.objects.all()
paginator=Paginator(allproduct,5)
page_number=request.GET.get('page')
pagedata=paginator.get_page(page_number)
totalpage=pagedata.paginator.num_pages
print(allproduct)
context= {'allproduct':allproduct,
'main_category':main_category,
'allproduct':pagedata,
'totalpagelist':[n+1 for n in range(totalpage)]
}
return render (request,"shop/index.html",context)
in html:
{% for product in allproduct %}
<div class="col-6 col-sm-6 col-md-6 col-lg-3">
<div class="card">
<img class="card-img-top " src='/media/{{product.image}}' alt="Card image cap">
<div class="card-body">
<h4 class="card-title">{{product.name}}</h4>
<p class="card-text">{{product.des |truncatechars:50}}</p>
<p class="card-text">{{product.time}}</p>
<div class="row">
<div class="col">
<a class=" btn btn-primary" href="{% url 'cart_add' product.id %}">Add to cart</a>
<a class="btn btn-danger ">{{product.price}} Tk</a>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
To do it, I think you should change the ForeignKey to a OnetoOneField in the Product class. Then you can access it from the Category and Sub_Category class.
But to do it with the current setup, you would have to go through each category and filter the products by it.
So…
categories = Category.objects.all()
list = []
for cat in categories:
products = Products.objects.filter_by(category=cat)
dics = {"name":cat, "products":products}
list.append(dics)
then return the variable list to the html template
Models.py
class Listing(models.Model):
title = models.CharField(max_length=64, default="")
bid = models.ForeignKey(Bid, on_delete=models.CASCADE, related_name="listing", default=None,)
description = models.TextField(default="")
image_url = models.CharField(max_length=200, default="")
date = models.DateTimeField(default=timezone.now)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="listings", default="")
is_closed = models.BooleanField(default=False, blank=True, null=True)
watchlist = models.ManyToManyField(User, blank=True, related_name="watching")
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name="listing", null=False, blank=True, default="")
def __str__(self):
return self.title
#the category class
class Category(models.Model):
category = models.CharField(max_length=64)
def __str__(self):
return self.category
Views.py
*This is where I think the problem is because i'm not very familiar with the methods, if I use category = request.POST["category], I get an error saying multivalue dict..., I'm just stuck here if you have a clue how i can modify this method to show the items in a category *
def categories(request):
category = request.POST("category")
listings = category.listings.all()
return render(request, "auctions/categories.html", { "listings":listings })
```
categories.html
{% extends "auctions/layout.html" %}
{% block body %}
<h2>Categories</h2>
<form action="{% url 'categories' %}" method="post">
<div class="form-group">
<label for="categories">Category</label>
<select class="form-control" name="categories" id="categories">
{% for category in categories %}
<option>{{category}}</option>
{% endfor %}
</select>
</div>
</form>
{% for listing in listings %}
{% if not listing.is_closed or user == listing.bid.user %}
<p></p>
<div class="card" style="width: 60rem;">
<img class="card-img-top" style="width: 20rem;" src="{{listing.image_url}}" alt="Card image cap">
<div class="card-body">
<h5 class="card-title">{{listing.title}}</h5>
<p class="card-text">{{listing.description}}</p>
<p>Bid: {{listing.bid}}</p>
<p>Created {{listing.date}}</p>
</div>
<div class="card-body">
More
</div>
</div>
<p></p>
{% endif %}
{% endfor %}
{% endblock %}
You're not receiving anything as POST, so there wouldn't be any value there.
Your lines of:
category = request.POST("category")
listings = category.listings.all()
make no sense because:
in category = request.POST("category") you are first trying to store something into category from the POST which #1 doesn't exist and #2 would be a string even if it did.
Let's just assume there is something in the POST with the key "category", you then try to receive all the listings using the category variable. Since you didn't define category variable properly, there's no way this would work anyways. Assuming for one second that you had, the Category object you defined in your models has no listings field or relation.
The correct way to do this would be:
category = Category.objects.get(category="Name Of Category You Set")
listings = Listing.objects.filter(category=category)
But before you go ahead and do anything, I really recommend you learn more about Objects and classes because seeing your above attempts you seem to lack knowledge of not only those but of variables swell.
I have two models one is club details and the other is player structure. so my plan is to based on the club iteration which has values like'test', 'odi', 'listA' i need to represent its respective player structure in my Django template.
models.py
class Clubstate(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class PlayerStructure(models.Model):
clubstate = models.ForeignKey('Clubstate', on_delete=models.CASCADE, related_name='clubstate')
country = models.ForeignKey('TeamStructure', on_delete=models.CASCADE, null=True, related_name='identifier1')
firstname = models.CharField(max_length=255)
lastname = models.CharField(max_length=255)
imageUri = models.ImageField(upload_to='images/', verbose_name='image')
JerseyNumber = models.IntegerField()
def __str__(self):
return self.firstname + self.lastname
In views.py I'm using DetailView to represent the data.
class PlayerStatistics(DetailView):
context_object_name = 'Clubstate_details'
model = models.Clubstate
template_name = 'CricketDetails/playerstatistics_details.html'
Template html
<div class="jumbotron">
<div class="container">
<div class="row">
{% for club in Clubstate_details %}
<h1>{{club.name</h1>
{% endfor %}
</div>
</div>
</div>
My thought, logic is like
{% for club in clubs %}
{{club.name}}
{{club.player_structure.firstname}}
{{club.player_structure.lastname}}
{% endfor%}
So that for indivdual club i get its respective player structure.
I get TypeError: 'Clubstate' object is not iterable error.
Hope that makes sense...
Detail view won't give a list of items, instead it gives a single view only so change the DetailView to ListView and iterate through the output
class PlayerStatistics(ListView):
context_object_name = 'Clubstate_details'
model = models.Clubstate
template_name = 'CricketDetails/playerstatistics_details.html'
if you want detail view can get it by
{{ Clubstate_details.name }}
with DetailView
FK instance can be accessed by
{% for obj in Clubstate_details.playerstructure_set.all %}
{{ obj.firstname }}
{% endfor %}
I am beginner for django. I had already tried several times to solve this problem. Please consider my mistake if question is not asked properly.
I don't know where I am going wrong.
models.py
class Participant(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
first_name = models.CharField(max_length=255,blank=True,null=True)
last_name = models.CharField(max_length=255,blank=True,null=True)
class Assessment(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(blank=True)
created = models.DateTimeField(auto_now_add=True,editable=False)
modified = models.DateTimeField(auto_now=True)
class Seminar(models.Model):
topic = models.CharField(max_length=255)
date = models.DateField(null=True,blank=True)
time = models.TimeField(null=True,blank=True)
assessment = models.ManyToManyField(Assessment,blank=True,through='SeminarParticipant')
participant = models.ManyToManyField(Participant,blank=True,through='SeminarParticipant')
created = models.DateTimeField(auto_now_add=True,editable=False)
modified = models.DateTimeField(auto_now=True)
class SeminarParticipant(models.Model):
assessment = models.ForeignKey(Assessment,blank=True,on_delete=models.CASCADE)
seminar = models.ForeignKey(Seminar,blank=True,on_delete=models.CASCADE)
participant = models.ForeignKey(Participant,blank=True,on_delete=models.CASCADE)
request_time = models.PositiveIntegerField(default=0,validators=[MinValueValidator(0),])
is_survey_completed = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True,editable=False)
modified = models.DateTimeField(auto_now=True)
Already try to figure this out too:
many-to-many select_related in django class-based list view
How to Access Many to many field in class based views in Django?
views.py
class SeminarListView(ListView):
template_name = 'show_seminar.html'
model = Seminar
context_object_name = 'seminar'
def get_queryset(self):
queryset = Seminar.objects.prefetch_related('assessment_set').filter(participant__user=self.request.user).order_by('created')
return queryset
show_seminar.html
<div class="row mt-5">
{% for obj in seminar %}
<div class="col-sm-6">
<div class="card mt-2">
<div class="card-header">
<h4 class="text-center">{{obj.topic}}</h4>
</div>
<div class="card-body">
<button>Go For Seminar</button>
</div>
<div class="card-footer">
</div>
</div>
</div>
{% endfor %}
</div>
<div>
{% for obj in seminar.seminarparticipant_set.all %}
<p>{{obj}}</p>
{% endfor %}
</div>
I want to display assessment too on html page. But only getting seminar related data. In obj.seminar.seminarparticipant_set.all. I am getting blank.
Please help!!
I'm struggling finding docs or examples how to get data from a cousin related model.
So if the models look like this:
class Part(models.Model):
name = models.CharField(max_length=550)
class Quantity(models.Model):
quantity = models.DecimalField(max_digits=10, decimal_places=2)
part = models.ForeignKey('Part', related_name='quantity_part')
stockarea = models.ForeignKey('StockArea', related_name='quantity_stockarea')
class Stock(models.Model):
name = models.CharField(max_length=550)
class StockArea(models.Model):
area = models.CharField(max_length=550)
stock = models.ManyToManyField(Stock, related_name='stockarea_stock')
def __str__(self):
return self.area
And in the view I get the part like this:
def details(request, part_id):
part = get_object_or_404(Part, pk=part_id)
context = {
'part': part,
}
return render(request, 'part/details.html', context)
Finally template trying to display the data:
{% for a in part.quantity_part.all %}
{{ a.quantity }} pcs
Find part in area: {{ a.stockarea }}
in stock: {{ part.stockarea.stock.name }}
{% endfor %}
You see how I try to get the name of the stock. I can't figure out how to be able to get hold of the name of the stock. I have a path there from the part.
Part have a related_name to the Quantity model called quantity_park. And in the model Quantity I have a relation to model StockArea. And from there I have a relation to model Stock.
Guidance is much appreciated =)
Maybe I'm totally doing this backwards. Maybe I'm defining the models wrong to begin with. I'm used to MySQL, so this is very new to me.
The data model for this is better done as:
from django.db import models
class Unit(models.Model):
name = models.CharField(max_length=32)
description = models.TextField()
abbrev = models.CharField(max_length=7)
class Warehouse(models.Model):
name = models.CharField(max_length=100)
address = models.TextField()
class StockArea(models.Model):
warehouse = models.ForeignKey(Warehouse)
# Adjust type of these identifiers as necessary
aisle = models.PositiveIntegerField()
shelf = models.PositiveIntegerField()
class Part(models.Model):
name = models.CharField(max_length=550)
description = models.TextField()
class Stock(models.Model):
part = models.ForeignKey(Part, related_name='stock') # Adds a 'stock' attribute to 'Part'
quantity = models.PositiveIntegerField()
unit = models.ForeignKey(Unit)
location = models.ForeignKey(StockArea)
View code:
from django.views import generic
from .models import Part
class PartView(generic.DetailView):
# Pre-fetch related objects. This also illustrates the joins
queryset = Part.objects.prefetch_related(
'stock', 'stock__location', 'stock__location__warehouse'
)
template_name = 'yourapp/part/detail.html'
Template code yourapp/part/detail.html:
{% extends "base.html" %}
{% block content %}
<div class="container-fluid">
<div class="row">
<div class="col-xs-12 col-md-8 col-md-offset-2">
<h1 class="title">{{ part.name }}</h1>
<p>{{ part.description }}</p>
<h2>Stock information</h2>
<div class="container-fluid">
{% for stock in part.stock.all %}
<div class="row">
<div class="col-xs-3">
Aisle {{ stock.location.aisle }}, shelf {{ stock.location.shelf }}
</div>
<div class="col-xs-3 label">
Warehouse:
</div>
<div class="col-xs-6">
{{ stock.location.warehouse.name }}
<address>
{{ stock.location.warehouse.address }}
</address>
</div>
</div>
<div class="row">
<div class="col-xs-3 label">
Available:
</div>
<div class="col-xs-8 numeric">
{{ stock.quantity }}
</div>
<div class="col-xs-1 unit">
{{ stock.unit.abbrev }} <sup><i class="fa fa-icon" title="{{ stock.unit.name }}"></i></sup>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
{% endblock content %}
Edit:
Fixed model relation for stock/part.
Adjusted data model conforming specs in comments
Added view code to illustrate join and point to prefetch_related.
Adjusted template to match changes