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)
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 %}
只是想知道以上是否是外键查询的最佳做法。我在模板级别过滤(如果是category.id == sub ...),我应该将其移到模型或视图级别吗?
答案 0 :(得分:5)
如果只有一个子类别的深度,则以下代码应该不是问题:
{% for category in c %}
<h1>{{ category.name }}</h1>
<ul>
{% for sub in category.subcatergory_set.all %}
<li>{{ sub.name }}</li>
{% endfor %}
</ul>
{% endfor %}
但是有一些优化技巧可以减少查询次数,因为每个循环都会进行查询。我现在想想一个。
实际上,我开始认为这是一个有趣的问题:最佳实践?
您的方法使用2个查询。我的方法是使用django实践,但会进行多次查询。
为了防止多次查询,您基本上必须在视图中执行与模板相同的操作,即迭代SubCatergory
,在python中提取ID并将每个ID集合分组属性Category
。
我不知道这个问题的答案。
答案 1 :(得分:2)
我认为这里的一个好习惯是为这份工作创建一个模板标签。这样,您可以缓存渲染的模板,只在第一次渲染时点击数据库。
首先,在应用内创建模板标记
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 %}
覆盖模型中的save方法,以便删除类别列表缓存条目(强制它在下一个请求时呈现,也可以放在(pre | post)_save信号中):
models.py
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)
最后像这样使用它:
base.html文件
{% load show_categories_list %}
{% show_categories_list %}
您还可以向缓存条目添加超时,因此您不必覆盖模型中的save方法,但是您必须等待超时,以便可以再次渲染。
一些有用的参考资料:
http://docs.djangoproject.com/en/1.2/howto/custom-template-tags/#shortcut-for-simple-tags http://docs.djangoproject.com/en/1.2/topics/cache/#the-low-level-cache-api http://docs.djangoproject.com/en/1.2/topics/signals/
答案 2 :(得分:0)
为什么不在其他方向添加引用,以便每个类别引用SubCategories列表?然后你就可以编写两个嵌套循环:一个用于类别的外循环,在内循环中用于迭代每个类别中的子类别。