Hello all, I think this post might be of interest to those interested in the following posts:
"I have overridden the order.ShippingAddressForm but dashboard.orders.views.ShippingAddressUpdateView isnt picking it up"
"overriding the useraddressform"
Objective: I wanted to change the fields that are presented at checkout and for the address book. My original approach was to for the address app to override the AbstractAddress model to delete the title, postcode and line3 fields. I wanted to do this because I just didn't want these fields presented to the user, and I had no use for them (this is for a site in a country where postal codes are not useful). This, however, caused problems because of the way the get_classes method loading.py file loads oscar and local modules. The loader will always import the PartnerAddressForm class from the oscar module:
oscar/apps/dashboard/partners/forms.py
even if you fork dahsborad.partners and override the form - that is, even if you don't use the oscar module. The relevant section in loading.py is:
# e.g. split 'dashboard.catalogue.forms' in 'dashboard.catalogue', 'forms'
package, module = module_label.rsplit('.', 1)
# import from Oscar package (should succeed in most cases)
# e.g. 'oscar.apps.dashboard.catalogue.forms'
oscar_module_label = "oscar.apps.%s" % module_label
oscar_module = _import_module(oscar_module_label, classnames)
At the bottom of the forms.py file in the oscar module is the following class definition, which will always get imported even if you fork and try to override it:
class PartnerAddressForm(forms.ModelForm):
class Meta:
fields = ('line1', 'line2', 'line3', 'line4',
'state', 'postcode', 'country')
model = PartnerAddress
So if you delete any of the fields in the tuple above from the AbstractAddress model that you override, you will get an error when you try to use any sublcass of AbstractAddress as a model for a model form. The above class PartnerAddressForm will always get imported, and if any of the fields in the fields variable are missing, an error is raised.
So my workaround for this was to do the following:
1. Fork the address module, and keep the fields but override the ensure_postcode_is_valid_for_country method so that it does nothing. In the forms.py of that module I also got rid of PhoneNumberMixin (I want flexibility to enter phone numbers in various formats, with/without the country code, etc.).
2. To hide the title, line3 and postcode fields I modified TWO files:
(a) In my forked address module, in the forms.py file I added these three fields to the fields variable in the Meta class of the UserAddressForm class:
class UserAddressForm(AbstractAddressForm):
class Meta:
model = UserAddress
exclude = ('user', 'num_orders', 'hash', 'search_text',
'is_default_for_billing', 'is_default_for_shipping',
'title', 'line3', 'postcode',)
def __init__(self, user, *args, **kwargs):
super(UserAddressForm, self).__init__(*args, **kwargs)
self.instance.user = user
(b) I overrode the checkout module, and in that forms.py file I added these three fields to the Meta class of the ShippingAddressForm class:
class ShippingAddressForm(AbstractAddressForm):
def __init__(self, *args, **kwargs):
super(ShippingAddressForm, self).__init__(*args, **kwargs)
self.adjust_country_field()
def adjust_country_field(self):
countries = Country._default_manager.filter(
is_shipping_country=True)
# No need to show country dropdown if there is only one option
if len(countries) == 1:
del self.fields['country']
self.instance.country = countries[0]
else:
self.fields['country'].queryset = countries
self.fields['country'].empty_label = None
class Meta:
model = get_model('order', 'shippingaddress')
exclude = ('user', 'search_text', 'title', 'postcode', 'line3')
This seems to have done the trick. Took me a long time to figure out- I hope it saves others some time.
Cheers,