如何在django中显示子类别标题和它的项目在父类别下?

mzsu5hc0  于 2022-12-20  发布在  Go
关注(0)|答案(2)|浏览(150)

我想在Django的父类别下显示子类别标题和它的项目,例如,我有1个父类别,然后它有2个子猫,然后他们每个人有3个子猫。在每个子类别中有10个项目。

Parental category1
item1
item2

subcategory 1
item3
item4
item5

     child category 1 from subcategory1
     item6
     item7

subcategory 2
item8
item9
item10

下面是我的代码:
Models.py

from django.conf import settings
from django.db import models
from django.urls import reverse
from django.utils.text import slugify
from mptt.models import MPTTModel, TreeForeignKey

class Category(MPTTModel):
  name = models.CharField(max_length=settings.BLOG_TITLE_MAX_LENGTH, unique=True)
  parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
  slug = models.SlugField(max_length=settings.BLOG_TITLE_MAX_LENGTH, null=True, blank=True)
  description = models.TextField(null=True, blank=True)
  
  class MPTTMeta:
    order_insertion_by = ['name']

  class Meta:
    verbose_name_plural = 'Categories'

  def __str__(self):
    return self.name

  def save(self, *args, **kwargs):
    value = self.name
    if not self.slug:
      self.slug = slugify(value, allow_unicode=True)
    super().save(*args, **kwargs)

  def get_absolute_url(self):
    return reverse('items-by-category', args=[str(self.slug)])

class Item(models.Model):
    title = models.CharField(max_length=settings.BLOG_TITLE_MAX_LENGTH)
    category = TreeForeignKey('Category', on_delete=models.CASCADE, null=True, blank=True)
    description = models.TextField(null=True, blank=True)    
    slug = models.SlugField(
      max_length=settings.BLOG_TITLE_MAX_LENGTH,
    )

    def __str__(self):
      return self.title

    def get_absolute_url(self):
      kwargs = {
        'slug': self.slug
      }
      return reverse('item-detail', kwargs=kwargs)

    def save(self, *args, **kwargs):
      if not self.slug:
        value = self.title
        self.slug = slugify(value, allow_unicode=True)
      super().save(*args, **kwargs)

Views.py

from django.views import generic
from .models import Item, Category

class CategoryListView(generic.ListView):
    model = Category
    template_name = "blog/category_list.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['items'] = Item.objects.all()
        return context

class ItemsByCategoryView(generic.ListView):
    ordering = 'id'
    paginate_by = 10
    template_name = 'blog/items_by_category.html'

    def get_queryset(self):
        # https://docs.djangoproject.com/en/3.1/topics/class-based-views/generic-display/#dynamic-filtering
        # the following category will also be added to the context data
        self.category = Category.objects.get(slug=self.kwargs['slug'])
        queryset = Item.objects.filter(category=self.category)
         # need to set ordering to get consistent pagination results
        queryset = queryset.order_by(self.ordering)
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['category'] = self.category
        return context

class ItemDetailView(generic.DetailView):
    model = Item
    template_name = 'blog/item_detail.html'

items_by_category.html

{% extends "blog/base.html" %}

{% block title %}{{category.name}} list of items{% endblock %}

{% block content %}
<main>
    <section>
    <div class="container">
        <h1>{{category}} items</h1>
        <p>{{category.description}}.</p>
    </div>
    </section>
    {% include "blog/_breadcrumbs.html" with ancestors=category.get_ancestors object=category%}
    <div>
    {% for item in object_list%}
    <div>
        <a href="{{item.get_absolute_url}}">
        <p>{{item}}</p>
        </a>
    </div>
    {% endfor %}

    {% if is_paginated %}
    <div class="pagination">
        <span class="step-links">
        {% if page_obj.has_previous %}
        <a href="?page=1">&laquo; first</a>
        <a href="?page={{ page_obj.previous_page_number }}">previous</a>
        {% endif %}

        <span class="current">
            Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
        </span>

        {% if page_obj.has_next %}
        <a href="?page={{ page_obj.next_page_number }}">next</a>
        <a href="?page={{ page_obj.paginator.num_pages }}">last &raquo;</a>
        {% endif %}
        </span>
    </div>
    {% endif %}

    </div>
</main>
{% endblock %}

谢谢
我尝试显示家长类别,但未显示任何内容

fdx2calv

fdx2calv1#

在这里我试图解决这样一个问题...
here克隆Github存储库

浏览器输出

xxb16uws

xxb16uws2#

看看docs,您可能需要执行以下几个步骤:
首先,您的查询集只查找一个类别,您还需要该类别的子类别。MPTT模型有一些额外的模型函数来帮助您遍历树。在本例中,get_descendants是相关的,因为我们可以在集合中保留原始示例。(注:如果你想从页面的树中得到 * 所有的东西 *,你可以使用get_family())

self.category = Category.objects.get(slug=self.kwargs['slug'])
    #using category instance, create recordset with cat and its children
    self.category_and_children = self.category.get_descendants(include_self=True)

现在我们有一个完整的查询集来查找其中的项目,因此我们需要调整查询集

queryset = Item.objects.filter(category__in=self.category_and_children).order_by('category')

所以这将提供所有按类别分组的项。你可以使用这个方法轻松地得到一个平面列表,但是我们需要缩进。不幸的是,因为我们抓取的是项而不是类别,所以我们不能使用MPTT递归模板循环遍历类别并对treeForeignKey子项进行分类-为此,我们必须创建一个类别的查询集,并使用prefetch_related来获取项,例如:

queryset = self.category_and_children.prefetch_related('item_set')

现在,我们可以在模板中使用类似以下内容:

{% load mptt_tags %}
<ul>
    {% recursetree object.list %}
        <li>
            {{ node.name }}
            {% for item in node.item_set.all %}
                  <div>
                       <a href="{{item.get_absolute_url}}">
                       <p>{{item}}</p>
                       </a>
                  </div>                
            {% endfor %}
            {% if not node.is_leaf_node %}
                <ul class="children">
                    {{ children }}
                </ul>
            {% endif %}
        </li>
    {% endrecursetree %}
</ul>

相关问题