Open listView with foreignkey from another listview with Django - django

I am working on a product overview page in Django.
For this I have three models: category, brand, product.
I have created a View with ListView of the category. I loop through them to display them. I then want to open another overview of all brands within that category.
How do I do this?
Here are my models:
class Category(models.Model):
category_name = models.CharField(max_length=200)
sub_category = models.CharField(max_length=200,blank=True,null=True)
category_picture = models.ImageField(upload_to='category/', null=True, blank=True)
def __str__(self):
if self.sub_category is None:
return self.category_name
else:
return f" {self.category_name} {self.sub_category}"
class Meta:
ordering = ['category_name']
class Brand(models.Model):
category = models.ForeignKey('Category', on_delete=models.SET_NULL,null=True,blank=True)
brand_name = models.CharField(max_length=200)
brand_owner = models.CharField(max_length=200)
brand_story = models.TextField()
brand_country = models.CharField(max_length=200)
def __str__(self):
return f"{self.brand_name}"
class Bottle(models.Model):
category_name = models.ForeignKey('Category', on_delete=models.SET_NULL,null=True,blank=True)
brand = models.ForeignKey('Brand', on_delete=models.CASCADE)
bottle_name = models.CharField(max_length=255)
bottle_info = models.TextField()
bottle_tasting_notes = models.TextField()
bottle_barcode = models.IntegerField()
bottle_image = models.ImageField(upload_to='bottles/',null=True)
def __str__(self):
return f"{self.brand.brand_name} {self.bottle_name}"
How do I open a listview of all brands within a certain category from a link of the category listview?

First thing is to create another listview that displays all brands within a specific category. We do this by creating a new get_queryset() method.
views.py
class BrandListView(ListView):
model = Brand
def get_queryset(self):
return Brand.objects.filter(category__category_name=self.kwargs['category'])
Next add a url to your URLS.py so it can be accessed. We're using category_name as part of the url so it's human readable
from .views import BrandListView
urlpatterns = [
path('brands/<str:category>/', PublisherBookList.as_view()), name= "brand_list"
]
Then, as you loop through your categories in your template, create a link to the url
{% for category in categories %}
{{category.category_name}} : See brands in category
{% endfor %}
This will work as long as your categories have fairly simple names. If not, you might want to use the ID in the URL instead, or add a slug field to the model and use that.

Related

Need to Fetch specific foreign key object product from database in Django

Hi everyone I am new at Django and working on e-commerce site. I create a model name category and pass it to model shop by using foreign key. In Category model I have category Sale and i want to fetch all products that have category sale in my landing page and rest of us in shop page. Any one please help me how I do it?
My model.py code is:
class category(models.Model):
name = models.CharField(max_length=200)
def __str__(self):
return self.name
class shop(models.Model):
s_id = models.AutoField(primary_key=True)
s_name = models.CharField(max_length=50)
s_category = models.ForeignKey(category, on_delete= models.CASCADE)
s_artical_no = models.IntegerField(default=0)
View.py:
def index(request):
prod = shop.objects.get(s_category = 4)
params = {'prod': prod}
return render(request, "main/index.html", params )
Use related_name to accomplish this
class shop(models.Model):
s_category = models.ForeignKey(category, on_delete= models.CASCADE, related_name='shop_list')
In views.py
def index(request):
specific_category = category.objects.get(id=4)
prod = category.shop_list.all() #use related_name here
params = {'prod': prod}
return render(request, "main/index.html", params )
Hint: your classes names should follow the UpperCaseCamelCase convention so it should be Shop, Category
s_category is a category instance, you can't pass a category id. First get the category object for "Sale" i.e.
sale_category = category.objects.get(pk=4)
then simply use
prod = sale_category.shop_set.all()
As a side note, try to use PEP-8 compliant class names. The way you name your classes is confusing

django listing by category , with indexview and detailview classes

I am using generic views for list and details, on the index page I am getting my list but not getting my category list, but I am getting a category list on another template.
I want to list the category on the index page, and on click of that category, image go to that list which is filter by that specific category.
I hope you understand my question
. below is the view for brand index and model for category
class BrandsIndexView(generic.ListView):
template_name = "brands/index.html"
context_object_name = "latest_brands_list"
def get_queryset(self):
return Brands.objects.filter(created_on__lte=timezone.now()).order_by('-created_on')[:10]
model for category
class Category(models.Model):
category_name = models.CharField(null=False,max_length=200)
category_slug = models.SlugField(
max_length=200, db_index=True, unique=True)
category_image = models.FileField(upload_to="brand_cat_images",null=True,blank=True,validators=[file_ext])
class Brands(models.Model):
brand_name = models.CharField(max_length=200 , null=False,help_text="Enter Brand Name")
brand_slug = models.SlugField(max_length=200 , unique=True)
brand_logo = models.ImageField(null=False, blank=False, upload_to="brand_logo")
brand_description = models.TextField(max_length=250 ,null=True,blank=True)
brand_category = models.ForeignKey(Category,on_delete=models.CASCADE ,default="None",related_name="category")
You need to create a brands listview which is filtered by category slug, then define a url which accepts the category slug as argument.
You could use the get_queryset method as below:
def get_queryset(self):
cat_slug = self.kwargs['slug']
cat = Category.objects.get(category_slug=cat_slug)
qs = cat.brands_set.order_by('brand_name')
return qs
Example url:
path('categories/<slug>', views.BrandsListView.as_view(), name='brand_category'),
Template example:
<a href="{% url 'brand_category' 'some_category' %}">

How to properly use filter method with foreign key in django details view with multiple models

I have two model one model is being used for storing the blog posts and another model is being used for taking the ratings and comments. Below are two my models
# Models Code
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()
review = models.TextField()
# 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)])
comment = models.TextField()
#Views Code
class ProductListView(ListView):
model = Products
template_name = 'products.html'
context_object_name ='Products'
class ProductDetailView(DetailView):
model = Products
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
context['Rating'] = Rating.objects.filter(self.product_id) # How can i get the comments only for that specific product?
return context
In details-view how should I filter to fetch the comments for that specific product only ?
no need to write separate context for that in ProductDetailView, you can do it as follows in templates
{% for rate in object.rating_set.all %}
{{ rate.comment }}
{% endfor %}

Why can't I see user-added information with Django?

I'm using Django 2.2 and PostgreSQL. I want to display the product information that the user has added to the detail page. I see the information in the 'StoreOtherInfo' model, but I don't see the information in the 'Product' model. How can I do that?
store/models.py
class StoreOtherInfo(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,blank=True, null=True)
phone = models.CharField(max_length=11)
fax = models.CharField(max_length=11)
province = models.CharField(max_length=11)
district = models.CharField(max_length=11)
neighborhood = models.CharField(max_length=11)
def __str__(self):
return self.user.username
products/models.py
class Product(models.Model):
seller = models.ForeignKey(User, on_delete = models.CASCADE)
product_name = models.CharField(max_length = 50)
description = RichTextField()
added_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.seller
store/views.py
from store.models import StoreOtherInfo
from products.models import Product
def neighbor_detail(request,username):
neighbor_detail = get_object_or_404(User,username = username)
neighbor_list = StoreOtherInfo.objects.all()
product_list = Product.objects.all()
return render(request, 'store/neighbor_detail.html', {'neighbor_detail':neighbor_detail, 'neighbor_list':neighbor_list, 'product_list':product_list})
templates/neighbor_detail.html
<strong><p>{{neighbor_detail.first_name}} {{neighbor_detail.last_name}}</p></strong>
<p>{{neighbor_detail.username}}</p>
<p>{{neighbor_detail.email}}</p>
<p>{{neighbor_detail.storeotherinfo.phone}}</p>
<p>{{neighbor_detail.storeotherinfo.fax}}</p>
<p>{{neighbor_detail.storeotherinfo.province}}</p>
<p>{{neighbor_detail.storeotherinfo.district}}</p>
<p>{{neighbor_detail.storeotherinfo.neighborhood}}</p>
<p>{{neighbor_detail.product.product_name}}</p>
<p>{{neighbor_detail.product.description}}</p>
<p>{{neighbor_detail.product.added_date}}</p>
according to your Product model:
seller = models.ForeignKey(User, on_delete = models.CASCADE)
the relation between User model and Product model is one-to-many. This means every User(in this case seller) can have multiple Products.
So when you try to access the Product objects of a User object as you did in you template: <p>{{neighbor_detail.product.product_name}}</p> you end up giving an attribution error because neighbor_detail.product is not a single object of Product class it's a collection.
replace your template code with this and i hope you realize whats happening.
<strong><p>{{neighbor_detail.first_name}} {{neighbor_detail.last_name}}</p></strong>
<p>{{neighbor_detail.username}}</p>
<p>{{neighbor_detail.email}}</p>
<p>{{neighbor_detail.storeotherinfo.phone}}</p>
<p>{{neighbor_detail.storeotherinfo.fax}}</p>
<p>{{neighbor_detail.storeotherinfo.province}}</p>
<p>{{neighbor_detail.storeotherinfo.district}}</p>
<p>{{neighbor_detail.storeotherinfo.neighborhood}}</p>
{% for product in neighbor_detail.product_set.all %}
{{product.product_name}}<br/>
{{product.description}}<br/>
{{product.added_date}}<br/>
{% endfor %}
note that product_set is the default name that django associate with products related to each user.
A User can have multiple Products, so you can't do neighbor_detail.product because product isn't defined on a User. You need to loop through the list of products with {% for product in neighbor_detail.product_set.all %} and then you can display the properties of each product.
Read [this] for more information about one-to-many relationships.

Right way to create urls using inherit class in Django

In Django I have my app where I place information about countries and cities of these countries. This is my model.py file:
class Country(models.Model):
class Meta:
verbose_name_plural = u'Countries'
name = models.CharField(max_length=50)
slug = models.CharField(max_length=255)
description = models.TextField(max_length=10000, blank=True)
def __unicode__(self):
return self.name
class City(models.Model):
class Meta:
verbose_name_plural = u'Cities'
name = models.CharField(u'city', max_length=200)
slug = models.CharField(max_length=255, blank=True)
description = models.TextField(max_length=10000, blank=True)
country = models.ForeignKey('Country', blank=True, null=True)
def __unicode__(self):
return self.name
I have the detail view of my country, in this view there is a list of cities of this country(views.py):
def CountryDetail(request, slug):
country = get_object_or_404(Country, slug=slug)
list_cities = City.objects.filter(country=country)
return render(request, 'country/country.html', {'country':country, 'list_cities':list_cities})
this is my urls.py:
url(r'^(?P<slug>[-_\w]+)/$', views.CountryDetail, name='country'),
I want to create a url of cities which contain a slug of the country and a slug of the city, for example domain.com/spain/barcelona/.
So I created the detail view of the city, and it's looks like this:
def CityDetail(request, cityslug, countryslug):
country = Country.objects.get(slug=countryslug)
country_city = City.objects.get(country=country)
city = get_object_or_404(country_city, slug=cityslug)
return render(request, 'country/city.html', {'country':country, 'city':city})
Here is my urls.py for city detail:
url(r'^(?P<countryslug>[-_\w]+)/(?P<cityslug>[-_\w]+)$', views.CityDetail, name='resort'),
And this is how it looks like in my html file detail of the country that links to the cities:
<h1>{{country.name}}</h1>
<p>{{country.description}}</p>
<h2>Cities</h2>
{% for city in list_cities %}
<a href="/{{country.slug}}/{{city.slug}}">
<p>{{city.name}}</p>
</a>
{% endfor %}
But when I click on the link of the url of the city, I get error.
Object is of type 'City', but must be a Django Model, Manager, or QuerySet
In traceback i see that problem in CityDetail function in views.py file:
resort = get_object_or_404(country_city, slug=cityslug).
Hope you can help me with its problem. Thank You.
Yes, you can't call get_object_or_404 on an actual City object; the things that you can query are models or querysets, not instances. What do you think that call would do?
But actually the underlying problem is before that; your definition of country_city makes no sense. For a start, this is only currently working because you presumably have only one City in the country you're querying. When you have more than one, that line will fail with a MultipleObjectsReturned exception, because get can only return a single object.
You should remove that line altogether, and query the city directly from the country:
country = Country.objects.get(slug=countryslug)
city = get_object_or_404(City, country=country, slug=cityslug)