Django外键查询最佳实践

Django外键查询最佳实践,django,django-models,django-templates,django-views,Django,Django Models,Django Templates,Django Views,models.py class Category(models.Model): name = models.CharField(max_length=50) class SubCatergory(models.Model): parent_category = models.ForeignKey(Category) name = models.CharField(max_length=100) class Category(models.Model): nam

models.py

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

class SubCatergory(models.Model):
    parent_category = models.ForeignKey(Category)
    name = models.CharField(max_length=100)
class Category(models.Model):
    name = models.CharField(max_length=50)

    def save(self, *args, **kwargs):
        cache.delete('CATEGORIES_LIST_CACHE_KEY')
        return super(Category, self).save(*args, **kwargs)

class SubCatergory(models.Model):
    parent_category = models.ForeignKey(Category)
    name = models.CharField(max_length=100)

    def save(self, *args, **kwargs):
        cache.delete('CATEGORIES_LIST_CACHE_KEY')
        return super(Category, self).save(*args, **kwargs)
views.py

def all_products(request):
c = Category.objects.all()
s = SubCatergory.objects.all()

return render_to_response('all_products.html',
                          {'c':c, 's':s})
all_products.html

{% for category in c %}
    <h1>{{ category.name }}</h1>
    <ul>
        {% for sub in s  %}
        {% if category.id == sub.parent_category.id %}
            <li>{{ sub.name }}</li>
        {% endif %}
        {% endfor %}
    </ul>
{% endfor %}
{%用于c%中的类别]
{{category.name}
    {s%中的子对象的%s} {%if category.id==sub.parent_category.id%}
  • {{sub.name}}
  • {%endif%} {%endfor%}
{%endfor%}

只是想知道以上是否是外键查询的最佳实践。我在模板级别进行过滤(如果category.id==sub…),我应该将其移到模型或视图级别吗?

为什么不在另一个方向添加引用,以便每个类别都引用子类别列表?然后,您将能够编写两个嵌套循环:一个用于类别的外部循环和一个用于迭代每个类别中的子类别的内部循环。

如果子类别只有一个深度,那么以下代码应该不会有问题:

{% for category in c %}
    <h1>{{ category.name }}</h1>
    <ul>
        {% for sub in category.subcatergory_set.all %}
            <li>{{ sub.name }}</li>
        {% endfor %}
    </ul>
{% endfor %}
{%用于c%中的类别]
{{category.name}
    {category.subcategory_set.all%}
  • {{sub.name}}
  • {%endfor%}
{%endfor%}
但是,有一些优化技巧可以减少查询计数,因为您将对每个循环执行查询。我现在正在想一个

事实上,我开始觉得这是一个有趣的问题:最佳实践

您的方法使用2个查询。我的方法使用django实践,但执行多个查询

为了防止多个查询,您必须在视图中的模板中执行相同的操作,即迭代
子类别
,在python中提取它们的ID,并将每个ID集分组到
类别
上的属性


我不知道这个问题的答案

我认为这里的一个好做法是为这个作业创建一个模板标记。这样可以缓存渲染的模板,并且只在第一次渲染时命中数据库

首先,在应用程序中创建模板标签

templatetags/show_categories_list.py

from django.core.cache import cache

@register.simple_tag
def show_categories_list():
    cached = cache.get('CATEGORIES_LIST_CACHE_KEY', None)
    if cached is None:
        categories = Category.objects.all()
        rendered = render_to_string('all_categories.html', {'categories': categories})
        cache.set('CATEGORIES_LIST_CACHE_KEY', rendered)
        return rendered
    return cached
然后,创建要使用的模板

all_categories.html

{% for category in categories %}
    <h1>{{ category.name }}</h1>
    <ul>
        {% for sub in category.subcategory_set.all %}
            <li>{{ sub.name }}</li>
        {% endfor %}
    </ul>
{% endfor %}
最后像这样使用它:

base.html

{% load show_categories_list %}
{% show_categories_list %}
您还可以向缓存项添加超时,这样就不必重写模型中的save方法,但您必须等待超时,以便可以再次渲染它

一些有用的参考资料:

http://docs.djangoproject.com/en/1.2/topics/cache/#the-低级缓存api

这是正确的想法,但请注意,django会自动为您执行此操作。它会自动为指向模型的每个外键创建一个“反向关系”,即(如果您没有明确更改它)相关模型的名称加上“\u集”。有关更多信息,请参阅以下链接:django确实为您提供了一个API来查询反向关系。然而,使用反向关系检索相关模型仍然会导致额外的SQL查询,如果多次执行(即在循环中),这可能会对性能造成巨大影响。为了避免这种情况,您可能希望对关系进行非规范化,以便在上述情况下,保存对每个类别上的子类别的引用。谢谢,子类别只有一个深度。