Добавление аннотированного поля в Django Queryset

У меня есть приложение Django. У меня есть 3 модели Django, такие как:

/Модель 1:

class ModelAOrders(models.Model):
    id = models.CharField(primary_key=True, max_length=16)
    plant_num = models.ForeignKey(Plant, db_column='plant_num', db_index=True, on_delete=models.CASCADE)
    purchase_order_num = models.CharField(max_length=10)
    purchase_order_item_num = models.CharField(max_length=5)
    material_num = models.ForeignKey(Material, db_column='material_num', db_index=True, on_delete=models.CASCADE)
    current_delivery_dt = models.DateField(null=True)
    lastest_delivery_dt_modification_dt = models.DateField(null=True)
    .....
    [Other Fields]

    class Meta:
        db_table = 'modelA_po'

/Модель 2:

class ModelBFlags(models.Model):
    purchase_order = models.ForeignKey(ModelAOrders, null=True, on_delete=models.CASCADE)
    purchase_order_num = models.CharField(max_length=10)
    purchase_order_item_num = models.CharField(max_length=5)
    shipped_flg = models.BooleanField(default=False)
    delivered_flg = models.BooleanField(default=False)
    expedite_flg = models.BooleanField(default=False)

    class Meta:
        db_table = 'modelB_flags'

/Модель 3:

class ModelCBackorders(models.Model):
    bo_id = models.CharField(max_length=255, blank=True, null=True)
    bo_start_date = models.DateField(blank=True, null=True)
    bo_end_date = models.DateField(blank=True, null=True)
    material_num = models.ForeignKey(Material, db_column='material_num', db_index=True, on_delete=models.CASCADE)
    mrpcn = models.CharField(max_length=3, blank=True, null=True)
    mrpcn_mapping = models.ForeignKey(MrpcnMapping, null=True, on_delete=models.CASCADE)
    planned_delivery_time_value = models.FloatField(null=True)
     ....
    [Other Fields]
    
    class Meta:
        db_table = 'modelC_backorders'

Как добавить аннотированное поле к набору запросов обратного заказа на основе следующего SQL-кода:

SQL-эквивалент:

SELECT SUM(distinct(opo.outstanding_qty)) FROM apple.modelC_backorders kb
LEFT JOIN apple.modelA_po opo ON kb.material_num = opo.material_num
LEFT JOIN apple.modelB_flags iof
ON  opo.id = iof.purchase_order_id
WHERE iof.shipped_flg=1 AND opo.outstanding_qty>0
GROUP BY kb.material_num, opo.purchase_order_num, opo.purchase_order_item_num;

Это то, что у меня есть на данный момент, но он возвращает null для всех значений.

backorders_queryset = ModelCBackorders.objects.annotate(
    inbound_shipped_qty=Subquery(
        ModelAOrders.objects.filter(
            material_num=OuterRef('material_num'),  
            modelbflags__shipped_flg=True,
            outstanding_qty__gt=0
        ).annotate(
            total_outstanding_qty=Sum('outstanding_qty', distinct=True)
        ).values('total_outstanding_qty')[:1],
        output_field=IntegerField()
    )
)

Я отфильтровал ModelAOrders, чтобы получить заказы с флагами shipped и outstanding_qty > 0, но использовал distinct здесь, вот что отличается от вашего кода:

filtered_orders = ModelAOrders.objects.filter(
    modelbflags__shipped_flg=True,
    outstanding_qty__gt=0
).distinct()

Затем вторая часть. Я подготовил запрос на сумму неоплаченных количеств для тех же material_num, purchase_order_num и purchase_order_item_num:

summed_orders = filtered_orders.annotate(
    total_outstanding_qty=Sum('outstanding_qty')
).values('material_num', 'purchase_order_num', 'purchase_order_item_num', 'total_outstanding_qty')

и, наконец, используя подзапрос для получения суммированных значений:

backorders_queryset = ModelCBackorders.objects.annotate(
    inbound_shipped_qty=Subquery(
        summed_orders.filter(
            material_num=OuterRef('material_num'),
            purchase_order_num=OuterRef('purchase_order_num'),
            purchase_order_item_num=OuterRef('purchase_order_item_num')
        ).values('total_outstanding_qty')[:1],
        output_field=IntegerField()
    )
)
Вернуться на верх