使用django表单保存新的外键

Ed.*_*Ed. 5 django django-forms

我有两个型号:

class Studio(models.Model):
    name = models.CharField("Studio", max_length=30, unique=True)

class Film(models.Model):
    studio = models.ForeignKey(Studio, verbose_name="Studio")
    name = models.CharField("Film Name", max_length=30, unique=True)
Run Code Online (Sandbox Code Playgroud)

我有一个电影表单,允许用户选择一个预先存在的Studio,或键入一个新的:

class FilmForm(forms.Form):
    studio = forms.ModelChoiceField(Studio.objects, required=False)
    new_studio = forms.CharField(max_length=30, required=False, label = "New Studio Name")
    name = forms.CharField(max_length=30, label = "Film Name")
Run Code Online (Sandbox Code Playgroud)

验证确保new_studio名称尚不存在.如果用户输入new_studio,我想保存工作室,然后保存新的电影.

form = FilmForm(request.POST) 
if form.is_valid(): # All validation rules pass
    std = Studio(name = form.cleaned_data['new_studio'])
    std.save()
Run Code Online (Sandbox Code Playgroud)

但是,如何根据全新的工作室ID保存电影实例?我已经看过这个问题,但是如果我在电影模型和电影形式中有更多的领域呢?如果我使用链接的答案,我将必须输入每个字段:

studio = Studio.objects.get(name=request.POST['new_studio'])
newFilm=Film(name=form.name, studio=studio, field_one = form.field_one, field_two = form.field_two, etc.)
Run Code Online (Sandbox Code Playgroud)

实现这个的正确方法是什么?

Chr*_*att 5

真的,你唯一的问题是你使用的是标准Form而不是标准ModelForm.Form没有save方法,因为它本身并不与任何东西联系在一起(即它不知道要保存什么或保存到哪里).

但是,如果您使用a,则ModelForm需要处理在表单中创建新工作室所涉及的所有逻辑.这实际上更好,因为那样你就可以使用表单而不用担心其他任何事情:表单包含正确保存自身所需的所有逻辑.

class FilmForm(forms.ModelForm):
    class Meta:
        model = Film

    # only need to define `new_studio`, other fields come automatically from model
    new_studio = forms.CharField(max_length=30, required=False, label = "New Studio Name")

    def __init__(self, *args, **kwargs):
        super(FilmForm, self).__init__(*args, **kwargs)
        # make `studio` not required, we'll check for one of `studio` or `new_studio` in the `clean` method
        self.fields['studio'].required = False

    def clean(self):
        studio = self.cleaned_data.get('studio')
        new_studio = self.cleaned_data.get('new_studio')
        if not studio and not new_studio:
            # neither was specified so raise an error to user
            raise forms.ValidationError('Must specify either Studio or New Studio!')
        elif not studio:
            # get/create `Studio` from `new_studio` and use it for `studio` field
            studio, created = Studio.objects.get_or_create(name=new_studio)
            self.cleaned_data['studio'] = studio

        return super(FilmForm, self).clean()
Run Code Online (Sandbox Code Playgroud)

然后,在您看来,您所需要的只是:

if form.is_valid():
    form.save()
Run Code Online (Sandbox Code Playgroud)