现在我正在尝试构建使用带有条件相关查询的注释的复杂查询集。
我有以下型号:
},
我的目标是使用以下方案构建json:
class MenuItemCategory(CreateUpdateModel):
name = models.CharField(max_length=255, blank=True, null=True)
class MenuItem(CreateUpdateModel):
category = models.ForeignKey(MenuItemCategory, blank=True, null=True)
name = models.CharField(max_length=255, blank=True, null=True)
class LineItem(models.Model):
order = models.ForeignKey(Orders, blank=True, null=True)
menu_item = models.ForeignKey(MenuItems, blank=True, null=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
quantity = models.DecimalField(max_digits=10, decimal_places=3)
amount = models.DecimalField(max_digits=10, decimal_places=2)
class Order(CreateUpdateModel):
waiter = models.ForeignKey(Employees, blank=True, null=True)
guests_count = models.IntegerField(blank=True, null=True, default=0)
closed_at = models.DateTimeField(blank=True, null=True, db_index=True)
class Employees(CreateUpdateModel):
restaurant = models.ForeignKey(Restaurants, blank=True, null=True)
name = models.CharField(max_length=255, blank=True, null=True)
使用以下序列化程序:
[
{
employee_name: 'Jane',
menu_item_categories: [
{
name: 'Drinks',
line_items_quantity: 10, //times when this waiter brings any item from this category to the customer at the period
amount: 49.00, // price of all drinks sold by this waiter at the period
menu_items: [
name: 'Vodka',
amount: 1.00,
line_items_quantity: 4, # times when this item has been ordered for this waiter at the period
]
}
],
visits: 618,
guests: 813,
cycle_time: 363
}
]
但是当我尝试构建class EmployeeSerializer(serializers.ModelSerializer):
name = serializers.CharField(max_length=255)
visits = serializers.SerializerMethodField()
guests = serializers.SerializerMethodField()
cycle_time = serializers.SerializerMethodField()
menu_item_categories = serializers.SerializerMethodField()
def get_visits(self, obj):
# works
def get_guests(self, obj):
# works
def get_cycle_time(self, obj):
# works
def get_menu_item_categories(self, obj):
qs = MenuItemCategories.objects.annotate(
line_items_quantity=Count('menuitems__lineitems__order',
filter=Q(
menuitems__lineitems__order__closed_at__range=self.context.get('period'),
menuitems__lineitems__order__waiter=obj)
),
amount=Sum('menuitems__lineitems__amount',
filter=Q(
menuitems__lineitems__order__closed_at__range=self.context.get('period'),
menuitems__lineitems__order__waiter=obj)
),
menu_items=Subquery(
MenuItems.objects.filter(
lineitems__order__closed_at__range=self.context.get('period'),
lineitems__order__waiter=obj
).annotate(amount=Sum('lineitems__amount', filter=Q(lineitems__order__closed_at__range=self.context.get('period'),
lineitems__order__waiter=obj)))
)
)
return MenuItemCategorySerializer(qs, many=True).data
值时,它会给我一个错误:menu_item_categories
。据我所知,我的目标是使用自定义子查询来注释类别queryset,我的麻烦是我不了解子查询是如何工作的,或者我使用不正确的工具包来构建orm查询。那么,我如何用orm查询和这个序列化器构建这个json?
UPD
当前查询
subquery must return only one column
答案 0 :(得分:1)
您无法直接通过一个查询获得此类结构,这仅仅是因为RDBMS的工作方式。但是,您可以从最简单的项目中获得大量冗余信息的大结果,这样您就可以以编程方式对数据进行分组以生成json结构,或者您可以通过迭代查询集来一步完成: / p>
t_range=self.context.get('period')
employees = Employees.objects.filter(order__closed_at__range=t_range) \
.annotate(
visits=Count(...),
guests=Count(...),
cycle_time=Sum(...),
)
result = []
for employee in employees:
menu_item_categories = MenuItemCategory.objects.filter(menuitem__lineitem__order__waiter=employee) \
.annotate(
line_items_quantity=Count(...),
amount=Sum(...),
)
_cats = []
for cat in menu_item_categories:
menu_items = cat.menuitem_set.filter(order__waiter=employee) \
.annotate(
amount=Sum(...),
line_items_quantity=Count(...),
)
_menu_items = []
for menu_item in menu_items:
_menu_item = {
'name': menu_item.name,
'amount': menu_item.amount,
'line_items_quantity': menu_item.line_items_quantity,
}
_menu_items.append(_menu_item)
_cats.append({
'name': cat.name,
'line_items_quantity': cat.line_items_quantity,
'amount': cat.amount,
'menu_items': _menu_items
})
result.append({
'employee_name': employee.name,
'visits': employee.visits,
'guests': employee.guests,
'cycle_time': employee.cycle_time,
'menu_item_categories': _cats
})
当然,这将不止一次打到数据库,所以除非你更喜欢这种方法的表现,否则这就行了。