【问题标题】:Saving formset when a compulsory field was not supplied?未提供必填字段时保存表单集?
【发布时间】:2020-04-18 07:16:27
【问题描述】:

当我尝试在更新视图中保存表单集并且表单集添加了新表单时,我收到错误“NOT NULL 约束失败”。我认为原因是数据库有一个不属于Formset ModelForm 的必填字段(journal_entry)。因此,当尝试保存表单集时 lineitem_formset.save() 我得到了错误。

如何在保存表单集之前添加此必填字段值?

查看.py

@login_required
def entries_update(request, pk):
    journal_entry = get_object_or_404(JournalEntry, pk=pk)
    journal_entry.date = journal_entry.date.strftime('%Y-%m-%d') #Convert date format to be suitable for Datepicker input.
    journal_entry_form = JournalEntryForm(instance=journal_entry)

    LineItemFormSet = modelformset_factory(LineItem, fields=('ledger','description','project','cr','dr'), extra=2)
    line_items = LineItem.objects.filter(journal_entry=journal_entry)
    lineitem_formset = LineItemFormSet(queryset=line_items)

    if request.method == 'POST':
        lineitem_formset = LineItemFormSet(request.POST)
        journal_entry_form = JournalEntryForm(request.POST, instance=journal_entry)
        if lineitem_formset.is_valid() and journal_entry_form.is_valid:
            lineitem_formset.save()       <-- ERROR HAPPENS HERE
            journal_entry_form.save()
            messages.success(request, "Journal entry successfully updated.")
            return HttpResponseRedirect(reverse('journal:entries_show_detail', kwargs={'pk': journal_entry.id}) )

模型.py

class JournalEntry(models.Model):
    # User needs to be set back to compulsory !!!
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=True, blank=True)
    date = models.DateField(null=False, blank=False)
    TYPE = (
        ('BP', 'Bank Payment'),
        ('YE', 'Year End'),
        ('JE', 'Journal Entry')
    )
    type = models.CharField(
        max_length=2,
        choices=TYPE,
        blank=True,
        default='0'
        )
    description = models.CharField(max_length=255, null=True, blank=True)
    def __str__(self):
        if self.description:
            return self.description
        else:
            return 'Journal Entry' + str(self.id)
    class Meta(object):
        ordering = ['id']
        verbose_name_plural = 'Journal entries'

class LineItem(models.Model):
    journal_entry = models.ForeignKey(JournalEntry, on_delete=models.CASCADE) <--- This is the field that needs to be set.
    ledger = models.ForeignKey(Ledger, on_delete=models.PROTECT)
    description = models.CharField(max_length=255, null=True, blank=True)
    project = models.ForeignKey(Project, on_delete=models.SET_NULL, null=True, blank=True)
    cr = models.DecimalField(max_digits=8, decimal_places=2, null=True, blank=True)
    dr = models.DecimalField(max_digits=8, decimal_places=2, null=True, blank=True)
    STATUS = (
        ('0', 'Not reconciled'),
        ('1', 'Draft'),
    )
    status = models.CharField(
        max_length=1,
        choices=STATUS,
        default='0'
        )
    reconciliation_date = models.DateField(null=True, blank=True)
    #def __str__(self):
    #    return self.description
    class Meta(object):
        ordering = ['id']

forms.py

class JournalEntryForm(ModelForm):
    def clean_date(self):
        data = self.cleaned_data['date']
        #Check date is not more than 30d future
        if data > (datetime.date.today() + datetime.timedelta(30)):
            raise ValidationError('Date cannot be more than 30d future')
        if data < (datetime.date.today() - datetime.timedelta(90)):
            raise ValidationError('Date cannot be more than 90d past')
        return data
    class Meta:
        model = JournalEntry
        fields = ['date','description']
        widgets = {'date': DateTypeInput()}

class LineItemForm(ModelForm):
    class Meta:
        model = LineItem
        fields = ['ledger','description','project','cr','dr']
    # This init disallows empty formsets
    def __init__(self, *arg, **kwarg):
            super(LineItemForm, self).__init__(*arg, **kwarg)
            self.empty_permitted = False
    def clean(self):
        cr = self.cleaned_data['cr']
        dr = self.cleaned_data['dr']
        if cr == None and dr == None:
            raise ValidationError('You must enter a CR or DR.')
        if cr and dr:
            raise ValidationError('You must enter a CR or DR, not both.')

【问题讨论】:

标签: django django-forms


【解决方案1】:

再次感谢@Iain Shelvington。编辑以下行以使用 inline_formset 并且现在可以使用:

LineItemFormSet = inlineformset_factory(JournalEntry, LineItem, fields=('ledger','description','project','cr','dr'), extra=2)

和:

lineitem_formset = LineItemFormSet(request.POST, instance=journal_entry)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-29
    相关资源
    最近更新 更多