使用 CBV 在 Django 中的一个视图/模板中的两个模型表单

Posted

技术标签:

【中文标题】使用 CBV 在 Django 中的一个视图/模板中的两个模型表单【英文标题】:Two model forms in one view/template in Django using CBV 【发布时间】:2013-05-30 13:15:54 【问题描述】:

有人可以展示在一个视图/模板中使用两个模型表单的示例吗?任务是在一个 CBV 中处理多个表单,其中第二个表单的模型对第一个表单模型具有 FK,因此来自第一个表单的选择小部件的值必须作为对象的值处理,在第二个表单中创建。

我的表单如下所示:

class CompanyEditForm(ModelForm):
    name = CharField(label="Наименование", required=True)
    type = ModelChoiceField(queryset=CompanyTypes.objects.all(), label="Тип компании", empty_label=None, initial=3)
    description = CharField(label="Описание компании", required=False, widget=forms.Textarea(attrs='cols': 40, 'rows':3))
    www = CharField(label="WEB сайт", required=False)

    class Meta:
        model = Companies
        fields = ('type', 'name', 'description', 'www')


class BranchEditForm(ModelForm):
    name = CharField(label="Наименование офиса", required=True)
    type = ModelChoiceField(queryset=BranchTypes.objects.all(), label="Тип отделения", empty_label=None, initial=1)

    class Meta:
        model = Branches
        exclude = ('company', 'address')


class AddressEditForm(ModelForm):
    postalcode = IntegerField(label="Почтовый код", required=False)
    city = CharField(label="Город", required=True)
    street = CharField(label="Улица", required=True)
    app = CharField(label="Дом", required=True)
    app_extra = CharField(label="Корпус / Строение", required=False)
    comment = CharField(label="Примечание к адресу", required=False)
    exclude = ('company',)

    class Meta:
        model = Addresses
        fields = ('postalcode', 'city', 'street', 'app', 'app_extra', 'comment')

更新

我写了这个 mixin:

class MultiFormCreate(FormMixin, TemplateResponseMixin, View):
    formconf = None

    def get_form_classes(self):
        form_classes = 
        for key, params in self.formconf.items():
            form_classes[key] = params.formclass
        return self.form_classes

    def get_initial(self, classname):
        inicial = 
        if 'inicial' in self.formconf[classname]:
            inicial = self.formconf[classname]['inicial'].copy()
        return inicial

    def get_form_kwargs(self, classname):
        kwargs = 'initial': self.get_initial(classname), 'prefix': classname
        if self.request.method in ('POST', 'PUT'):
            kwargs.update(
                'data': self.request.POST,
                'files': self.request.FILES,
                )
        return kwargs

    def get_forms(self):
        for classname, params in self.formconf.items():
            log.info("Name: %s, Params: %s" % (classname, params))
        return dict(
            [(classname, params['formclass'](**self.get_form_kwargs(classname))) for classname, params in self.formconf.items()])

    def get(self, request, *args, **kwargs):
        forms = self.get_forms()
        return self.render_to_response(self.get_context_data(forms=forms))

    def get_success_url(self):
        if self.success_url:
            url = force_text(self.success_url)
        else:
            raise ImproperlyConfigured(
                "No URL to redirect to. Provide a success_url.")
        return url

那么在视图中我只需要在post中编写处理:

class CompanyCreate(MultiFormCreate):
    template_name = 'company/edit.html'
    success_url = '/forbidden/'
    formconf = 
        'company': 'formclass': CompanyEditForm, 'inicial': 'name': "TESTNAME",
        'branch': 'formclass': BranchEditForm,
        'address': 'formclass': AddressEditForm
    

    def post(self, request, *args, **kwargs):
        forms = self.get_forms()
        cform = forms['company']
        aform = forms['address']
        bform = forms['branch']
        if cform.is_valid() and aform.is_valid() and bform.is_valid():
            ''' Creating main form form object (by saving tthe form) '''
            company_object = cform.save()
            ''' Creating dependant object '''
            address_object = aform.save(commit=False)
            branch_object = bform.save(commit=False)
            ''' assigning dependent fields '''
            address_object.company = company_object
            ''' saving dependent _object_ '''
            address_object.save()
            ''' managing another dependent fields '''
            branch_object.company = company_object
            branch_object.address = address_object
            ''' saving last object '''
            branch_object.save()
            return HttpResponseRedirect(self.get_success_url())
        else:
            forms = self.get_forms()
            return self.render_to_response(self.get_context_data(forms=forms))

【问题讨论】:

您是否尝试将分支表单 (BranchEditForm) 保存在我们应该作为对象传递的公司对象中? 是的! CompanyForm 中创建的对象的 CompnayID 必须在 BranchEditForm 的保存结果中保存为“公司”,如果是“创建”视图,如果也是“编辑”视图.. 【参考方案1】:

查看文件代码:

    if request.method == "POST":
        company_form = CompanyEditForm(request.POST)
        if company_form.is_valid():
           company_object = company_form.save()
           post_data = request.POST.copy()
           branch_form = BranchEditForm(post_data)
           branch_form.data['company'] = company_object
           if branch_form.is_valid():
              branch_object.save()

休息实现你的业务逻辑..

【讨论】:

以上是关于使用 CBV 在 Django 中的一个视图/模板中的两个模型表单的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 CBV 在我的所有 Django 模板中创建侧边栏?

Django:两个模型中的一个 url 搜索(cbv)

Django中的CBV与FBV

Django中的CBV与FBV

django中cbv源码和restful规范

Flask视图函数与模板语法