Как показать категории товаров на главной странице?

Я хочу показать все мои продукты ряд за рядом на главной странице по категориям. Предположим, перед началом нового ряда будет заголовок (название категории), затем будут показаны все продукты в соответствии с категорией продукта, а затем снова будет начинаться новый ряд с заголовком в соответствии с категорией. Как я могу это сделать? Я применил 3/4 методов, но ничего не получилось. Ниже я показал один из методов. Он не работает должным образом. Пожалуйста, помогите мне.

views.py:

def home(request):
    all_products = Products.objects.all()

    context ={
        "all_products":all_products,
    }
    return render(request,'home.html', context)

model.py:

class Category(models.Model):
    title = models.CharField(blank=True, null=True, max_length = 100)

    def __str__(self):
        return str(self.title)

class Products(models.Model):
    product_image = models.ImageField(blank=True, null=True, upload_to = "1_products_img")
    product_title = models.CharField(blank=True, null=True, max_length = 250)
    product_price = models.IntegerField(blank=True, null=True)
    offer_price = models.IntegerField(blank=True, null=True)
    created_date = models.DateTimeField(blank=True, null=True, auto_now=True)


    product_category = models.ForeignKey(Category, related_name="categoty_related_name", on_delete=models.CASCADE, blank=True, null=True)

context_processors.py:

from .models import Category

def categories(request):
    return {"categories":Category.objects.all()}

Шаблон:

{% for products in all_products %}
<h4 class="text-start montserrat_alternates_font ">{{products.product_category}}</h4>
<hr>

<!--- product card --->

<div class="col mb-5">
    <div class="card h-100">

        <!-- Sale badge-->
        {% if products.offer_price != None %}
        <div class="badge bg-dark text-white position-absolute" style="top: 0.5rem; right: 0.5rem">
            SALE
        </div>
        {% endif %}

        <!-- Product image-->
        <img class="card-img-top" style="height:150px;" src="{{products.product_image.url}}" alt="..." />
        <!-- Product details-->
        <div class="card-body ">
            <div class="text-center">
                <!-- Product name-->
                <h5 class="fw-bolder product_title" style="">{{products.product_title}}</h5>

            </div>
        </div>

    </div>
</div>
{% endfor %}

Вам нужно немного изменить свое мышление :) Самый простой подход - думать от больших "предметов" (как ваш Category) к меньшим (Product).

Прежде всего, используйте единственное число для именования моделей, например Product (без 's', так же как вы сделали с Category), потому что в противном случае вы получите путаницу в настройках. Кроме того, не называйте поля именем модели, если это действительно необходимо, product_category должно быть просто category и так далее.

Во-вторых, откройте большой цикл for с Category, который вы передаете как контекст классического представления:

def home(request):
    categories = Category.objects.all()

    context = {
        "categories": categories,
    }
    return render(request,'home.html', context)

Затем посмотрите на ваше поле ForeignKey в Product:

class Products(models.Model):
    ...
    category = models.ForeignKey(Category, related_name="products", ...)

Главное - правильно использовать related name. В своем шаблоне попробуйте использовать логику, подобную этой (плавное использование related_name в обратных отношениях):

{% for category in categories %}
    {{ category.title }}

    {% for product in category.products.all %}
        {{ product.title }} - {{ product.price }}
    {% endfor %}
{% endfor %}

Если вы не установите related_name, то он будет доступен с помощью <model_name>_set.all(), в данном случае product_set.all() (в шаблонах без скобок, конечно). В любом случае, это будет работать как шарм :)

Вернуться на верх