The error:
null value in column “postal_code_id” violates not-null constraint
The form:
def add(request):
if request.method == 'POST':
address_form = AddressForm(request.POST)
company_form = CompanyForm(request.POST)
if address_form.is_valid() and company_form.is_valid():
print address_form.cleaned_data['postal_code'] # <-- prints (<PostalCode: V4N 1K6>, False)
address_form.save() # <------------------------------- occurs here
else:
print 'Address errors',address_form.errors
print 'Company errors', company_form.errors
else:
address_form = AddressForm()
company_form = CompanyForm()
return render(request, 'company/add.html', locals())
Clearly the form does have a valid PostalCode object, so I’m not sure why it’s saying it violates the not-null constraint. Of course, I am doing something kinda funny with the form:
class AddressForm(ModelForm):
postal_code = CharField(max_length=10, validators=[validate_postal_code])
city = CharField(max_length=50, validators=[validate_non_whitespace])
province = CharField(max_length=50, validators=[validate_non_whitespace])
country = CharField(max_length=50, initial='Canada', validators=[validate_non_whitespace])
def clean_postal_code(self):
code = self.cleaned_data['postal_code']
code = code.upper()
code = re.sub('[^A-Z0-9]', '', code)
code = code[:3] + ' ' + code[-3:]
return code
def clean_country(self):
country = self.cleaned_data['country']
try:
country = Country.objects.get(name__iexact=country)
except Country.DoesNotExist:
raise ValidationError('Country does not exist')
return country
def clean_province(self):
province = self.cleaned_data['province']
if not Province.objects.filter(name__iexact=province).exists():
raise ValidationError('Province does not exist')
return province
def clean(self):
data = self.cleaned_data
if 'country' in data and 'province' in data:
try:
data['province'] = Province.objects.get(country=data['country'], name__iexact=data['province'])
if 'city' in data:
data['city'] = City.objects.get_or_create(name__iexact=data['city'], province=data['province'], defaults={'name':data['city']})[0]
if 'postal_code' in data:
data['postal_code'] = PostalCode.objects.get_or_create(code=data['postal_code'], city=data['city'])
except Province.DoesNotExist:
self._errors['province'] = self.error_class(['Province does not exist in that Country'])
del data['province']
return data
class Meta:
exclude = ['postal_code']
model = Address
Specifically, I’m replacing the postal_code field with a text field and then I find/create the object in the “clean” method. Why does that confuse Django? It’s getting the object it needs in the end, isn’t it?
You’re excluding
postal_code, which will cause the model form to skip over the field later on during the save attempt. I’ve had a similar problem, and had to trace through django code to figure out the behaviour. It’s worth doing by the way.What you want to do instead, is set the widget used for the postal_code field instead of excluding then including.
That should allow the modelform to validate the field correctly and save it. I excluded the rest of your form for brevity.
Edit:
Attempting to use a CharField for a ForeignKey is fraught with horrible in a ModelForm. Instead, convert it to a regular form. You already appear to be defining most of your fields anyway. Then the reliance is on you to validate that fields are valid, and are members of the database already. Create a save method that behaves like the ModelForm save method, and away you go.