2

I have an address model:

class Address(models.Model):
  line1 = models.CharField(max_length=100)
  ....

and an AddressForm:

class AddressForm(forms.ModelForm):
  class Meta:
    model = Address

Several models will have an address field, so instead of copy+pasting all of the fields from the AddressForm, I wanted to extend the AddressForm so I can reuse it. Specifically, I want to avoid copying+pasting all of the form fields into other app's forms and have only one AddressForm.is_valid() function.

For example, an Order will have an Address, so my plan was to do something like this:

class Order:
  address = models.ForeignKey(Address, on_delete=models.CASCADE)

class OrderForm(AddressForm):
  class Meta:
    model = Order

However, when I pass an instance to the OrderForm from the order/views.py, I'm passing instance of an Order and all of the AddressForm fields show up as blank:

form = OrderForm(instance=order)

How do I initialize the AddressForm fields from the order.address field?

I had tried this:

class OrderForm(AddressForm):
    def __init__(self, *args, **kwargs):
        kwargs['instance'] = kwargs['instance'].address
        super(OrderForm, self).__init__(*args, **kwargs)

But it doesn't work.

Is there a way to do this? Or a better way of reusing the AddressForm? Or would this only work if Order was a subclass of Address?

Cheers,

1 Answer 1

5

If you don't want to subclass Address, then you should use two forms in your view instead of trying to include the address fields in the order form.

if request.method = "POST":
    address_form = AddressForm(request.POST, instance=order.address)
    order_form = OrderForm(request.POST, instance=order)
    if address_form.is_valid() and order_form.is_valid():
        address = address_form.save()
        order = order_form.save()

Your order form should exclude the foreign key to Address.

class OrderForm(AddressForm):
    class Meta:
    model = Order
    exclude = ['address']

When you create new instances, then you should save the order form with commit=False, set the address, and then save the order:

if request.method = "POST":
    address_form = AddressForm(request.POST)
    order_form = OrderForm(request.POST)
    if address_form.is_valid() and order_form.is_valid():
        address = address_form.save()
        order = order_form.save(commit=False)
        order.address = address
        order.save()
Sign up to request clarification or add additional context in comments.

1 Comment

Awesome, that's a great solution. Cheers!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.