为什么Django给我这个“违反非空约束”的错误?

时间:2011-06-11 02:45:36

标签: python django django-models django-forms

错误:

  列“postal_code_id”中的

空值违反了非空约束

表格:

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())

显然,表单确实有一个有效的PostalCode对象,所以我不确定为什么它会违反not-null约束。当然,我正在做一些有趣的事情:

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

具体来说,我用文本字段替换postal_code字段,然后在“clean”方法中查找/创建对象。为什么这会混淆Django?它最终得到了它需要的对象,不是吗?

4 个答案:

答案 0 :(得分:2)

您要排除postal_code,这会导致模型表单稍后在保存尝试期间跳过该字段。我遇到了类似的问题,并且必须通过django代码来查找行为。值得一提的是。

你要做的是设置用于postal_code字段的小部件,而不是排除然后包括。

class AddressForm(ModelForm):
    class Meta:
        model = Address
        widgets = {
            'postal_code': CharField(max_length=10),
        }

这应该允许modelform正确验证字段并保存它。为简洁起见,我排除了表格的其余部分。

编辑:

在ModelForm中尝试使用CharField作为ForeignKey充满了可怕。而是将其转换为常规形式。无论如何,您似乎已经定义了大部分字段。然后依赖于您验证字段是否有效,并且已经是数据库的成员。创建一个行为类似于ModelForm保存方法的保存方法,然后离开。

答案 1 :(得分:1)

我不知道Django,但您可能需要确保在尝试保存地址之前保存邮政编码?

答案 2 :(得分:1)

我遇到了这个问题,因为我试图在保存表单之前自动添加uploaded_by字段以形成数据。我使用ModelFormuploaded_by被排除在外。我发现related stackoverflow question的答案是解决这个问题的简洁方法。

答案 3 :(得分:0)

我到达这个问题是因为当我尝试提交一个具有blank=True的CharField的ModelForm实例时,我收到了IntegrityError错误(是的,null=True永远不应该与CharField一起使用)。问题出在表单本身:相应字段的clean_field()方法首先检查字段值是否存在,但如果该值不存在,则返回None,这正是为什么不为null约束被违反了。修复方法以返回检查值的相同cleaned_data['field']解决了问题。