为相关对象编写按请求过滤

Writing on-request filtering for related objects

假设我们有以下模型

class Category(models.Model):
    name = models.CharField(max_length=254)

class Item(models.Model):
    category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="items")
    name = models.CharField(max_length=254)
    state = models.ForeignKey(State, on_delete=models.CASCADE)

类别及其项目如下所示

def view(request):
   categories = Category.objects.all()
   pass

{% for category in categories %}
    {{ category.name }}
    {% for item in category.items.all %}
        {{ item.name }}
    {% endfor %}
{% endfor %}
 

在这个结构中,我想为列出的'items'编写按需过滤。

def view(request):
    ...
    queryset = ???
    state = request.GET.get('state')
    if state:
        queryset = queryset.filter(state__name=state)

问题是定义 'queryset'。因为,项目被列为类别的相关对象。

能不能做好?或者我需要更改设计吗?

你可以看看我的设计更清楚。

Low fidelity design

您在“类别的项目对象”字段中的 related_name 应命名为“项目”。然后 category.items.all 将为您提供该类别中的项目列表。查看 documentation.

中的示例
class Tag(models.Model):
    article = models.ForeignKey(
        Article,
        on_delete=models.CASCADE,
        related_name="tags",
    )
    name = models.CharField(max_length=255)

要根据类别过滤项目,您可以在请求中传递类别的 PK,并根据这些特定类别进行过滤。

views.py
def your_view(request):
    ...
    list_of_your_category_ids = [1,4] #get them as a list from frontend
    list_of_your_state_names = [1,2] 
    queryset =  Item.objects.filter(
                category__in=list_of_your_category_ids,
                state__code__in=list_of_your_category_names
            )

这将为您提供所需的查询集。现在你需要做的就是用它们的类别重新组合这个查询集。

Django 提供了一个 regroup 模板标签来做这件事。

{% regroup queryset by category as categories_list %}
<ul>
    {% for category in categories_list %}
    <li>
        {{category.grouper}}
        <ul>            
            {% for item in category.list %}
            <li>
                {{item}}: state - {{item.state.code}}
            </li>
            {% endfor %}
        </ul>
    </li>
    {% endfor %} 
</ul>
https://i.stack.imgur.com/TbTpz.png