Django:基于类的视图一次可以接受两种形式吗?

Hou*_*man 17 django django-class-based-views django-1.5

如果我有两种形式:

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

并且想要使用基于类的视图,并将两个表单发送到模板,是否可能?

class TestView(FormView):
    template_name = 'contact.html'
    form_class = ContactForm
Run Code Online (Sandbox Code Playgroud)

看起来FormView一次只能接受一个表单.在基于函数的视图中,虽然我可以轻松地将两个表单发送到我的模板并在request.POST中检索两者的内容.

variables = {'contact_form':contact_form, 'social_form':social_form }
return render(request, 'discussion.html', variables)
Run Code Online (Sandbox Code Playgroud)

这是使用基于类的视图(通用视图)的限制吗?

非常感谢

jam*_*mes 33

这是一个可扩展的解决方案.我的出发点是这个要点,

https://gist.github.com/michelts/1029336

我已经增强了该解决方案,以便可以显示多个表单,但可以提交全部或个人

https://gist.github.com/jamesbrobb/748c47f46b9bd224b07f

这是一个示例用法

class SignupLoginView(MultiFormsView):
    template_name = 'public/my_login_signup_template.html'
    form_classes = {'login': LoginForm,
                    'signup': SignupForm}
    success_url = 'my/success/url'

    def get_login_initial(self):
        return {'email':'dave@dave.com'}

    def get_signup_initial(self):
        return {'email':'dave@dave.com'}

    def get_context_data(self, **kwargs):
        context = super(SignupLoginView, self).get_context_data(**kwargs)
        context.update({"some_context_value": 'blah blah blah',
                        "some_other_context_value": 'blah'})
        return context

    def login_form_valid(self, form):
        return form.login(self.request, redirect_url=self.get_success_url())

    def signup_form_valid(self, form):
        user = form.save(self.request)
        return form.signup(self.request, user, self.get_success_url())
Run Code Online (Sandbox Code Playgroud)

模板看起来像这样

<form class="login" method="POST" action="{% url 'my_view' %}">
    {% csrf_token %}
    {{ forms.login.as_p }}

    <button name='action' value='login' type="submit">Sign in</button>
</form>

<form class="signup" method="POST" action="{% url 'my_view' %}">
    {% csrf_token %}
    {{ forms.signup.as_p }}

    <button name='action' value='signup' type="submit">Sign up</button>
</form>
Run Code Online (Sandbox Code Playgroud)

在模板上需要注意的一件重要事情是提交按钮.他们必须将'name'属性设置为'action',并且他们的'value'属性必须与'form_classes'dict中给表单的名称相匹配.这用于确定已提交的个人表单.


cat*_*ine 20

默认情况下,基于类的视图仅支持每个视图一个表单.但还有其他方法可以满足您的需求.但同样,这不能同时处理这两种形式.这也适用于大多数基于类的视图以及常规表单.

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

模板

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


Nar*_*ary 11

一个基于类的视图可以一次接受两个表单.

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

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

HTML

获取一个外部表单类并将操作设置为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>
Run Code Online (Sandbox Code Playgroud)

祝好运


Mar*_*rat 1

这不是基于阶级的观点的限制。通用 FormView 的设计目的不是接受两种表单(好吧,它是通用的)。您可以对其进行子类化或编写自己的基于类的视图来接受两种形式。