【问题标题】:Django - Add row to formset in class based view WITHOUT javascriptDjango - 在没有 javascript 的基于类的视图中向表单集添加行
【发布时间】:2014-09-06 12:34:41
【问题描述】:

我正在尝试使用内联表单集创建基于类的表单视图。我想要一个“添加”按钮,它将向表单集添加一个新行,并且我希望它可以在没有 javascript 的情况下工作。

我找到了一些有用的网站,这些网站让我可以创建一些粗略的代码(如下)。
https://stackoverflow.com/a/11910420/3800244:提供了一种优雅/干燥的方法来将表单集添加到 CBV。
http://pytipz.blogspot.com.au/2012/09/django-adding-inline-formset-rows.html:展示了如何在视图中向表单集添加行,但它似乎是针对基于函数的视图。

我的用例是一个纸牌游戏网站。我有一张牌桌、一张牌桌和一张牌桌。卡片表充满了数据,当人们创建卡片组时,他们需要能够为该卡片组选择卡片(都在同一页面/表单上)。这是我到目前为止的一些粗略代码;

models.py

class Card(models.Model):
    title = models.CharField()

class Deck(models.Model):
    title = models.CharField() 

class CardsInDeck(models.Model):
    deck = models.ForeignKey(Deck)
    card = models.ForeignKey(Card)
    quantity = models.PositiveSmallIntegerField(blank=False, default=1)

forms.py

class DeckForm(forms.ModelForm):
    class Meta:
        model = Deck

CardsInDeckFormSet = inlineformset_factory(Deck, CardsInDeck, extra=1)

views.py

class Deck_FormView(generic.edit.FormView):
    template_name = 'create_deck.html'
    model = Deck
    form_class = DeckForm

    success_url = 'viewdeck' #just an example

    def get_formsets(self):
        return {
            'cards': CardsInDeckFormSet(self.request.POST or None, prefix='cards'),
        }

    def get_context_data(self, **kwargs):
        context = super(Deck_FormView, self).get_context_data(**kwargs)
        context['formsets'] = self.get_formsets()
        return context

    def post(self, request, *args, **kwargs):

        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)

        if 'add_card' in request.POST:
            request.POST = request.POST.copy()
            request.POST['cards-TOTAL_FORMS'] = int(request.POST['cards-TOTAL_FORMS']) + 1
            return self.render_to_response(self.get_context_data(form=form))


        formsets = self.get_formsets()
        if (form.is_valid() and all((f.is_valid() for f in formsets.values()))):
            return self.form_valid(form, formsets)
        else:
            return self.form_invalid(form)

    def form_valid(self, form, formsets):
        self.object = form.save()

        for name, formset in 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 HttpResponseRedirect(self.get_success_url())

    def formset_cards_valid(self, formset):
        cards_formsets = formset.save(commit=False)
        for i in cards_formsets:
            i.deck = self.object
            i.save()

create_deck.html

<form action="" method="post">
    {% csrf_token %}
    {{ form.as_p }}

    <fieldset>
        <legend>Cards in deck</legend>
        {{ formsets.cards.management_form }}

        {% for form in formsets.cards %}
            {{ form.id }}
            <div class="inline {{ formsets.cards.prefix }}">
                {{ form }}
            </div>
        {% endfor %}

        <input type='submit' name='add_card' value="Add another card" />
    </fieldset>

    <br>

    <input type='hidden' name='action' value="deck">
    <input type='submit' name='submit' value="Save Deck" />

</form>

所以我的代码使用了我最初引用的方法。它显示表单和表单集,单击“添加”按钮会重新加载带有额外表单集行的页面。保存也可以。
问题是;创建新行时没有任何“默认值”(即在卡选择输入中未选择任何内容,并且未在数字输入中输入默认数量 1)。此外,新的“空”行通过验证,HTML 呈现“此字段是必需的”。每个字段的错误。

我想解决这些问题,使其对用户更实用。我不知道该怎么做。我想知道它是否与将 is_bound 设置为表单/表单集有关?我也相信以下链接可能是相关的,但我不知道如何实现它(如果确实是解决方案):Django class based views and formsets

【问题讨论】:

    标签: django django-forms django-views django-class-based-views


    【解决方案1】:

    我通过“手动”设置新表单集表单的每个字段的属性找到了解决方案。这是修改后的def post

    def post(self, request, *args, **kwargs):
    
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
    
        formsets = self.get_formsets()
    
        if 'add_card' in request.POST:
            request.POST = request.POST.copy()
            request.POST['cards-TOTAL_FORMS'] = int(request.POST['cards-TOTAL_FORMS']) + 1
    
            # This is the new block of code that loops over each base field,
            # and uses the initial values provided.
            new_formset_id = request.POST['cards-TOTAL_FORMS'] - 1
            for field in formsets['cards'].empty_form.base_fields:
                request.POST['cards-{0}-{1}'.format(new_formset_id, field)] = formsets['cards'].empty_form.base_fields[field].initial
    
            return self.render_to_response(self.get_context_data(form=form))
    
        if (form.is_valid() and all((f.is_valid() for f in formsets.values()))):
            return self.form_valid(form, formsets)
        else:
            return self.form_invalid(form)
    

    这在添加表单时不会出现验证错误。保存主表单后,这些空/默认表单集表单将被忽略。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-03
      • 2010-12-29
      • 2015-07-26
      • 2011-09-18
      • 2011-05-28
      • 2011-01-27
      • 2021-09-27
      • 1970-01-01
      相关资源
      最近更新 更多