【问题标题】:Django Crispy Forms, Twitter Bootstrap, and Formsets with form-inlineDjango Crispy Forms、Twitter Bootstrap 和 Formsets with form-inline
【发布时间】:2013-08-01 06:49:49
【问题描述】:

我正在试验django-crispy-forms 和 Twitter Bootstrap,这是 django-crispy-forms 用作其默认模板包的。我正在使用 Django 1.4.5、django-crispy-forms 1.2.3 和 Twitter Bootstrap 2.3.2。

相关代码

urls.py

from django.conf.urls import patterns, url
from core import views

urlpatterns = patterns('',
    url(r'^$', views.Survey.as_view(), name='survey'),
)

views.py

from django.views.generic.edit import FormView
from .forms import SurveyFormset


class Survey(FormView):
    form_class = SurveyFormset
    template_name = 'survey.html'

forms.py

from django import forms
from django.forms.formsets import formset_factory
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit


class SurveyForm(forms.Form):
    def __init__(self, *args, **kwargs):
        self.helper = FormHelper()
        self.helper.form_action = '.'
        self.helper.form_class = 'form-inline'

        self.helper.add_input(Submit('submit', 'Submit'))
        super(SurveyForm, self).__init__(*args, **kwargs)

    name = forms.CharField(
        widget=forms.TextInput(attrs={'placeholder': 'Name'}),
        label='',
        max_length=50
    )

    favorite_food = forms.CharField(
        widget=forms.TextInput(attrs={'placeholder': 'Favorite food'}),
        label='',
        max_length=50
    )

    favorite_game = forms.CharField(
        widget=forms.TextInput(attrs={'placeholder': 'Favorite game'}),
        label='',
        max_length=50
    )

SurveyFormset = formset_factory(SurveyForm, extra=2)

survey.html

{% load crispy_forms_tags %}

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Survey</title>
        <link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">
    </head>
    <body>
        {% crispy form form.form.helper %}
    </body>
</html>

实际结果

尽管我将表单的类设置为form-inline,但表单字段都是堆叠的。这也使您无法分辨出有两种不同的形式;它看起来就像一个带有重复字段的长表单。

这是正在生成的 HTML:

<form action="." class="form-inline" method="post">
    <div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='foo' /></div>

    <div>
        <input type="hidden" name="form-TOTAL_FORMS" value="2" id="id_form-TOTAL_FORMS" />
        <input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS" />
        <input type="hidden" name="form-MAX_NUM_FORMS" value="1000" id="id_form-MAX_NUM_FORMS" />
    </div>

    <div id="div_id_form-0-name" class="control-group">
        <div class="controls">
            <input name="form-0-name" maxlength="50" placeholder="Name" type="text" class="textinput textInput" id="id_form-0-name" />
        </div>
    </div>

    <div id="div_id_form-0-favorite_food" class="control-group">
        <div class="controls">
            <input name="form-0-favorite_food" maxlength="50" placeholder="Favorite food" type="text" class="textinput textInput" id="id_form-0-favorite_food" />
        </div>
    </div>

    <div id="div_id_form-0-favorite_game" class="control-group">
        <div class="controls">
            <input name="form-0-favorite_game" maxlength="50" placeholder="Favorite game" type="text" class="textinput textInput" id="id_form-0-favorite_game" />
        </div>
    </div>

    <div id="div_id_form-1-name" class="control-group">
        <div class="controls">
            <input name="form-1-name" maxlength="50" placeholder="Name" type="text" class="textinput textInput" id="id_form-1-name" />
        </div>
    </div>

    <div id="div_id_form-1-favorite_food" class="control-group">
        <div class="controls">
            <input name="form-1-favorite_food" maxlength="50" placeholder="Favorite food" type="text" class="textinput textInput" id="id_form-1-favorite_food" />
        </div>
    </div>

    <div id="div_id_form-1-favorite_game" class="control-group">
        <div class="controls">
            <input name="form-1-favorite_game" maxlength="50" placeholder="Favorite game" type="text" class="textinput textInput" id="id_form-1-favorite_game" />
        </div>
    </div>

    <div class="form-actions">
        <input type="submit" name="submit" value="Submit" class="btn btn-primary" id="submit-id-submit" />
    </div>
</form>

预期结果

由于 Twitter Bootstrap 是 django-crispy-forms 使用的默认模板包,我希望它默认能够很好地处理这个问题。这些字段应该并排,而不是堆叠,并且应该很明显有两种不同的形式。

我希望 HTML 看起来像这样:

<form action="." class="form-inline" method="post">
    <div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='foo' /></div>

    <div>
        <input type="hidden" name="form-TOTAL_FORMS" value="2" id="id_form-TOTAL_FORMS" />
        <input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS" />
        <input type="hidden" name="form-MAX_NUM_FORMS" value="1000" id="id_form-MAX_NUM_FORMS" />
    </div>

    <div id="id_form-0" class="control-group">
        <input type="text" id="id_form-0-name" class="textinput textInput" placeholder="Name" maxlength="50" name="form-0-name">
        <input type="text" id="id_form-0-favorite_food" class="textinput textInput" placeholder="Favorite food" maxlength="50" name="form-0-favorite_food">
        <input type="text" id="id_form-0-favorite_game" class="textinput textInput" placeholder="Favorite game" maxlength="50" name="form-0-favorite_game">
    </div>

    <div id="id_form-1" class="control-group">
        <input type="text" id="id_form-1-name" class="textinput textInput" placeholder="Name" maxlength="50" name="form-1-name">
        <input type="text" id="id_form-1-favorite_food" class="textinput textInput" placeholder="Favorite food" maxlength="50" name="form-1-favorite_food">
        <input type="text" id="id_form-1-favorite_game" class="textinput textInput" placeholder="Favorite game" maxlength="50" name="form-1-favorite_game">
    </div>

    <div class="form-actions">
        <input type="submit" name="submit" value="Submit" class="btn btn-primary" id="submit-id-submit" />
    </div>
</form>

我做错了吗?我应该怎么做才能获得预期的结果?

【问题讨论】:

    标签: django twitter-bootstrap django-crispy-forms


    【解决方案1】:

    我也能够复制这个问题。虽然我不能 100% 确定这种行为,但我能够在 django-crispy-forms documentation 中找到以下内容:

        #forms.py
        def __init__(self, *args, **kwargs):
            self.helper = FormHelper()
            self.helper.form_action = '.'
            self.helper.form_class = 'form-inline'
            self.helper.template = 'bootstrap/table_inline_formset.html'
    
            self.helper.add_input(Submit('submit', 'Submit'))
            super(SurveyForm, self).__init__(*args, **kwargs)
    
        # views.py
        from django.views.generic.edit import FormView
        from .forms import SurveyFormset, SurveyForm
    
    
        class Survey(FormView):
            form_class = SurveyForm
            template_name = 'survey.html'
    
            def get(self, request, *args, **kwargs):
                self.object = None
                form_class = self.get_form_class()
                form = self.get_form(form_class)
                formset = SurveyFormset()
                return self.render_to_response(
                    self.get_context_data(
                        form=form,
                        formset=formset,
                    )
                )
    
            def post(self, request, *args, **kwargs):
                """
                Handles POST requests, instantiating a form instance and its inline
                formsets with the passed POST variables and then checking them for
                validity.
                """
                self.object = None
                form_class = self.get_form_class()
                form = self.get_form(form_class)
                formset = SurveyFormset(self.request.POST)
                if (form.is_valid() and formset.is_valid()):
                    return self.form_valid(form, formset)
                else:
                    return self.form_invalid(form, formset)
    
            def form_valid(self, form, formset):
                """
                Called if all forms are valid. Creates a Recipe instance along with
                associated Ingredients and Instructions and then redirects to a
                success page.
                """
                self.object = form.save()
                formset.instance = self.object
                formset.save()
                return HttpResponseRedirect(self.get_success_url())
    
            def form_invalid(self, form, formset):
                """
                Called if a form is invalid. Re-renders the context data with the
                data-filled forms and errors.
                """
                return self.render_to_response(
                    self.get_context_data(
                        form=form,
                        formset=formset,
                    )
                )
    
        # survey.html
        {% load crispy_forms_tags %}
    
        <!DOCTYPE html>
        <html lang="en">
            <head>
                <meta charset="utf-8">
                <title>Survey</title>
                <link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">
            </head>
            <body>
                <div class="container">
                    <div class="row">
                        <div class="span12">
                            {% crispy formset formset.form.helper 'bootstrap' %}
                        </div>
                    </div>
                </div>
            </body>
        </html>
    

    虽然我对使用 div 的解决方案感到好奇,因为 django-crispy-forms 文档指出它应该可以工作,但我可以确认该解决方案在我的机器上有效。上面的部分代码归功于Kevin Dias

    【讨论】:

      猜你喜欢
      • 2022-01-04
      • 2015-08-03
      • 2015-08-29
      • 2014-05-19
      • 2012-07-01
      • 2014-04-10
      • 2019-07-31
      • 1970-01-01
      • 2015-02-19
      相关资源
      最近更新 更多