Django — concatenate filter on a many_to_many relation create unexpected join
Question:
class ProductionOrderProductionOrderStatus(sf_models.BaseModel):
production_order = models.ForeignKey(ProductionOrder, on_delete=models.CASCADE)
production_order_status = models.ForeignKey(ProductionOrderStatus, on_delete=models.CASCADE)
class ProductionOrderStatus(sf_models.BaseModel):
status = models.IntegerField(null=False)
begin_datetime = models.DateTimeField(default=timezone.now)
end_datetime = models.DateTimeField(null=True, blank=True)
class ProductionOrder(sf_models.BaseModel):
statuses = models.ManyToManyField(ProductionOrderStatus, through='ProductionOrderProductionOrderStatus', related_name='production_orders')
if i concatenate 2 filter like this ->
ProductionOrder.objects.filter(statuses__status=2).filter(statuses__end_datetime=None)
i get this sql:
'SELECT ... FROM "production_order_productionorder"
INNER JOIN "production_order_productionorderproductionorderstatus" ON ("production_order_productionorder"."id" = "production_order_productionorderproductionorderstatus"."production_order_id")
INNER JOIN "production_order_productionorderstatus" ON ("production_order_productionorderproductionorderstatus"."production_order_status_id" = "production_order_productionorderstatus"."id")
LEFT OUTER JOIN "production_order_productionorderproductionorderstatus" T4 ON ("production_order_productionorder"."id" = T4."production_order_id")
LEFT OUTER JOIN "production_order_productionorderstatus" T5 ON (T4."production_order_status_id" = T5."id")
WHERE ("production_order_productionorderstatus"."status" = 2 AND T5."end_datetime" IS NULL)'
if i put on the same filter like this ->
ProductionOrder.objects.filter(statuses__status=2, statuses__end_datetime=None)
i get this sql:
'SELECT ... FROM "production_order_productionorder"
INNER JOIN "production_order_productionorderproductionorderstatus" ON ("production_order_productionorder"."id" = "production_order_productionorderproductionorderstatus"."production_order_id")
INNER JOIN "production_order_productionorderstatus" ON ("production_order_productionorderproductionorderstatus"."production_order_status_id" = "production_order_productionorderstatus"."id")
WHERE ("production_order_productionorderstatus"."end_datetime" IS NULL AND "production_order_productionorderstatus"."status" = 2)'
if i have a queryset created with this condition: ProductionOrder.objects.filter(statuses__status=2)
how can i concatenate the second condition?
is there a solution to get a dict of the already filtered condition? (to get for example {‘statuses__status’:2}, so i can concatenate the second condition and recreate the query)
Answers:
This is a "by-design" Django behavior -> see Django docs
Possible duplicate of Chaining multiple filter() in Django, is this a bug?
class ProductionOrderProductionOrderStatus(sf_models.BaseModel):
production_order = models.ForeignKey(ProductionOrder, on_delete=models.CASCADE)
production_order_status = models.ForeignKey(ProductionOrderStatus, on_delete=models.CASCADE)
class ProductionOrderStatus(sf_models.BaseModel):
status = models.IntegerField(null=False)
begin_datetime = models.DateTimeField(default=timezone.now)
end_datetime = models.DateTimeField(null=True, blank=True)
class ProductionOrder(sf_models.BaseModel):
statuses = models.ManyToManyField(ProductionOrderStatus, through='ProductionOrderProductionOrderStatus', related_name='production_orders')
if i concatenate 2 filter like this ->
ProductionOrder.objects.filter(statuses__status=2).filter(statuses__end_datetime=None)
i get this sql:
'SELECT ... FROM "production_order_productionorder"
INNER JOIN "production_order_productionorderproductionorderstatus" ON ("production_order_productionorder"."id" = "production_order_productionorderproductionorderstatus"."production_order_id")
INNER JOIN "production_order_productionorderstatus" ON ("production_order_productionorderproductionorderstatus"."production_order_status_id" = "production_order_productionorderstatus"."id")
LEFT OUTER JOIN "production_order_productionorderproductionorderstatus" T4 ON ("production_order_productionorder"."id" = T4."production_order_id")
LEFT OUTER JOIN "production_order_productionorderstatus" T5 ON (T4."production_order_status_id" = T5."id")
WHERE ("production_order_productionorderstatus"."status" = 2 AND T5."end_datetime" IS NULL)'
if i put on the same filter like this ->
ProductionOrder.objects.filter(statuses__status=2, statuses__end_datetime=None)
i get this sql:
'SELECT ... FROM "production_order_productionorder"
INNER JOIN "production_order_productionorderproductionorderstatus" ON ("production_order_productionorder"."id" = "production_order_productionorderproductionorderstatus"."production_order_id")
INNER JOIN "production_order_productionorderstatus" ON ("production_order_productionorderproductionorderstatus"."production_order_status_id" = "production_order_productionorderstatus"."id")
WHERE ("production_order_productionorderstatus"."end_datetime" IS NULL AND "production_order_productionorderstatus"."status" = 2)'
if i have a queryset created with this condition: ProductionOrder.objects.filter(statuses__status=2)
how can i concatenate the second condition?
is there a solution to get a dict of the already filtered condition? (to get for example {‘statuses__status’:2}, so i can concatenate the second condition and recreate the query)
This is a "by-design" Django behavior -> see Django docs
Possible duplicate of Chaining multiple filter() in Django, is this a bug?