Using a model instance with django-crispy and a formset - django

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

Related

Custom button classes in django crispy forms

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'

Rendering several forms with helpers Crispy Django

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)

Django overrides a Button in Crispy Form

I've got a first form as following:
class SupplierRegistrationSupplementForm(forms.ModelForm):
siret = FRSIRETField()
def __init__(self, *args, **kwargs):
super(SupplierRegistrationSupplementForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_class = 'form-horizontal'
self.helper.form_id = 'company_supplement_form'
self.helper.form_action = "."
self.helper.label_class = 'col-lg-2'
self.helper.field_class = 'col-lg-8'
self.helper.add_input(
Submit('submit', _('Save'),
css_class="btn-primary btn-lg",
css_id="save_company"
)
)
I need to inherit from it but with a different button. In order to change the button id, I would have done this:
class SupplierUpdateForm(SupplierRegistrationSupplementForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper.form_tag = False
self.helper.add_input(
Submit('submit', _('Save'),
css_class="btn-primary btn-lg",
css_id="save_user"
)
)
But it adds a new button to the previous one. Is it possible to remove the first one?
When you call add_inputs, the code appends the input to self.inputs. So a quick hack would be to pop the existing input from the list before adding the new one.
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
...
self.inputs.pop()
self.helper.add_input(...)
However this is fragile, because it assumes that there is exactly one input. It might be better to have a BaseSupplierForm which does not have any inputs, then have two subclasses SupplierRegistrationSupplementForm and SupplierUpdateForm, which both define their own inputs.

align field on django-crispy forms horizontally to centre of page?

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

django crispy forms - how to group the fields?

My form is here:
class SortFieldsForm(forms.Form):
LatestyearModel=forms.BooleanField(label="latest year")
LowestPrice=forms.BooleanField(label="lowest price")
HighestPrice=forms.BooleanField(label="highest price")
Newest_Entry=forms.BooleanField(label="latest date")
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_id = 'id-exampleForm'
self.helper.form_class = 'form-inline'
self.helper.form_method = 'post'
self.helper.form_action = 'sort_posting'
#self.helper.add_input(Submit('submit', 'Submit'))
super(SortFieldsForm, self).__init__(*args, **kwargs)
self.helper.layout = Layout(
#Fieldset(
# 'price',
# 'LowestPrice',
# 'HighestPrice',
),
PrependedText('LowestPrice', ''),
PrependedText('HighestPrice', ''),
PrependedText('Newest_Entry', ''),
PrependedText('LatestyearModel', ''),
ButtonHolder(
Submit('submit', 'Submit', css_class='button white')
)
)
Currently the form shows as this:
I want to group lowest price and highest price in one radioselect,
latest date and latest year as checkboxes neatly aligned with submit button next to the field. Not below them as it currently now.
Any pointers/tips?
Try this out:
class SortFieldsForm(forms.Form):
LatestyearModel=forms.BooleanField(label="latest year")
LowestPrice=forms.BooleanField(label="lowest price")
HighestPrice=forms.BooleanField(label="highest price")
Newest_Entry=forms.BooleanField(label="latest date")
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_id = 'id-exampleForm'
self.helper.form_class = 'form-inline'
self.helper.form_method = 'post'
self.helper.form_action = 'sort_posting'
#self.helper.add_input(Submit('submit', 'Submit'))
super(SortFieldsForm, self).__init__(*args, **kwargs)
self.helper.layout = Layout(
'LowestPrice',
'HighestPrice',
'Newest_Entry',
'LatestyearModel' ,
ButtonHolder(
Submit('submit', 'Submit', css_class='button white')
)
)
You should use ChoiceField and MultipleChoiceField with labels and custom widgets RadioSelect and CheckboxSelectMultiple.
More explanation
First, some code. I said about CheckboxSelectMultiple but you can do without it. RadioSelect is actually needed for radio buttons. You can place checkboxes and radio buttons after their labels using Bootstrap horizontal form layout.
class SortFieldsForm(forms.Form):
price_order=forms.ChoiceField(widget=forms.RadioSelect, choices=(('lowest', 'Lowest first'), ('highest', 'Highest first')))
newest_entry=forms.BooleanField(label="Latest date")
latest_year=forms.BooleanField(label="Latest year")
helper = FormHelper()
helper.form_class = 'form-horizontal'
helper.label_class = 'col-lg-2'
helper.field_class = 'col-lg-8'
helper.layout = Layout(
'price_order',
'newest_entry',
'latest_year',
Submit('submit', 'Submit', css_class='button white'))
Try to do like this. I cannot guarantee if there is no typos but you can achieve your goals this way.
Also, check out links below:
https://docs.djangoproject.com/en/dev/ref/forms/widgets/
http://django-crispy-forms.readthedocs.org/en/latest/crispy_tag_forms.html#bootstrap3-horizontal-forms
Learn about bootstrap and its classes.