Добавление аннотированного поля в 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()
)
)