2011-06-11 81 views
3

錯誤:爲什麼Django給我這個「違反非空約束」的錯誤?

null value in column "postal_code_id" violates not-null constraint

形式:

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字段,然後我發現/在「乾淨」的方法創建對象。爲什麼會混淆Django?它最終得到了它需要的對象,不是嗎?

回答

2

您不包括postal_code,這將導致模型表單在保存嘗試期間稍後跳過該字段。我遇到過類似的問題,必須通過django代碼來找出行爲。這是值得的。

你想做什麼,而是設置用於postal_code字段的小部件,而不是排除然後包括。

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

這應該允許modelform正確驗證字段並保存它。爲簡潔起見,我排除了其他表單。

編輯:

試圖使用一個CharField爲一個ForeignKey是充滿了一個可怕的ModelForm。相反,將其轉換爲常規形式。無論如何,你似乎已經定義了你的大部分領域。然後,依賴於您驗證該字段是否有效,並且已經是數據庫的成員。創建一個類似於ModelForm保存方法的保存方法,然後離開。

+0

哈!輝煌。忘了我已經排除了'postal_code'。那,我需要一個'[0]'在'PostalCode.objects.get_or_create'(它返回一個元組)。刪除排除修復它,但做它的「小部件」,而不是導致此錯誤「CharField」對象沒有屬性「value_from_datadict''而是。你知道這是爲什麼嗎? – mpen 2011-06-11 03:04:48

+1

@mark對不起,我沒有清楚地閱讀你的問題。由於postal_code是一個外鍵,當它試圖將POST數據轉換爲表單中的字段時,該字段需要一個id(不是文本字段)。這就是它失敗的原因。之前我必須處理這個問題,最簡單的方法是定義自己的自定義表單(不是模型表單),並自己處理保存方法。你沒有太多的領域,所以它不應該太難。 – 2011-06-11 03:36:18

+0

Hrm ...我現在要繼續這樣做(覆蓋該領域),但如果這變得有問題,我會記住這一點。謝謝! – mpen 2011-06-11 05:51:42

1

我不知道Django,但也許您必須確保在嘗試保存地址之前保存郵政編碼?

+0

好的理論,但'get_or_create'確實在數據庫中創建對象。只是檢查,它確實存在。 – mpen 2011-06-11 02:50:09

1

我來到這個問題,因爲我試圖自動添加一個uploaded_by字段形成數據之前,窗體被保存。我使用的是ModelForm,排除了uploaded_by。我發現對related stackoverflow question的回答是解決這個問題的簡潔方法。

0

我到了這個問題,因爲當我試圖提交一個帶有blank=True的CharField的ModelForm實例(yep,null=True不應該與CharField一起使用)時,我得到了那個IntegrityError錯誤。問題出現在表單中:各個字段的clean_field()方法首先檢查字段值的存在,但如果值不存在,則返回None,這正是違反非空約束的原因。修復方法返回檢查值的相同cleaned_data['field']解決了問題。

相關問題