django基于类的视图与内联模型或formset

我有以下型号:

class Bill(models.Model): date = models.DateTimeField(_("Date of bill"),null=True,blank=True) class Item(models.Model): name = models.CharField(_("Name"),max_length=100) price = models.FloatField(_("Price")) quantity = models.IntegerField(_("Quantity")) bill = models.ForeignKey("Bill",verbose_name=_("Bill"), related_name="billitem") 

我知道这是可能的:

 from django.forms.models import inlineformset_factory inlineformset_factory(Bill, Item) 

然后通过标准视图进行处理。

现在我想知道,如果有一种方法来实现相同(意思是:使用内联添加/编辑属于一个账单的项目)使用基于类的视图 (而不是pipe理界面)。

要点是:

  1. 使用inlineformset_factoryforms.py生成inlineformset_factory

     BookImageFormSet = inlineformset_factory(BookForm, BookImage, extra=2) BookPageFormSet = inlineformset_factory(BookForm, BookPage, extra=5) 
  2. views.pyCreateView类中返回FormSet

     def get_context_data(self, **kwargs): context = super(BookCreateView, self).get_context_data(**kwargs) if self.request.POST: context['bookimage_form'] = BookImageFormSet(self.request.POST) context['bookpage_form'] = BookPageFormSet(self.request.POST) else: context['bookimage_form'] = BookImageFormSet() context['bookpage_form'] = BookPageFormSet() return context 
  3. 使用form_valid来保存表单和表单集:

      def form_valid(self, form): context = self.get_context_data() bookimage_form = context['bookimage_formset'] bookpage_form = context['bookpage_formset'] if bookimage_form.is_valid() and bookpage_form.is_valid(): self.object = form.save() bookimage_form.instance = self.object bookimage_form.save() bookpage_form.instance = self.object bookpage_form.save() return HttpResponseRedirect('thanks/') else: return self.render_to_response(self.get_context_data(form=form)) 

我在检查了一些预制的CBV后,添加了自己的版本。 我特别需要控制multiple formsets -> one parent单个视图中的每个单独的保存function的multiple formsets -> one parent

我基本上填充了FormSet数据绑定到get_context_dataform_valid调用的get_context_data form_valid

在那里,我检查是否所有的表单都是有效的,并且在每个表单集合的基础上寻找一个覆盖一个普通的旧的formset.save()来自定义保存的方法。

模板通过渲染formset

 {% with named_formsets.my_specific_formset as formset %} {{ formset }} {{ formset.management_form }} {% endwith %} 

我想我会定期使用这个系统。

 class MyView(UpdateView): # FormView, CreateView, etc def get_context_data(self, **kwargs): ctx = super(MyView, self).get_context_data(**kwargs) ctx['named_formsets'] = self.get_named_formsets() return ctx def get_named_formsets(self): return { 'followup': FollowUpFormSet(self.request.POST or None, prefix='followup'), 'action': ActionFormSet(self.request.POST or None, prefix='action'), } def form_valid(self, form): named_formsets = self.get_named_formsets() if not all((x.is_valid() for x in named_formsets.values())): return self.render_to_response(self.get_context_data(form=form)) self.object = form.save() # for every formset, attempt to find a specific formset save function # otherwise, just save. for name, formset in named_formsets.items(): formset_save_func = getattr(self, 'formset_{0}_valid'.format(name), None) if formset_save_func is not None: formset_save_func(formset) else: formset.save() return http.HttpResponseRedirect('') def formset_followup_valid(self, formset): """ Hook for custom formset saving.. useful if you have multiple formsets """ followups = formset.save(commit=False) # self.save_formset(formset, contact) for followup in followups: followup.who = self.request.user followup.contact = self.object followup.save() 

你应该试试django-extra-views 。 查找CreateWithInlinesViewUpdateWithInlinesView

我红色的1.3-β-1的通用源代码:

代码是绝对没有准备好列表编辑或有一些黑魔法在这里。 但我认为这可以很快实施。

如果您查看django.view.generic.edit(支持详细对象编辑)模块如何使用django.view.generic.detail模块。

我认为,一个django.view.generic.list_edit模块可以使用django.view.generic.list和django.view.generic.edit的一些部分来实现。

我对原始解决scheme做了一些修改,让formset.is_valid()工作:

  if self.request.POST: context['fs'] = MyInlineFS(self.request.POST, instance=self.object) else: context['fs'] = MyInlineFS(instance=self.object) 

乔丹答案中的代码对我来说并不合适。 我发布了自己的问题 ,我相信我现在已经解决了。 inlineformset_factory的第一个参数应该是Book, 而不是 BookForm。

为了在模板上下文中存在get_context_data()我需要对Jordan和Speq的视图的get_context_data()做一个更多的修改。

 ... if self.request.POST: context['fs'] = MyInlineFS(self.request.POST, instance=self.object) context['fs'].full_clean() # <-- new else: context['fs'] = MyInlineFS(instance=self.object) return context