Home > Software engineering >  Render all products that relate to one of subcategories of one category, in category page
Render all products that relate to one of subcategories of one category, in category page

Time:03-07

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!

CodePudding user response:

class Category(models.Model):
    # ...
    root = models.ForeignKey('self', on_delete=models.CASCADE)
    # ...

    def save(self, *args, **kwargs):  # Use pre_save signal is better
        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.

CodePudding user response:

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))
  • Related