【问题标题】:Why is Django giving me this "violates not-null constraint" error?为什么 Django 给我这个“违反非空约束”错误?
【发布时间】:2011-09-12 21:54:52
【问题描述】:

错误:

“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 对象,所以我不确定为什么它说它违反了非空约束。当然,我正在对表单做一些有趣的事情:

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 感到困惑?它最终得到了它需要的对象,不是吗?

【问题讨论】:

    标签: python django django-models django-forms


    【解决方案1】:

    您排除了postal_code,这将导致模型表单稍后在保存尝试期间跳过该字段。我遇到了类似的问题,不得不通过 django 代码来找出行为。顺便说一句,这是值得的。

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

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

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

    编辑:

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

    【讨论】:

    • 哈!杰出的。忘了我已经排除了postal_code。那,我需要[0] 上的PostalCode.objects.get_or_create(它返回一个元组)。删除排除修复它,但这样做widgets 会导致此错误'CharField' object has no attribute 'value_from_datadict' 代替。你知道这是为什么吗?
    • @mark 抱歉,我没有足够清楚地阅读您的问题。由于 postal_code 是外键,因此当它尝试将 POST 数据转换为表单中的字段时,该字段需要一个 id(不是文本字段)。这就是它失败的原因。我之前不得不处理这个问题,最简单的方法是定义自己的自定义表单(不是模型表单),并自己处理保存方法。你没有很多领域,所以应该不会太难。
    • Hrm... 我现在将继续这样做(覆盖该字段),但如果这成为问题,我会记住这一点。谢谢!
    【解决方案2】:

    我不知道 Django,但也许您必须确保在尝试保存地址之前保存邮政编码?

    【讨论】:

    • 理论不错,但get_or_create 确实在数据库中创建了对象。刚查了一下,确实有。
    【解决方案3】:

    我来这个问题是因为我试图在保存表单之前自动添加一个uploaded_by 字段到表单数据。我使用的是ModelForm,不包括uploaded_by。我发现related stackoverflow question 的答案是这个问题的简洁解决方案。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2021-01-21
        • 2018-09-12
        • 2015-07-13
        • 2012-11-02
        • 2020-03-17
        • 1970-01-01
        • 2019-08-08
        • 1970-01-01
        • 2018-05-28
        相关资源
        最近更新 更多