在Django ORM中连接两次表

nwnhqdif  于 2023-10-21  发布在  Go
关注(0)|答案(1)|浏览(99)

我有两个模特

class Customer(AbstractBaseModel):    
    uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, db_column='uuid')
    name = models.CharField(max_length=55)

class CustomerAddress(AbstractBaseModel):
    uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, db_column='uuid')
    customer = models.ForeignKey(Customer, on_delete=models.DO_NOTHING, related_name='addresses', db_column='customer_uuid')
    country_code = models.CharField(max_length=3)
    type = models.CharField(max_length=8, choices=[('shipping', 'shipping'), ('billing', 'billing')])

用户可以使用两个字段筛选客户:billing_countryshipping_country,它们可以填充一个或两个字段。如果用户填写两个字段,我必须两次连接到CustomerAddress表。我在原始SQL中这样做:

SELECT *
FROM customer c
LEFT OUTER JOIN address shipping_address ON shipping_address.customer_uuid = c.uuid AND shipping_address.type = 'shipping'
LEFT OUTER JOIN address billing_address ON billing_address.customer_uuid = c.uuid AND billing_address.type = 'billing'

并附加WHERE子句,如果用户使用这样的过滤器:

# billing_country and shipping_country are sanitized at this point
filters = []
if billing_country:
    filters.append(f"billing_address.country_code = '{billing_country}'")
if shipping_country:
    filters.append(f"shipping_address.country_code = '{shipping_country}'")
where_part = 'WHERE ' + ' AND '.join(filters)

如何使用Django ORM实现这一点?

knpiaxh1

knpiaxh11#

最后我使用了FilteredRelation:

qs = Customer.objects.annotate(
    shipping_address=FilteredRelation('address', condition=Q(address.type='shipping')),
    billing_address=FilteredRelation('address', condition=Q(address.type='billing'))
)

WHERE部分如下所示:

if billing_country:
    qs.filter(billing_address__country_code__iexact=billing_country)

相关问题