postgresql DRF ORM:在同一查询中聚合、注解和删除重复项

qpgpyjmq  于 2023-06-05  发布在  PostgreSQL
关注(0)|答案(1)|浏览(344)

知道我有以下模型:

class Merchant(BaseModel):
    business_name = CharField()
    user = ForeignKey(
        User,
        related_name='merchant'
        # ...
    )
    # other fields...

class Sale(BaseModel):
    merchant = ForeignKey(
        Merchant,
        related_name='sale_merchant'
        # ...
    )
    statue = CustomCharField(
        max_length=20,
        choices=[(DRAFT, DRAFT)), (COMPLETED, COMPLETED), (FAILD, FAILD)],
        # ...
    )
    # other fields like total, discount, data...

class SaleItem(BaseModel):
    quantity = PositiveIntegerField()
    product = ForeignKey(
        Product,
        # ...
    )
    sale = ForeignKey(
        Sale,
        related_name='sold_item'
        # ...
    )
    # other fields...

以及Product模型和User模型(User模型存储用户的城市作为City模型的参考)。
正如你所看到的,一个Sale,可以有多个SaleItem,一个SaleItem指的是一个ProductSale本身,并且有一个量。
最后,Sale代表我们出售给特定商家的一组产品。
我想得到的项目的数量,每种产品被出售给每个商人。我试图实现的输出示例(id复制第一个SaleItemid,该SaleItem将产品X链接到商家Y):

+--------------------------------------------------------------------+
| id  |  Merchant Name | Denomination |  Quantity  |  Merchant City  |
|-----|----------------|--------------|------------|-----------------|
|  1  |   Merchant_1   |  Product_1   |    133     |     London      |
|-----|----------------|--------------|------------|-----------------|
|  2  |   Merchant_1   |  Product_2   |    1234    |      NYC        |
|-----|----------------|--------------|------------|-----------------|
|  3  |   Merchant_2   |  Product_1   |     54     |     Tokyo       |
+--------------------------------------------------------------------+

Denomination表示产品名称。
我尝试了很多方法,但都无法达到同样的效果。我可以通过多个步骤来完成它,但我需要在一个查询中完成它,无论它有多复杂。
最后,我需要id来获取出售给商家的每个产品的单个项目的信息,所以如果有更好的方法来实现这一点,我愿意听取建议。谢谢

bd1hkmkf

bd1hkmkf1#

我认为下面的方法应该会产生预期的结果

qs = Merchant.objects.all()
# Join through Sale and SaleItem by the use of related_name
qs = qs.annotate(product_id=F("sale_merchant__sold_item__product__id"))
# Gather relevant data
qs = qs.annotate(denomination=F("sale_merchant__sold_item__product__denomination"))
qs = qs.annotate(individual_quantity=F("sale_merchant__sold_item__quantity"))
qs = qs.annotate(city_name=F("user__city__name"))
# Keeping only relevant data and discarding the model layer to allow for grouping
qs = qs.values("id", "product_id", "name", "denomination", "city_name")
# Froce a grouping while summing the quantities
qs = qs.annotate(quantity=Sum("individual_quantity"))
# Keeping only the desired data
qs = qs.values("name", "denomination", "quantity", "city_name")

您会注意到,结果将是一个以"name", "denomination", "quantity", "city_name"作为键的dict。
作为一个侧记,您的related_name s应该是复数,因为有一个以上的销售每个商家和一个以上的销售项目每个销售。salessold_items是合适的。

相关问题