簡體   English   中英

單個 Django ModelForm 中的多個模型?

[英]Multiple Models in a single django ModelForm?

django 的單個ModelForm中是否可以包含多個模型? 我正在嘗試創建個人資料編輯表單。 所以我需要包含來自 User 模型UserProfile 模型的一些字段。 目前我正在使用 2 種這樣的表格

class UserEditForm(ModelForm):

    class Meta:
        model = User
        fields = ("first_name", "last_name")

class UserProfileForm(ModelForm):

    class Meta:
        model = UserProfile
        fields = ("middle_name", "home_phone", "work_phone", "cell_phone")

有沒有辦法將這些合並成一種形式,或者我只需要創建一個形式並處理數據庫加載和保存自己?

您可以只在一個<form> html 元素內的模板中顯示兩種表單。 然后只需在視圖中單獨處理表單。 您仍然可以使用form.save()而不必自己處理數據庫加載和保存。

在這種情況下,您不需要它,但如果您要使用具有相同字段名稱的表單,請查看 django 表單的prefix kwarg。 (我在這里回答了一個問題)。

您可以嘗試使用這段代碼:

class CombinedFormBase(forms.Form):
    form_classes = []

    def __init__(self, *args, **kwargs):
        super(CombinedFormBase, self).__init__(*args, **kwargs)
        for f in self.form_classes:
            name = f.__name__.lower()
            setattr(self, name, f(*args, **kwargs))
            form = getattr(self, name)
            self.fields.update(form.fields)
            self.initial.update(form.initial)

    def is_valid(self):
        isValid = True
        for f in self.form_classes:
            name = f.__name__.lower()
            form = getattr(self, name)
            if not form.is_valid():
                isValid = False
        # is_valid will trigger clean method
        # so it should be called after all other forms is_valid are called
        # otherwise clean_data will be empty
        if not super(CombinedFormBase, self).is_valid() :
            isValid = False
        for f in self.form_classes:
            name = f.__name__.lower()
            form = getattr(self, name)
            self.errors.update(form.errors)
        return isValid

    def clean(self):
        cleaned_data = super(CombinedFormBase, self).clean()
        for f in self.form_classes:
            name = f.__name__.lower()
            form = getattr(self, name)
            cleaned_data.update(form.cleaned_data)
        return cleaned_data

示例用法:

class ConsumerRegistrationForm(CombinedFormBase):
    form_classes = [RegistrationForm, ConsumerProfileForm]

class RegisterView(FormView):
    template_name = "register.html"
    form_class = ConsumerRegistrationForm

    def form_valid(self, form):
        # some actions...
        return redirect(self.get_success_url())

erikbwork 和我都有一個問題,即只能將一個模型包含到通用的基於類的視圖中。 我找到了一種與 Miao 類似的方法,但更加模塊化。

我寫了一個 Mixin,所以你可以使用所有通用的基於類的視圖。 定義模型、字段以及 child_model 和 child_field - 然后您可以將兩個模型的字段包裝在 Zach 描述的標簽中。

class ChildModelFormMixin: 
    ''' extends ModelFormMixin with the ability to include ChildModelForm '''
    child_model = ""
    child_fields = ()
    child_form_class = None

    def get_child_model(self):
        return self.child_model

    def get_child_fields(self):
        return self.child_fields

    def get_child_form(self):
        if not self.child_form_class:
            self.child_form_class = model_forms.modelform_factory(self.get_child_model(), fields=self.get_child_fields())
        return self.child_form_class(**self.get_form_kwargs())

    def get_context_data(self, **kwargs):
        if 'child_form' not in kwargs:
            kwargs['child_form'] = self.get_child_form()
        return super().get_context_data(**kwargs)

    def post(self, request, *args, **kwargs):
        form = self.get_form()
        child_form = self.get_child_form()

        # check if both forms are valid
        form_valid = form.is_valid()
        child_form_valid = child_form.is_valid()

        if form_valid and child_form_valid:
            return self.form_valid(form, child_form)
        else:
            return self.form_invalid(form)

    def form_valid(self, form, child_form):
        self.object = form.save()
        save_child_form = child_form.save(commit=False)
        save_child_form.course_key = self.object
        save_child_form.save()

        return HttpResponseRedirect(self.get_success_url())

示例用法:

class ConsumerRegistrationUpdateView(UpdateView):
    model = Registration
    fields = ('firstname', 'lastname',)
    child_model = ConsumerProfile
    child_fields = ('payment_token', 'cart',)

或使用 ModelFormClass:

class ConsumerRegistrationUpdateView(UpdateView):
    model = Registration
    fields = ('firstname', 'lastname',)
    child_model = ConsumerProfile
    child_form_class = ConsumerProfileForm

完畢。 希望能幫助某人。

您可能應該看看Inline formsets 當您的模型通過外鍵關聯時,將使用內聯表單集。

我在我的項目中使用了django BetterformsMultiForm 和 MultiModelForm 不過,代碼可以改進。 例如,它依賴於 3.+ 不支持的 django.six,但所有這些都可以輕松修復

這個問題在 StackOverflow 中已經出現過好幾次了,所以我認為是時候找到一種標准化的方法來解決這個問題了。

您可以在此處查看我的答案以了解類似問題。

它討論了如何將注冊和用戶配置文件組合到一個表單中,但它可以推廣到任何 ModelForm 組合。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM