class Order(models.Model):
name = models.CharField(max_length=100)
# other fields..
user = models.ForeginKey(User)
old = models.BooleanField(default=False)
我想显示特定用户的所有订单,但我想将它们拆分为“旧”和非旧订单。
所以,目前我在views.py
:
orders = Order.objects.filter(user=user)
在模板中:
第一张表:
<table>
{% for order in orders %}
{% if not order.old %}
<tr>
<td>... </td>
</tr>
{% endif %}
{% endfor %}
</table>
另一张桌子:
{% for order in orders %}
{% if order.old %}
<tr>
<td>...</td>
<tr>
{% endif %}
{% endfor %}
这种方式有一些缺点,首先,现在我想计算有多少订单是“旧的”,在模板中显示这个数字。我不能,除非我做另一个查询。
可以annotate(number_of_old=Count('old'))
吗?或者我还要做另一个查询?
那么什么是最好的?
1.执行两个查询,一个使用old = False,另一个使用old = True,并将两个查询集传递给模板。并在查询集上使用|len
过滤器
2.像这样做一个查询并在python中以某种方式拆分它们?这样不太方便,因为我有类似的结构,我想这样分开。
我应该调用DB .count()吗?
修改
如果我像这样写我的模型:
class Order(models.Model):
name = models.CharField(max_length=100)
# other fields..
user = models.ForeginKey(User)
old = models.BooleanField(default=False)
objects = CustomManager() # Custom manager
class CustomQueryset(models.QuerySet):
def no_old(self):
return self.filter(old=False)
class CustomManager(models.Manager):
def get_queryset(self):
return CustomQuerySet(model=self.model, using=self._db)
此模板代码是否会生成一个或两个查询?
{% if orders.no_old %}
{% for order orders.no_old %}
...
{% endfor %}
{% endif %}
答案 0 :(得分:1)
您无法进行任何注释,因为您已拥有内存中的所有数据,因此无需进行.count()
。所以它真的恰到好处:
orders = Order.objects.filter(user=user)
old_orders = [o for o in orders if o.old]
new_orders = [o for o in orders if not o.old]
#or
old_orders = Order.objects.filter(user=user, old=True)
new_orders = Order.objects.filter(user=user, old=False)
在这个特定场景中,我认为不会有任何性能差异。我个人会选择第二种方法进行两次查询。
有关问题提示的详细阅读:Django Database access optimization
关于您介绍的自定义管理器。我不认为你做得对,我想你想要的是这个:
class CustomQueryset(models.QuerySet):
def no_old(self):
return self.filter(old=False)
class Order(models.Model):
name = models.CharField(max_length=100)
# other fields..
user = models.ForeginKey(User)
old = models.BooleanField(default=False)
#if you already have a manager
#objects = CustomManager.from_queryset(CustomQueryset)()
#if you dont:
objects = CustomQueryset.as_manager()
所以:
orders = Order.objects.filter(user=user)
如果您执行{% if orders.no_old %}
将执行其他查询,因为this is new QuerySet
实例没有缓存..
正如您所提到的,为了使用它,您需要.order_by('old')
,如果您有其他订单,您仍然可以使用它,只需在old
之后应用您的订单,例如.order_by('old', 'another_field')
。通过这种方式,您将只使用一个Query,这将在列表上保存一次迭代(因为Django将拆分列表只迭代一次),但是您在模板中的可读性会降低。