如何使用另一个查询集注释查询集

时间:2017-12-26 14:34:25

标签: django django-orm

现在我正在尝试构建使用带有条件相关查询的注释的复杂查询集。

我有以下型号:

},

我的目标是使用以下方案构建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

1 个答案:

答案 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
    })

当然,这将不止一次打到数据库,所以除非你更喜欢这种方法的表现,否则这就行了。