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理界面)。
要点是:
-
使用
inlineformset_factory
在forms.py
生成inlineformset_factory
:BookImageFormSet = inlineformset_factory(BookForm, BookImage, extra=2) BookPageFormSet = inlineformset_factory(BookForm, BookPage, extra=5)
-
在
views.py
的CreateView
类中返回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
-
使用
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_data
和form_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 。 查找CreateWithInlinesView
和UpdateWithInlinesView
。
我红色的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