24

2つのフォームがある場合:

class ContactForm(forms.Form):
    name = forms.CharField()
    message = forms.CharField(widget=forms.Textarea)

class SocialForm(forms.Form):
    name = forms.CharField()
    message = forms.CharField(widget=forms.Textarea)

クラスベースのビューを使用して、両方のフォームをテンプレートに送信したいのですが、それも可能ですか?

class TestView(FormView):
    template_name = 'contact.html'
    form_class = ContactForm

FormViewは一度に1つのフォームしか受け入れることができないようです。関数ベースのビューでは、2つのフォームをテンプレートに簡単に送信し、request.POST内で両方のコンテンツを取得できます。

variables = {'contact_form':contact_form, 'social_form':social_form }
return render(request, 'discussion.html', variables)

これは、クラスベースのビュー(汎用ビュー)を使用する際の制限ですか?

どうもありがとう

4

7 に答える 7

26

既定では、クラス ベースのビューは、ビューごとに 1 つのフォームのみをサポートします。しかし、必要なことを達成する方法は他にもあります。ただし、これは両方のフォームを同時に処理することはできません。これは、通常のフォームだけでなく、ほとんどのクラスベースのビューでも機能します。

ビュー.py

class MyClassView(UpdateView):

    template_name = 'page.html'
    form_class = myform1
    second_form_class = myform2
    success_url = '/'

    def get_context_data(self, **kwargs):
        context = super(MyClassView, self).get_context_data(**kwargs)
        if 'form' not in context:
            context['form'] = self.form_class(request=self.request)
        if 'form2' not in context:
            context['form2'] = self.second_form_class(request=self.request)
        return context

    def get_object(self):
        return get_object_or_404(Model, pk=self.request.session['value_here'])

    def form_invalid(self, **kwargs):
        return self.render_to_response(self.get_context_data(**kwargs))

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        if 'form' in request.POST:
            form_class = self.get_form_class()
            form_name = 'form'
        else:
            form_class = self.second_form_class
            form_name = 'form2'

        form = self.get_form(form_class)

        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(**{form_name: form})

テンプレート

<form method="post">
    {% csrf_token %}
    .........
    <input type="submit" name="form" value="Submit" />
</form>

<form method="post">
    {% csrf_token %}
    .........
    <input type="submit" name="form2" value="Submit" />
</form>
于 2013-03-19T12:15:25.137 に答える
13

1 つのクラスベースのビューで、一度に 2 つのフォームを受け入れることができます。

view.py

class TestView(FormView):
    template_name = 'contact.html'
    def get(self, request, *args, **kwargs):
        contact_form = ContactForm()
        contact_form.prefix = 'contact_form'
        social_form = SocialForm()
        social_form.prefix = 'social_form'
        # Use RequestContext instead of render_to_response from 3.0
        return self.render_to_response(self.get_context_data({'contact_form': contact_form, 'social_form': social_form}))

    def post(self, request, *args, **kwargs):
        contact_form = ContactForm(self.request.POST, prefix='contact_form')
        social_form = SocialForm(self.request.POST, prefix='social_form ')

        if contact_form.is_valid() and social_form.is_valid():
            ### do something
            return HttpResponseRedirect(>>> redirect url <<<)
        else:
            return self.form_invalid(contact_form,social_form , **kwargs)


    def form_invalid(self, contact_form, social_form, **kwargs):
        contact_form.prefix='contact_form'
        social_form.prefix='social_form'

        return self.render_to_response(self.get_context_data({'contact_form': contact_form, 'social_form': social_form}))

フォーム.py

from django import forms
from models import Social, Contact
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit, Button, Layout, Field, Div
from crispy_forms.bootstrap import (FormActions)

class ContactForm(forms.ModelForm):
    class Meta:
        model = Contact
    helper = FormHelper()
    helper.form_tag = False

class SocialForm(forms.Form):
    class Meta:
        model = Social
    helper = FormHelper()
    helper.form_tag = False

HTML

外部フォーム クラスを 1 つ取得し、アクションを TestView Url として設定します

{% load crispy_forms_tags %}
<form action="/testview/" method="post">
  <!----- render your forms here -->
  {% crispy contact_form %}
  {% crispy social_form%}
  <input type='submit' value="Save" />
</form>

幸運を

于 2015-05-08T05:38:02.457 に答える
2

に基づいて、次の一般的なビューを使用しましたTemplateView

def merge_dicts(x, y):
    """
    Given two dicts, merge them into a new dict as a shallow copy.
    """
    z = x.copy()
    z.update(y)
    return z


class MultipleFormView(TemplateView):
    """
    View mixin that handles multiple forms / formsets.
    After the successful data is inserted ``self.process_forms`` is called.
    """
    form_classes = {}

    def get_context_data(self, **kwargs):
        context = super(MultipleFormView, self).get_context_data(**kwargs)
        forms_initialized = {name: form(prefix=name)
                             for name, form in self.form_classes.items()}

        return merge_dicts(context, forms_initialized)

    def post(self, request):
        forms_initialized = {
            name: form(prefix=name, data=request.POST)
            for name, form in self.form_classes.items()}

        valid = all([form_class.is_valid()
                     for form_class in forms_initialized.values()])
        if valid:
            return self.process_forms(forms_initialized)
        else:
            context = merge_dicts(self.get_context_data(), forms_initialized)
            return self.render_to_response(context)

    def process_forms(self, form_instances):
        raise NotImplemented

これには、再利用可能で、すべての検証がフォーム自体で行われるという利点があります。

その後、次のように使用されます。

class AddSource(MultipleFormView):
    """
    Custom view for processing source form and seed formset
    """
    template_name = 'add_source.html'
    form_classes = {
        'source_form': forms.SourceForm,
        'seed_formset': forms.SeedFormset,
    }

    def process_forms(self, form_instances):
        pass # saving forms etc
于 2015-03-27T01:06:57.160 に答える
1

これは、クラス ベースのビューの制限ではありません。ジェネリック FormView は、2 つのフォームを受け入れるようには設計されていません (まあ、ジェネリックです)。それをサブクラス化するか、独自のクラスベースのビューを記述して 2 つのフォームを受け入れることができます。

于 2013-03-19T11:25:39.450 に答える