Search code examples
djangodjango-orm

How to annotate integer as a ForeignKey in django?


I have this model:

class Order(Model):
    sale_address = ForeignKey(Address)
    purchase_address = ForeignKey(Address)

and want to conditionally annotate one address or another depending on some condition, as a ForeignKey:

order = Order.objects.annotate(
    address=...  # sale_address if current user is seller
).first()

assert isinstance(order.address, Address)  # True

How can I do that?

I've tried this:

annotate(
    address_id=Case(
        When(
            user_role='SELLER',
            then=F('sale_address'),
        ),
        When(
            user_role='BUYER',
            then=F('purchase_address'),
        ),
    ),
)

but in this case address_id is just an integer and I get N+1 issues when making list of orders with address.region.


Solution

  • As @AKX says, it is likely better to just .select_related(…) [Django-doc] the two Addresses, and then use a @property to determine which one to use, so:

    class Order(models.Model):
        user_role = …
        sale_address = models.ForeignKey(
            Address, on_delete=models.CASCADE, related_name='sale_orders'
        )
        purchase_address = models.ForeignKey(
            Address, on_delete=models.CASCADE, related_name='purchase_orders'
        )
    
        @property
        def address(self):
            if self.user_role == 'SELLER':
                return self.sale_address
            if self.user_role == 'BUYER':
                return self.purchase_address