I am trying to add simple option to my admin panel. I have category, subcategory and site models. For example:
Computers (category)
- PC (subcategory)
- Notebooks (subcategory)
Health (category)
- Diet (subcategory)
- Fitness (subcategory)
Subcategory is within category. When I am adding site in my admin panel I have list of all categories and subcategories. When I choose category (Computers) in my Subcategory field I have: PC, Notebooks, Diet, Fitness (all subcategories). I don't have any idea how can I filter this only to PC and Notebooks. Any suggestions?
class Category(models.Model):
name = models.CharField(max_length=30, unique=True,
verbose_name='Nazwa kategorii')
slug = models.SlugField()
image = models.ImageField(upload_to='category_images',
verbose_name="Image",
blank=True)
description = models.TextField(default='Description',
verbose_name="Category description")
class Meta:
verbose_name_plural = "Categories"
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
def image_thumb(self):
if self.image:
return '<img src="/media/%s" width="40" height="40" />' % (self.image)
else:
return('')
image_thumb.short_description = 'Thumb'
image_thumb.allow_tags = True
def __str__(self):
return self.name
class SubCategory(models.Model):
category = models.ForeignKey(
'Category',
related_name='subcategory',
on_delete=models.CASCADE,
blank=True,
null=True,
)
name = models.CharField(max_length=30)
class Meta:
verbose_name_plural = "Subcategories"
def __str__(self):
return self.name
class Site(models.Model):
category = models.ForeignKey('Category')
# sub = SubCategory.objects.filter(category=category)
subcategory = models.ForeignKey('SubCategory', related_name='subcategory')
name = models.CharField(max_length=30)
Related
I have a listview where I'm trying to filter out products by category. Some products have a subcategory. When a product has a subcategory I want the listview to display them by subcategory.
Problem is: The listview works perfect for items with a subcategory, but does not work for items who do not have a subcategory. Where am I taking a wrong turn here?
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 = ResizedImageField(upload_to='category/', null=True, blank=True)
category_info = models.TextField(blank=True, null=True)
category_video = models.CharField(max_length=250,blank=True, null=True)
def __str__(self):
if self.sub_category is None:
return self.category_name
else:
return f" {self.sub_category}"
class Meta:
ordering = ['category_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 = ResizedImageField(upload_to='bottles/',null=True, blank=True)
bottle_shop_link = models.CharField(max_length=250, null=True, blank=True)
def __str__(self):
return f"{self.brand}, {self.bottle_name}"
class Meta:
ordering = ['bottle_name']
View:
class BottlesByCategoryView(ListView):
model = Bottle
context_object_name = 'bottles'
#Filter bij subcategory in the category model. If no subcategory exists, load by category_name
def get_queryset(self):
if Bottle.objects.filter(category_name__sub_category=self.kwargs['category']) is None:
return Bottle.objects.filter(category_name__category_name=self.kwargs['category'])
else:
return Bottle.objects.filter(category_name__sub_category=self.kwargs['category'])
def get_context_data(self, **kwargs):
context = super(BottlesByCategoryView, self).get_context_data(**kwargs)
if Bottle.objects.filter(category_name__sub_category=self.kwargs['category']) is None:
context['category_info'] = Category.objects.filter(category_name=self.kwargs['category'])
else:
context['category_info'] = Category.objects.filter(sub_category=self.kwargs['category'])
return context
URLS:
path('BottlesByCategory/<str:category>/',BottlesByCategoryView.as_view(template_name='academy/bottlesByCat_list.html'),name='bottlesByCat_list'),
Can i not use if statements in the get_context_data and get_query_set?
I had a question. I am creating an ecommerce website in django. There, I have categories and subcategories. When I enter to subcategory page, I able to render all products that relate to this subcategory. But, when I wanted to render all product that relate on one parent category, I am having troubles. So, I have some subcategories in one category. In that category page, I want to render all products that relate to one of subcategories of this category. Can you help me please?
models.py
class Category(models.Model):
parent = models.ForeignKey('self', related_name='children', on_delete=models.CASCADE, blank=True, null=True)
title = models.CharField(max_length=255)
slug = models.SlugField(max_length=255)
image = models.ImageField(null=True, blank=True, verbose_name="Изображение")
ordering = models.IntegerField(default=0)
is_featured = models.BooleanField(default=False)
class Meta:
verbose_name_plural = 'Categories'
ordering = ('ordering',)
def __str__(self):
if self.parent is not None:
return f"{self.parent}/{self.title}"
return self.title
#property
def imageURL(self):
try:
url = self.image.url
except:
url = ''
return url
def get_absolute_url(self):
return '/%s/' % (self.slug)
class Product(models.Model):
category = models.ForeignKey(Category, related_name='products', on_delete=models.CASCADE)
parent = models.ForeignKey('self', related_name='variants', on_delete=models.CASCADE, blank=True, null=True)
name = models.CharField(max_length=200, verbose_name="Название продукта")
price = models.IntegerField(verbose_name="Цена")
slug = models.SlugField(max_length=255)
description = models.CharField(max_length=5000,blank=True, verbose_name="Описание:")
image = models.ImageField(null=True, blank=True, verbose_name="Изображение")
novinki = models.BooleanField(default=False, verbose_name="Новинки")
popularnye = models.BooleanField(default=False, verbose_name="Популарные")
def __str__(self):
return self.name
class Meta:
verbose_name = 'Продукты'
verbose_name_plural = "Продукты"
#property
def imageURL(self):
try:
url = self.image.url
except:
url = ''
return url
views.py
def category_detail(request, slug):
data = cartData(request)
cartItems = data['cartItems']
order = data['order']
items = data['items']
categories_for_menu = Category.objects.filter(parent=None)[:3]
categories = Category.objects.filter(parent=None)
category = get_object_or_404(Category, slug=slug)
**products_all = Product.objects.filter(category.parent==category)**
print(products_all)
products = category.products.all()
context = {'items' : items, 'order' : order, 'cartItems' : cartItems, 'products':products, 'category':category, 'categories':categories,'categories_for_menu':categories_for_menu,'products_all':products_all}
return render(request, "store/categories.html", context)
Here I want to save all products that relate the category in products_all. Looking forward to your help!
class Category(models.Model):
# ...
root = models.ForeignKey('self', on_delete=models.CASCADE)
# ...
def save(self, *args, **kwargs):
self.root = self.parent.root if self.parent else self
# I didn't debug it. Maybe it has some bug.
super(Category, self).save(*args, **kwargs)
# query
Product.objects.filter(category__root=(...))
I don't agree this answer:
products = Product.objects.filter(Q(category = category)|Q(category__parent = category))
When your category is more than 2 depth, it will be wrong.
You can do it using Q function:
from django.db.models import Q
category = get_object_or_404(Category, slug=slug)
products = Product.objects.filter(Q(category = category)|Q(category__parent = category))
I have a Product model that has a ManyToMany to Category.
Category has a ForeignKey to itself named parent.
I want to add all parents of selected category to category field.
example for category:
digital appliance->None __ Mobile->digital appliance __ Samsung->Mobile and...
when choose Samsung for category of a product, I want to add Mobile and digital appliance to category
it's my models, the save method doesn't do anything
Class Product:
class Product(models.Model):
STATUS_CHOICES = (
('s', 'show'),
('h', 'hide'),
)
title = models.CharField(max_length=150)
slug = models.SlugField(max_length=170, unique=True)
category = models.ManyToManyField(Category)
thumbnail = models.ImageField(upload_to='images/products', default='images/no-image-available.png')
image_list = ImageSpecField(source='thumbnail', processors=[ResizeToFill(400, 200)], format='JPEG',options={'quality': 75})
image_detail = ImageSpecField(source='thumbnail', processors=[ResizeToFill(1000, 500)], format='JPEG',options={'quality': 100})
description = models.TextField()
inventory = models.IntegerField()
features = models.ManyToManyField(Feature)
status = models.CharField(max_length=1, choices=STATUS_CHOICES, default='s')
def __str__(self):
return self.title
class Meta:
verbose_name = "product"
verbose_name_plural = "products"
def save(self, *args, **kwargs):
for cat in self.category.all():
if cat.parent:
self.category.add(cat.parent)
return super(Product, self).save(*args, **kwargs)
objects = ProductManager()
Category and CategoryManager:
class CategoryManager(models.Manager):
def no_parent(self):
return self.filter(parent=None)
def get_parent(self, parent):
return self.filter(parent=parent)
class Category(models.Model):
parent = models.ForeignKey('self', default=None, null=True, blank=True, on_delete=models.SET_NULL,related_name='children')
title = models.CharField(max_length=40)
slug = models.SlugField()
status = models.BooleanField(default=True)
I think it makes more sense to have Foreign Key to category table rather than m2m relation. You can flatten it in the view whenever needed
I have an order form which displays available items which are attached to a Catalog object. Instead of displaying the available items, it is currently only displaying the field name of available instead of the the items available. Is there a way to target the values in the crispy form? Similar to how it is done in the template like:
{% for i in catalog.annual_products.all %}
Here is my form:
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, ButtonHolder, Submit
from . import models
class OrderListForm(forms.ModelForm):
class Meta:
fields = ('order_lines',)
model = models.Order
def __init__(self, *args, **kwargs):
super(OrderListForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
'order_lines',
ButtonHolder(
Submit('create', 'Create')
)
)
Here is my model:
class Catalog(models.Model):
products = models.CharField(max_length=200)
def __unicode__(self):
return self.products
class Issue(models.Model):
catalog = models.ForeignKey(Catalog, related_name='issue_products')
Volume = models.DecimalField(max_digits=3, decimal_places=1)
def __unicode__(self):
return unicode(self.catalog)
class Annual(models.Model):
catalog = models.ForeignKey(Catalog, related_name='annual_products')
year_id = models.IntegerField(max_length=4)
start_date = models.CharField(max_length=6)
end_date = models.CharField(max_length=6)
def __unicode__(self):
return unicode(self.year_id)
class Annual_Issue(models.Model):
annual_id = models.ForeignKey(Annual, related_name='annual_ids')
issue_id = models.ForeignKey(Issue, related_name='issues')
def __unicode__(self):
return self.annual_id
class Article(models.Model):
catalog = models.ForeignKey(Catalog, related_name='article_products')
title = models.CharField(max_length=200)
abstract = models.TextField(max_length=1000, blank=True)
full_text = models.TextField(blank=True)
proquest_link = models.CharField(max_length=200, blank=True, null=True)
ebsco_link = models.CharField(max_length=200, blank=True, null=True)
def __unicode__(self):
return self.title
class Order(models.Model):
user = models.ForeignKey(User, related_name='who_ordered')
order_lines = models.ForeignKey(Catalog, related_name='items_ordered')
This is what I'm currently returning in the template: (which is just the name of the products field in Catalog)
I have a form for submitting an order. Multiple items have been attached to a catalog object, I'd like to have the form dropdown contain options for all of the items attached to the foreign key, instead of the foreign key Catalog name of Available. I know how to access these in the view, using the related name, is this possible in forms?
Here is my current form:
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, ButtonHolder, Submit
from . import models
class OrderListForm(forms.ModelForm):
class Meta:
fields = ('order_lines',)
model = models.Order
def __init__(self, *args, **kwargs):
super(OrderListForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
'order_lines',
ButtonHolder(
Submit('create', 'Create')
)
)
Here is my model:
class Catalog(models.Model):
products = models.CharField(max_length=200)
def __unicode__(self):
return self.products
class Issue(models.Model):
catalog = models.ForeignKey(Catalog, related_name='issue_products')
Volume = models.DecimalField(max_digits=3, decimal_places=1)
def __unicode__(self):
return unicode(self.catalog)
class Annual(models.Model):
catalog = models.ForeignKey(Catalog, related_name='annual_products')
year_id = models.IntegerField(max_length=4)
start_date = models.CharField(max_length=6)
end_date = models.CharField(max_length=6)
def __unicode__(self):
return unicode(self.year_id)
class Annual_Issue(models.Model):
annual_id = models.ForeignKey(Annual, related_name='annual_ids')
issue_id = models.ForeignKey(Issue, related_name='issues')
def __unicode__(self):
return self.annual_id
class Article(models.Model):
catalog = models.ForeignKey(Catalog, related_name='article_products')
title = models.CharField(max_length=200)
abstract = models.TextField(max_length=1000, blank=True)
full_text = models.TextField(blank=True)
proquest_link = models.CharField(max_length=200, blank=True, null=True)
ebsco_link = models.CharField(max_length=200, blank=True, null=True)
def __unicode__(self):
return self.title
class Order(models.Model):
user = models.ForeignKey(User, related_name='who_ordered')
order_lines = models.ForeignKey(Issue, related_name='items_ordered')
you can access all the Annuals and Articles that are in the same catalog by using:
c = Catalog.objects.get(....
c.article_products_set.all()
c.annual_products_set.all()