django 计算查询集中的特定行
django count specific rows in queryset
class Order(models.Model):
name = models.CharField(max_length=100)
# other fields..
user = models.ForeginKey(User)
old = models.BooleanField(default=False)
我想显示特定用户的所有订单,但我想将它们拆分为 "old" 和非 "old"。
所以,目前我在 views.py
:
orders = Order.objects.filter(user=user)
在模板中:
第一个table:
<table>
{% for order in orders %}
{% if not order.old %}
<tr>
<td>... </td>
</tr>
{% endif %}
{% endfor %}
</table>
另一个table:
{% for order in orders %}
{% if order.old %}
<tr>
<td>...</td>
<tr>
{% endif %}
{% endfor %}
这种方式有一些缺点,首先,现在我想统计有多少订单是"old",以便在模板中显示这个数字。我不能,除非我再做一次查询。
可以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 %}
你不能做任何注释,也没有必要做.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
更新
关于您介绍的自定义Manager。我认为你做的不正确我认为你想要的是这个:
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
没有缓存的实例..
关于 {% regroup %} 标签
正如您所说,要使用它,您需要 .order_by('old')
,如果您有其他订单,您仍然可以使用它,只需在 old
之后应用您的订单即可,例如.order_by('old', 'another_field')
。这样您将只使用一个查询,这将节省您对列表的一次迭代(因为 Django 将拆分列表只迭代一次),但模板的可读性会降低。
class Order(models.Model):
name = models.CharField(max_length=100)
# other fields..
user = models.ForeginKey(User)
old = models.BooleanField(default=False)
我想显示特定用户的所有订单,但我想将它们拆分为 "old" 和非 "old"。
所以,目前我在 views.py
:
orders = Order.objects.filter(user=user)
在模板中:
第一个table:
<table>
{% for order in orders %}
{% if not order.old %}
<tr>
<td>... </td>
</tr>
{% endif %}
{% endfor %}
</table>
另一个table:
{% for order in orders %}
{% if order.old %}
<tr>
<td>...</td>
<tr>
{% endif %}
{% endfor %}
这种方式有一些缺点,首先,现在我想统计有多少订单是"old",以便在模板中显示这个数字。我不能,除非我再做一次查询。
可以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 %}
你不能做任何注释,也没有必要做.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
更新
关于您介绍的自定义Manager。我认为你做的不正确我认为你想要的是这个:
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
没有缓存的实例..
关于 {% regroup %} 标签
正如您所说,要使用它,您需要 .order_by('old')
,如果您有其他订单,您仍然可以使用它,只需在 old
之后应用您的订单即可,例如.order_by('old', 'another_field')
。这样您将只使用一个查询,这将节省您对列表的一次迭代(因为 Django 将拆分列表只迭代一次),但模板的可读性会降低。