【发布时间】:2021-01-23 07:06:23
【问题描述】:
当我想定义我的业务逻辑时,我正在努力寻找正确的方法来执行此操作,因为我经常需要一个属性和一个自定义查询集来获取相同的信息。到头来,逻辑是重复的。
让我解释一下……
首先,在定义了我的类之后,我自然而然地开始为我需要的数据编写一个简单的属性:
class PickupTimeSlot(models.Model):
@property
def nb_bookings(self) -> int:
""" How many times this time slot is booked? """
return self.order_set.validated().count()
然后,我很快意识到在处理查询集中的许多对象时调用此属性会导致重复查询并会降低性能(即使我使用预取,因为再次调用过滤)。所以我解决了编写带有注释的自定义查询集的问题:
class PickupTimeSlotQuerySet(query.QuerySet):
def add_nb_bookings_data(self):
return self.annotate(db_nb_bookings=Count('order', filter=Q(order__status=Order.VALIDATED)))
问题
然后,我遇到了两个问题:
- 我有两次相同的业务逻辑(“如何查找预订数量”),这可能会导致功能错误。
- 我需要找到两个不同的属性名称以避免冲突,因为显然,为属性和注释设置
nb_bookings不起作用。这迫使我在使用对象时考虑如何生成数据,调用正确的属性名称(比如说pickup_slot.nb_bookings(属性)或pickup_slot.db_nb_bookings(注释))李>
这对我来说似乎设计得很糟糕,我很确定有办法做得更好。我需要一种方法来始终编写 pickup_slot.nb_bookings 并获得高效的答案,始终使用相同的业务逻辑。
我有一个想法,但我不确定......
我正在考虑完全删除该属性并只保留自定义查询集。然后,对于单个对象,将它们包装在查询集中,以便能够在其上调用添加注释数据。比如:
pickup_slot = PickupTimeSlot.objects.add_nb_bookings_data().get(pk=pickup_slot.pk)
对我来说似乎很老套和不自然。你怎么看?
【问题讨论】:
-
好问题。 Django项目相关票证:code.djangoproject.com/ticket/28822.
-
有时
property的实现更容易当你的数据库中有一个大数据集(比如 1M),因为此时,注释会变慢,因为你正在执行超过 1M 记录的查询. -
恕我直言,只要它们返回相同的结果,就将这两个逻辑保留在您的代码中。让我们等待“官方”实现。
-
只是问:这不是为了获得特定的记录吗?
pickup_slot = PickupTimeSlot.objects.filter(pk=pickup_slot.pk).add_nb_bookings_data()[0]我想注释只会对一条记录进行,对吧?
标签: python django django-models django-queryset