当前位置:  开发笔记 > 编程语言 > 正文

Django:使用表单在一个模板中的多个模型

如何解决《Django:使用表单在一个模板中的多个模型》经验,为你挑选了5个好方法。

我正在构建支持票据跟踪应用程序,并且我想从一个页面创建一些模型.门票通过ForeignKey属于客户.Notes也通过ForeignKey属于Tickets.我想选择一个客户(这是一个完整的单独项目)或创建一个新客户,然后创建一个Ticket,最后创建一个分配给新票证的Note.

由于我是Django的新手,我倾向于迭代工作,每次尝试新功能.我玩过ModelForms,但我想隐藏一些字段并进行一些复杂的验证.看起来我正在寻找的控制级别要么需要使用formset,要么手工完成所有操作,完成一个繁琐的手工编码模板页面,我试图避免.

我有什么可爱的功能吗?有人使用formset有一个很好的参考或示例吗?我为他们花了整整一个周末的API文档,我仍然无能为力.如果我分解并手工编写所有内容,这是一个设计问题吗?



1> Jason Christ..:

使用ModelForms实现这一点并不困难.所以假设你有表格A,B和C.你打印出每个表格和页面,现在你需要处理POST.

if request.POST():
    a_valid = formA.is_valid()
    b_valid = formB.is_valid()
    c_valid = formC.is_valid()
    # we do this since 'and' short circuits and we want to check to whole page for form errors
    if a_valid and b_valid and c_valid:
        a = formA.save()
        b = formB.save(commit=False)
        c = formC.save(commit=False)
        b.foreignkeytoA = a
        b.save()
        c.foreignkeytoB = b
        c.save()

以下是自定义验证的文档.


顺便说一句,我不认为formsets是你所描述的问题的好方法.我总是用它们来表示模型的多个实例.例如,您有申请表,并且您希望3个引用您制作一个包含3个Reference模型实例的formset.

2> Gnudiff..:

我前一天刚好处于同样的情况,这是我的2美分:

1)我发现可以说是单一形式的多个模型输入的最短和最简洁的演示:http://collingrady.wordpress.com/2008/02/18/editing-multiple-objects-in-django-with-newforms/.

简而言之:为每个模型创建一个表单

,使用prefixkeyarg 将它们一起提交到模板中,并使视图句柄验证.如果存在依赖关系,只需确保在依赖之前保存"父"模型,并在提交保存"子"模型之前使用父标识的外键.该链接有演示.

2)也许表单集可打成了这样做,但据我的钻研,表单集主要用于输入相同的模型,它的倍数可能 /模型由外键可以任意捆绑到另一种模式.但是,似乎没有用于输入多个模型数据的默认选项,而且这不是什么formset似乎意味着.



3> 小智..:

我最近遇到了一些问题,并且想出了如何做到这一点.假设你有三个类,Primary,B,C和B,C有一个主键的外键

    class PrimaryForm(ModelForm):
        class Meta:
            model = Primary

    class BForm(ModelForm):
        class Meta:
            model = B
            exclude = ('primary',)

    class CForm(ModelForm):
         class Meta:
            model = C
            exclude = ('primary',)

    def generateView(request):
        if request.method == 'POST': # If the form has been submitted...
            primary_form = PrimaryForm(request.POST, prefix = "primary")
            b_form = BForm(request.POST, prefix = "b")
            c_form = CForm(request.POST, prefix = "c")
            if primary_form.is_valid() and b_form.is_valid() and c_form.is_valid(): # All validation rules pass
                    print "all validation passed"
                    primary = primary_form.save()
                    b_form.cleaned_data["primary"] = primary
                    b = b_form.save()
                    c_form.cleaned_data["primary"] = primary
                    c = c_form.save()
                    return HttpResponseRedirect("/viewer/%s/" % (primary.name))
            else:
                    print "failed"

        else:
            primary_form = PrimaryForm(prefix = "primary")
            b_form = BForm(prefix = "b")
            c_form = Form(prefix = "c")
     return render_to_response('multi_model.html', {
     'primary_form': primary_form,
     'b_form': b_form,
     'c_form': c_form,
      })

此方法应该允许您执行所需的任何验证,以及在同一页面上生成所有三个对象.我还使用了javascript和隐藏字段来允许在同一页面上生成多个B,C对象.


在此示例中,如何将模型B和C的外键设置为指向主模型?

4> jozxyqk..:

该MultiModelForm从django-betterforms是一个方便的包装做的是在描述Gnudiff的答案.它将常规ModelForms 包装在单个类中,透明地(至少对于基本用法)用作单个表单.我从下面的文档中复制了一个示例.

# forms.py
from django import forms
from django.contrib.auth import get_user_model
from betterforms.multiform import MultiModelForm
from .models import UserProfile

User = get_user_model()

class UserEditForm(forms.ModelForm):
    class Meta:
        fields = ('email',)

class UserProfileForm(forms.ModelForm):
    class Meta:
        fields = ('favorite_color',)

class UserEditMultiForm(MultiModelForm):
    form_classes = {
        'user': UserEditForm,
        'profile': UserProfileForm,
    }

# views.py
from django.views.generic import UpdateView
from django.core.urlresolvers import reverse_lazy
from django.shortcuts import redirect
from django.contrib.auth import get_user_model
from .forms import UserEditMultiForm

User = get_user_model()

class UserSignupView(UpdateView):
    model = User
    form_class = UserEditMultiForm
    success_url = reverse_lazy('home')

    def get_form_kwargs(self):
        kwargs = super(UserSignupView, self).get_form_kwargs()
        kwargs.update(instance={
            'user': self.object,
            'profile': self.object.profile,
        })
        return kwargs



5> Paul Bormans..:

我目前有一个解决方法功能(它通过我的单元测试).当你只想从其他模型中添加有限数量的字段时,这是一个很好的解决方案.

我在这里错过了什么吗?

class UserProfileForm(ModelForm):
    def __init__(self, instance=None, *args, **kwargs):
        # Add these fields from the user object
        _fields = ('first_name', 'last_name', 'email',)
        # Retrieve initial (current) data from the user object
        _initial = model_to_dict(instance.user, _fields) if instance is not None else {}
        # Pass the initial data to the base
        super(UserProfileForm, self).__init__(initial=_initial, instance=instance, *args, **kwargs)
        # Retrieve the fields from the user model and update the fields with it
        self.fields.update(fields_for_model(User, _fields))

    class Meta:
        model = UserProfile
        exclude = ('user',)

    def save(self, *args, **kwargs):
        u = self.instance.user
        u.first_name = self.cleaned_data['first_name']
        u.last_name = self.cleaned_data['last_name']
        u.email = self.cleaned_data['email']
        u.save()
        profile = super(UserProfileForm, self).save(*args,**kwargs)
        return profile

推荐阅读
依然-狠幸福
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有