我正在试验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>
我做错了吗?我该怎么做才能得到预期的结果?
答案 0 :(得分:2)
我也能够复制这个问题。虽然我对行为并不是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。