【问题标题】:Where should I set model fields derived from a form field?我应该在哪里设置从表单字段派生的模型字段?
【发布时间】:2021-10-19 18:55:40
【问题描述】:

给定模型的某些字段不直接映射到ModelForm 的字段,我应该在哪里设置它们的值?在下文中,form.blast_db 应分配给model.protein_dbmodel.nucleotide_db,具体取决于它是什么类型的爆炸数据库。它们是互斥的,但是是必需的,所以必须在调用model.full_clean() 之前设置它们。

from django.db import models

class BlastQuery(models.Model):

    # Protein/nucleotide blast DB. Mutually exclusive, one must be provided
    protein_db = models.ForeignKey(ProteinDB, null=True, blank=True)
    nucleotide_db = models.ForeignKey(ProteinDB, null=True, blank=True)

    # Just 1 field to keep it terse but in reality there are many other fields
    foo = models.IntegerField()

    def clean(self):
        if self.protein_db and self.nucleotide_db:
            raise ValidationError('Protein/nucleotide DB are mutually exclusive')
        if not self.protein_db and not self.nucleotide_db:
            raise ValidationError('Protein/nucleotide DB are required')
from django import forms

class BlastForm(forms.ModelForm):

    # Magical field that's like a ModelChoiceField but can
    # hold both ProteinDB and NucleotideDB instances
    blast_db = BlastDBField()

    class Meta:
        model = BlastQuery
        fields = ('foo',)

【问题讨论】:

    标签: django django-forms modelform


    【解决方案1】:

    您可以在Form.clean中设置派生字段:

    class BlastForm(forms.ModelForm):
    
        # ...
    
        def clean(self):
            super().clean()
    
            # Validate/modify self.cleaned_data
            # ...
            
            # Derive the protein/nucleotide db field
            blast_db = self.cleaned_data.get('blast_db')
            if blast_db:
                if blast_db.type == 'protein':
                    self.instance.protein_db = blast_db
                else:
                    self.instance.nucleotide_db = blast_db
    

    ModelFormform.clean() (在_post_clean)之后将self.instance 更新为self.cleaned_data 并调用model.full_clean(),所以如果你要在form.save() 中更改self.instance,你就来不及阻止验证错误。还要注意,只有Meta.exclude 中没有出现的Meta.fieldsself.cleaned_data 应用到self.instance,所以在self.cleaned_data 中设置protein_db/nucleotide_db 也不会做任何事情。您可以覆盖Model.clean_fields(exclude) 而不是Model.clean,并在protein_dbnucleotide_db 位于exclude 时跳过它们的验证,但是除非您在保存之前再次调用form.full_clean(),否则它们将永远不会被验证。因此只需将其设置为 Form.clean,因为它没有这些缺点。

    【讨论】:

      猜你喜欢
      • 2014-07-09
      • 1970-01-01
      • 1970-01-01
      • 2022-09-29
      • 2021-11-06
      • 2022-08-08
      • 1970-01-01
      • 1970-01-01
      • 2011-12-02
      相关资源
      最近更新 更多