Django:通过外键

时间:2016-10-06 02:50:06

标签: python django django-templates

我有这个问题:我有两个型号,产品和类别,类别是在灯具中定义的(它们不会改变),我需要在一个模板中显示所有类别,作为一个网格。模型相当简单,重要的是Products有一个指向Category模型的外键,另一个指向User模型(owner)。

我必须在每个类别块中显示所有产品(CSS无关紧要,我只需要能够提出它们)但是我到目前为止所获得的解决方案是

查看

def index(request):
    user_products = []
    if request.user.is_authenticated():
        user_products = Product.objects.filter(owner=request.user)
    categories = Category.objects.all()
    return render(request, 'index.html', {'user_products': user_products, 'categories': categories})

模板

<!-- This goes for each category, 12 in total -->
<div>
    <h3>Category (name hardcoded)</h3>
    {% for category in categories %}
        {% if category.pk == 3 %}
            <ul class="product_list">
            {% for product in category.product_set.all %}
                {% if product.owner == request.user %}
                <li>
                    <div class="product">
                        <h2 class="title">{{ product.title }} </h2>
                        <p class="text">{{ product.text }}</p>
                    </div>
                </li>
                {% endif %}
            {% empty %}
            {% endfor %}
            </ul>
        {% endif %}
    {% endfor %}
</div>

我希望在上下文中发送类似:

user_products = {<category.pk>: [list of Product objects in category]}

因此,每次 过滤 request.user 时,我都可以访问每个类别的产品列表,而无需定义 for 循环。你能想到一个更好的方法吗?我不得不对每个类别进行硬编码,因为它们具有给定的顺序,但如果您知道如何在保持该顺序的同时动态显示它们,那将非常棒。谢谢!

1 个答案:

答案 0 :(得分:2)

有更好的方法可以做到这一点。使用Prefetch对象。预取将仅包含每个类别的过滤数据。

from django.db.models.query import Prefetch

def index(request):
    user_products = []
    if request.user.is_authenticated():
        user_products = Product.objects.filter(owner=request.user)
    else:
        # answering comment
        user_products = Product.objects.none()
    prefetch = Prefetch('product_set', queryset=user_products)
    categories = Category.objects.all().prefetch_related(prefetch)

    return render(request, 'index.html', {'categories': categories})

然后你可以在模板中执行此操作

<!-- You need to do this only once. No need to copy this for each category -->
<div>
    {% for category in categories %}
    <h3>Category {{ category.name }}</h3>
        <ul class="product_list">
        {% for product in category.product_set.all %}
            <li>
                <div class="product">
                    <h2 class="title">{{ product.title }} </h2>
                    <p class="text">{{ product.text }}</p>
                </div>
            </li>
        {% endfor %}
        </ul>
    {% endfor %}
</div>