I'm having an issue using several forms with django-crispy-forms for Django.
From the documentation, we must set self.helper.form_tag = False in out Form. Documentation here
Then wrapp the forms with a Form tag in the HTML.
class SearchForm(forms.Form):
X = forms.IntegerField(label='X', min_value=0, max_value=10)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper
self.helper.form_method = 'post'
self.helper.form_tag = False
self.helper.layout = Layout(
'X',
Submit('submit', 'Submit', css_class='btn-success')
)
class PredictForm(forms.Form):
Y = forms.IntegerField(label='X', min_value=0, max_value=10)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper
self.helper.form_method = 'post'
self.helper.form_tag = False
self.helper.layout = Layout(
'Y',
Submit('submit', 'Submit', css_class='btn-success')
)
Then in the HTML file I have:
<form action="my_action" class="uniForm" method="post">
<div id="box" class="box">{% crispy formSearch formSearch.helper %}</div>
<div id="box2" class="box2">{% crispy formPrediction formPrediction.helper %}</div>
</form>
In my View.py:
def index(request):
if request.method == 'POST':
formSearch = SearchForm(request.POST)
formPrediction = PredictionForm(request.POST)
# Do stuff
else
formSearch = SearchForm()
formSearch.fields['X'].initial = 5
formPrediction = PredictionForm()
formSearch.fields['Y'].initial = 5
return render(request, 'index.html', {'formSearch': formSearch}, 'formPrediction': formPrediction)
What I get is 2 crispy forms that are displayed on my web page, but the first forms tries to load the fields of the seconds forms. It seems like my second form is duplicated.
I get this error:
KeyError: "Key 'Y' not found in 'SearchForm'. Choices are: X."
It is trying to get data from PredictForm but is aware that only X is in SearchForm. I thought it was I typo somewhere, but I can't find my mistake.
Here is the answer:
A collision war made between the 2 forms, why? Because I did not initiate properly each form functions.
I have changed
self.helper = FormHelper
to
self.helper = FormHelper(self)
Related
The technical issue of styling buttons in django crispy forms. I would like to apply my own class, without using the primary button class.
class MyForm(Form):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
Fields("field_1"),
Fields("field_2"),
Submit('submit', u'On', css_class='own-css-class'),
)
Basically, I solved this by adding self.helper.form_tag = False and inserting the button code directly into the html template. In addition, I deleted the submit button from the layout.
class MyForm(Form):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
Fields("field_1"),
Fields("field_2"),
)
self.helper.form_tag = False
Is this solution correct and will it be compatible in the long term?
I'd recommend that you create your own custom button and use that when creating your layout.
class CustomButton(BaseInput)
input_type = 'submit'
field_classes = 'my custom css'
I have a one field form which I want to align horizontally and centre of page.
I want to have autofocus and placeholder enabled.
Here is my code:
class VinForm(forms.Form):
VIN = forms.CharField(max_length=17, label='VIN')
def __init__(self, *args, **kwargs):
super(VinForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_method = 'post'
#self.helper.form_class = 'form-horizontal col-xs-12 col-md-6 col-lg-5'
self.helper.form_class = 'form-horizontal'
#self.helper.form_class = 'form-inline col-md-12'
#self.helper.label_class = 'col-xs-3 col-md-3 col-lg-3'
#self.helper.field_class = 'col-xs-12 col-md-12 col-lg-12'
#self.helper.form_class = 'form-inline'
self. helper.layout = Layout(
FieldWithButtons('VIN', StrictButton("Go!"), autofocus=True, placeholder='JN1HJ01F8RT231164'),
# Div(
# Div('VIN',css_class='col-md-6',autofocus=True, placeholder='JN1HJ01F8RT231164'),
# css_class='row',
# ),
# Fieldset(
# #'Get Driving profile',
# Field('VIN', autofocus=True, placeholder='JN1HJ01F8RT231164'),
# ),
# FormActions(
# Submit('submit', 'get vehicle info'),
# ),
# )
)
you can see from my code above that I tried many things still none worked. Here is how it looks.
It lacks
1) center of page
2) inline form
3) autofocus and placeholders are not working
I am using twitter bootstrap3
I do the below. Note 'Field' in the snippet below, where we specify additional css in css_class. Here is the docs link
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
Row(
HTML('<h3>About you</h4>'),
Column(Field('computers', css_class='text-center'), css_class='col-md-12 text-center')
),
https://stackoverflow.com/a/24812832/960471
The crispy forms documentation shows how to do horizontal forms for bootstrap, perhaps that will help. http://django-crispy-forms.readthedocs.org/en/latest/crispy_tag_forms.html?highlight=horizontal#bootstrap3-horizontal-forms
I'm trying to conditionally set an initial value on a crispy forms InlineRadio field, and am getting ignored.
I set the initial value like so:
class CustomWizardForm3(ModelForm):
def __init__(self, user, *args, **kwargs):
self.helper = FormHelper()
self.helper.layout = Layout(
Fieldset("",
Div(ImageInlineRadios('sleeve_length'), css_class='span8 clearfix'),
Div(
CustomStyleDiv('armhole_edging_stitch', 'armhole_edging_height'),
css_class="row-fluid")
)
)
super(CustomWizardForm3, self).__init__(user, HELP_TEXT, *args, **kwargs)
if self.instance.is_vest():
self.fields['sleeve_length'].initial = DC.SLEEVE_VEST
class Meta:
model = IndividualDesign
fields = ('armhole_edging_stitch', 'armhole_edging_height', 'sleeve_length',)
In the model, sleeve_length is declared as:
sleeve_length= models.CharField(
max_length = 20,
choices = DC.SLEEVE_LENGTH_CHOICES,
null = True,
blank = True)
I've stepped through it in the debugger, and the initial attribute is set to what I expect. But when the radio buttons are generated, nothing is checked. What gives? Crispy and/or Django Forms is driving me mad.
ETA: ImageInlineRadios is a simple subclass of the standard crispy thing.
class ImageInlineRadios(InlineRadios):
def __init__(self, *args, **kwargs):
self.span_class = kwargs.pop('span_class', 2)
super(ImageInlineRadios, self).__init__(*args, **kwargs)
template = 'radio_buttons.html'
def render(self, form, form_style, context, template_pack='bootstrap'):
import pdb; pdb.set_trace()
context.update({'inline_class': 'inline',
'images': 'none',
'span_class':self.span_class})
return super(ImageInlineRadios, self).render(form, form_style, context)
In the radio_buttons.html template file, we have:
<input type="radio"
{% if choice.0|stringformat:"s" == field.value|stringformat:"s" %} checked="checked"{% endif %}
Does crispy not set field.value from initial? That part looks to me like what's in the radioselect.html template that comes with crispy, but if there's something else I should test, I'd love to know what it is.
I'm trying to imeplement an edit formset. Then, i'm instancing the objects in the formset using modelformset_factory. When the request isn't POST, the formset loads perfectly, but, if the request is POST, the formset constructor raises a MultiValueDictKeyError.
This is my code.
forms.py
class SchoolSectionForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout(
Div(
'name',
css_class='name',
),
)
super(SchoolSectionForm, self).__init__(*args, **kwargs)
class Meta:
model = SchoolSection
exclude = [
'school',
'created_by',
]
class SectionBreakFormSet(BaseFormSet):
def __init__(self, *args, **kwargs):
super(SectionBreakFormSet, self).__init__(*args, **kwargs)
class SectionBreakForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout(
Div(
Div(
'start_time',
css_class='start_time',
),
Div(
'end_time',
css_class='end_time',
),
css_class='formset_element',
)
)
super(SectionBreakForm, self).__init__(*args, **kwargs)
class Meta:
model = SectionBreak
exclude = [
'school_section',
'created_by',
]
views.py
def school_section_edit(request, section_id):
section = get_object_or_404(
SchoolSection,
id=section_id,
)
current_school = request.user.current_school
school_sections_list = current_school.schoolsection_set.all()
section_break_formset = modelformset_factory(
SectionBreak,
max_num=3,
extra=0,
form=SectionBreakForm,
)
formset_qset = SectionBreak.objects.filter(school_section=section)
formset = section_break_formset(queryset=formset_qset)
school_section_form = SchoolSectionForm(instance=section)
if request.method == 'POST':
school_section_form = SchoolSectionForm(request.POST)
# Bug raises in this line
formset = section_break_formset(request.POST, queryset=formset_qset)
# Bug raises in this line
if school_section_form.is_valid() and formset.is_valid():
school_section_form.save()
formset.save()
messages.success(
request,
u'xxx',
)
return HttpResponseRedirect(reverse('school:school_section_add'))
else:
messages.error(
request,
u'xxx',
)
return render(request, 'school/schoolsection_add.html', {
'school_section_form': school_section_form,
'formset': formset,
'school_sections_list': school_sections_list,
})
template
<form class="new_section_form" method="post" action="">
<div class="school_section_form">
{% crispy school_section_form %}
</div>
<h3>Horarios de descanso:</h3>
<div class="section_break_formset">
{% crispy formset formset.form.helper %}
</div>
<button class="button color">guardar</button>
</form>
When i post the form... crashh.... i have this error
thanks for help...
Exception Type: MultiValueDictKeyError at /administrador/ciclo-educativo/editar/34/
Exception Value: "Key u'form-0-id' not found in <>QueryDict: {u'name': [u'Primaria'], u'form-MAX_NUM_FORMS': [u'3'], u'form-TOTAL_FORMS': [u'1'], u'form-0-start_time': [u'07:00:00'], u'form-0-end_time': [u'12:00:00'], u'form-INITIAL_FORMS': [u'1'], u'csrfmiddlewaretoken': [u'aZkZPJ6tlzJeCd1kjC0EpkjPuFbWe6IB', u'aZkZPJ6tlzJeCd1kjC0EpkjPuFbWe6IB']}<>"
You might need to add the form id {{ form.id }} e.g.
{% crispy formset formset.form.id %}
Form id is hidden field but if you not include it in form in your template then it will through the above error.
if include it in your template you will get rid of above error
Ex:
{{form.title}} #this field you want to display
{{ form.id }} # this is hidden field, this will not get display in form. but at the time of form-set submission this is required.
I've got a modelform_formset that I'm rendering with django-crispy. Inside the layout of form used I have the following:
self.helper.layout = Layout(
Field('remove', css_class="inline"),
HTML('{{ form.instance.user.get_full_name|title }} ({{ form.instance.user }})'),
Field('is_admin')
)
Note the {{form.instance}} - That's not getting rendered properly binding. Is there a way to get the value for the specific model?
I would recommend you do this. This captures the case where you don't have an instance :D
class XYXForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(XYXForm, self).__init__(*args, **kwargs)
label = "New Object"
if self.instance:
label = '{0} {1}'.format(
self.instance.user.get_full_name.capitalize(),
self.instance.user)
self.helper = FormHelper()
self.helper.form_id = 'community_form'
self.helper.form_method = 'post'
self.helper.layout = Layout(
Field('remove', css_class="inline"),
HTML(label),
Field('is_admin')
)
HTH