通过 Django ModelForm 中的外键字段验证多个相关对象

Validate multiple related objects through foreign key field in Django ModelForm

在下面代码所示的示例中,是否可以使用 LocalizacaoForm 自动验证和创建 EnderecoCoordenada 的实例?

我之所以要这样做是为了尽可能多地使用通用视图,并且它们不能很好地(至少不是开箱即用的)使用多个 ModelForm每次观看。

在应用程序中,我想呈现一个 LocalizacaoForm 并显示来自 EnderecoCoordenada 的字段。到目前为止我所做的似乎并没有解决它,因为 self.fields.update(fields_for_model(Coordenada)) 只创建输入字段,而不是 Coordenada 的实际实例。因此,我得到对象 coordenada.

django NOT NULL constraint failed id

有没有办法做我想做的事,或者我应该坚持单独渲染每个表单?

#models.py
class Coordenada(models.Model):
    latitude = models.FloatField()
    longitude = models.FloatField()
    altitude = models.FloatField()
    erro_horizontal = models.FloatField()

class Endereco(models.Model):
    cep = models.IntegerField()
    uf = models.CharField(max_length=2)
    localidade = models.CharField(max_length=50)  # nome da cidade
    # other fields...

class Localizacao(models.Model):
    endereco = models.OneToOneField(Endereco)
    coordenada_geografica = models.ForeignKey('Coordenada')

#forms.py
class LocalizacaoForm(forms.ModelForm):

    def __init__(self, instance=None, *args, **kwargs):
        super(LocalizacaoForm, self).__init__(instance=instance, *args, **kwargs)
        # Retrieve the fields from Endereco and Coordenada model and update the fields with it
        self.fields.update(fields_for_model(Endereco))
        self.fields.update(fields_for_model(Coordenada))

    class Meta:
        model = Localizacao
        exclude = ('endereco', 'coordenada_geografica')

#views.py
class LocalizacaoCreateView(generic.CreateView):
    model = Localizacao
    form_class = LocalizacaoForm
    template_name = 'localizacao_create_form.html'

您可以在 LocalizacaoFormsave() 方法中创建 CoordenadaEndereco 的实例,如下所示:

class LocalizacaoForm(forms.ModelForm):

    # The rest of the form ...
    # ...

    def save(self, commit=False):
        localizacao = super(LocalizacaoForm, self).save(commit=False)

        # create an instance of Coordenada
        coordenada = Coordenada.objects.create(
                        latitude=self.cleaned_data['latitude'],
                        longitude=self.cleaned_data['longitude'],
                        altitude=self.cleaned_data['altitude'],
                        erro_horizontal=self.cleaned_data['erro_horizontal']
                    )

        # create an instance of Endereco
        endereco = Endereco.objects.create(
                        cep=self.cleaned_data['cep'],
                        uf=self.cleaned_data['uf'],
                        localidade=self.cleaned_data['localidade'],
                    )

        # add those instances to localizacao
        localizacao.coordenada_geografica = coordenada
        localizacao.endereco = endereco

        if commit:
            localizacao.save()
        return localizacao