Set the default billing address in admin form

时间:2019-01-18 18:55:15

标签: python django django-models django-admin

I'm working on a Django project where I have several customers, each of which can have multiple postal addresses (office 1, office 2, office 3, ...). I have to choose the default address for each customer.

I created a model for postal addresses with ForeignKey pointing to the customer model and in my customer model I entered a PositiveIntegerField to contain the default postal address ID. The problem is that I do not know how to filter in the Admin Form only the addresses relevant to the client and show the description of the address instead of a PositiveIntegerField.

Some advice?

1 个答案:

答案 0 :(得分:1)

I created a model for postal addresses with ForeignKey pointing to the customer model and in my customer model I entered a PositiveIntegerField to contain the default postal address ID.

Don't do that. This is in fact a relation, so you should use the tool that is constructed for this: a ForeignKey [Django-doc].

We can thus construct something like:

class Customer(models.Model):
    default_address = models.ForeignKey(
        'app.Address',
        on_delete=models.SET_NULL,
        null=True
    )

class Address(models.Model):
    customer = models.ForeignKey(
        Customer,
        on_delete=models.CASCADE,
        related_name='addresses'
    )

In a ModelForm you can then restrict the options to addresses that belong to that specific instance. For example:

class CustomerModelForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(CustomerModelForm, self).__init__(*args, **kwargs)
        if self.instance:
            self.fields['default_address'].queryset = Address.objects.filter(
                customer=self.instance
            )

    class Meta:
        model = Customer

So here we limit the options to addresses that belong to the customer.

The advantage of using a ForeignKey is that the database will protect referential integrity (the id can not refer to a non-existing address), and furthermore all advanced querying you can do with Django's ORM is still possible here. You can thus filter on Customers with a default_address that is located in London for example with something like Customer.objects.filter(default_address__city='London') (given an address has a city field).