具有内联模型表单或formset的基于类的基于django的视图

Hix*_*ixi 55 django inline-formset django-class-based-views

我有以下型号:

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")
Run Code Online (Sandbox Code Playgroud)

我知道这是可能的:

from django.forms.models import inlineformset_factory
inlineformset_factory(Bill, Item)
Run Code Online (Sandbox Code Playgroud)

然后通过标准视图处理.

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

Jor*_*ter 63

要点是:

  1. FormSetforms.py使用中生成的inlineformset_factory:

    BookImageFormSet = inlineformset_factory(BookForm, BookImage, extra=2)
    BookPageFormSet = inlineformset_factory(BookForm, BookPage, extra=5)
    
    Run Code Online (Sandbox Code Playgroud)
  2. FormSet在一个CreateView班级中返回s views.py:

    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
    
    Run Code Online (Sandbox Code Playgroud)
  3. 用于form_valid保存表单和formset:

     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))
    
    Run Code Online (Sandbox Code Playgroud)

  • *form_valid*似乎是错误的地方,因为它通常在表单验证后调用.我认为重写*post*将是更清洁的解决方案. (5认同)
  • 该示例导致在表单无效时重新创建表单集(请参阅`self.get_context_data(form = form)` - 这不是问题,直到您在formset中出现非表单错误,当您调用`formset时出现.is_valid()`(访问`formset.errors`,导致实例化错误列表).重用formset的解决方案(将其传递给`get_context_data`并在`get_context_data`中检查是否提供了,只有当它没有时才添加它...或者像之前的评论所说的那样使用`post`,这将导致自然地重复使用formset). (5认同)
  • 虽然我认为解决方案是合理的,但在`get_context_data()`中检查请求方法没有多大意义.基于Django源中的`ProcessFormView`,`get()`和`post()`方法是你应该实例化你的表单并将它们添加到`get_context_data(form = form)`调用的地方. (4认同)
  • 我认为它是'self.object`,而不是`self.instance` (3认同)
  • 派对有点晚了,但这对我有用,@ orokusaki对'self.object`而不是'self.instance`是正确的. (3认同)
  • 这里似乎有一个更好的处理方法:http://kevindias.com/writing/django-class-based-views-multiple-inline-formsets/但似乎还有很多工作要做,只是创建当时复制进行编辑,如果你有多个具有相同设置的模型,这开始变得很多维护(这是CBV应该帮助的,不是吗?).这是在Django 1.7中解决的吗? (3认同)

Yuj*_*ita 14

在查看了一些预先制作的CBV后,我刚刚添加了自己的版本.我特别需要multiple formsets -> one parent在单个视图中进行控制,每个视图都有单独的保存功能.

我基本上将FormSet数据绑定填充到一个get_named_formsetsget_context_dataand 调用的函数中form_valid.

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

模板通过渲染formset

{% with named_formsets.my_specific_formset as formset %}
 {{ formset }}
 {{ formset.management_form }}
{% endwith %}
Run Code Online (Sandbox Code Playgroud)

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

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()
Run Code Online (Sandbox Code Playgroud)

  • 这很干净.我喜欢它 :) (2认同)

Udi*_*Udi 9

你应该试试django-extra-views.寻找CreateWithInlinesViewUpdateWithInlinesView.