Field labels crispy forms Django - django

I want to use the same model for two forms and change the labels of field how can i change the label?
this is my one form:
class jobpostForm(forms.ModelForm):
class Meta:
model = jobpost
fields = ('job_type','title','company_name','location','country','description','start_date','end_date','how_to_apply')
widgets = {
'job_type':RadioSelect(),
'location':TextInput(attrs={'size':'70','cols': 10, 'rows': 20}),
'description': TinyMCE(attrs={'cols':'100', 'row': '80'}),
'start_date':AdminDateWidget(attrs={'readonly':'readonly'}),
'end_date':AdminDateWidget(attrs={'readonly':'readonly'}),
'how_to_apply':RadioSelect(),
}
def __init__(self, *args, **kwargs):
super(jobpostForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_class = 'horizontal-form'
self.helper.form_id = 'id-jobpostform'
self.helper.form_class = 'blueForms'
self.helper.form_method = 'post'
self.helper.form_action = '/portal/next/post/'
self.helper.add_input(Submit(_('submit_addcontent'), 'Preview'))
super(jobpostForm, self).__init__(*args, **kwargs)
like i want to change 'location' to 'Job Location'..how can i do this?

This problem is not really specific for Django Crispy Forms.
One option is to set the label in the init() method of your JobPostForm.
def __init__(self, *args, **kwargs):
super(JobPostForm, self).__init__(*args, **kwargs)
self.fields['location'].label = "Job Location"
A good read when dealing with these kind of questions is Overloading Django Form Fields.

There is an easier way to do this. See my example below:
class CreateAPIKey(forms.ModelForm):
class Meta:
model = APIKey
fields = ["client_id"]
labels = {
"client_id": "Nome da Key",
}
help_texts = {
"client_id": _(
"Um identificador exclusivo de formato livre da chave. 50 caracteres no máximo"
),
}
widgets = {
"client_id": forms.TextInput(
attrs={
"id": "key_id",
"required": True,
"placeholder": "Entre um nome único para a chave",
"label": "dasdasdsdasd",
}
),
}
Then, then rendering the form on the template:
<form class="" method="POST" action="#">
{% csrf_token %}
<div class="col-md-4 col-sm-12 form-group" data-children-count="1">
{% for field in form %}
{{ field|as_crispy_field }}
{% endfor %}
</div>
</form>
RESULT:

In my case calling the __init__ on my forms.py file worked
CODE FORMAT:
def __init__(self, *args, **kwargs):
super(ChangeFormNameHere, self).__init__(*args, **kwargs)
self.fields['model_filed_default_name'].label = "Your_new_label_name"

Related

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 - How do I add a placeholder on a modelform that's the current field of the model?

I want to be able to vary the placeholder like so:
<input placeholder=" {{ input.placeholder }}">
Where input is a model with the "placeholder" field. The placeholder field will vary since I'll be using a formset, and each placeholder will vary.
Here's my modelForm
class Value(forms.ModelForm):
class Meta:
model = ValueModel
fields = ['value_text']
widgets = {
'value_text': forms.TextInput(attrs={'class': 'form-control'})
and my modelformset
values_formset = modelformset_factory(model=ValueModel, extra=0, form=Value)
I've tried
class Value(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(Value, self).__init__(*args, **kwargs)
self.fields['value_text'].widget.attrs['placeholder'] = self.fields['placeholder']
class Meta:
model = ValueModel
fields = ['value_text', 'placeholder']
widgets = {
'value_text': forms.TextInput(attrs={'class': 'form-control'})
And other attempts at trying to modify the self.fields with no success.
Edit: The relevant part of my views.py:
def page_view(request, values_id):
values_form = values_formset(queryset=ValueModel.objects.filter(
values_id=values_id))
context = {'value': values_form}
return render(request, 'view.html', context)
My template view:
{{ value.management_form }}
{% for form in value %}
{{ form.id }}
{{ form.value_text }}
{% endfor %}
self.fields['placeholder'] refers to a form field object, not a value; you couldn't use it as a placeholder. But it seems like what you want is to use the value of the model instance.
def __init__(self, *args, **kwargs):
super(Value, self).__init__(*args, **kwargs)
self.fields['value_text'].widget.attrs['placeholder'] = self.instance.placeholder

Crispy forms ignores initial value for radio button

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.

How to add class, id, placeholder attributes to a field in django model forms

I have a django model like below
models.py
class Product(models.Model):
name = models.CharField(max_length = 300)
description = models.TextField(max_length = 2000)
created = models.DateTimeField(auto_now_add = True)
updated = models.DateTimeField(auto_now = True)
def __unicode__(self):
return self.name
forms.py
class ProductForm(ModelForm):
class Meta:
model = Product
exclude = ('updated', 'created')
product_form.py(just an example)
<form enctype="multipart/form-data" action="{% url 'add_a_product' %}" method="post">
<div id="name">
{{form.name}}
</div>
<div id="description">
{{form.description}}
</div>
</form>
Actually I want to display/render the html output like below
<input id="common_id_for_inputfields" type="text" placeholder="Name" class="input-calss_name" name="Name">
<input id="common_id_for_inputfields" type="text" placeholder="Description" class="input-calss_name" name="description">
So finally how to add attributes(id, placeholder, class)to the model form fields in the above code ?
You can do the following:
#forms.py
class ProductForm(ModelForm):
class Meta:
model = Product
exclude = ('updated', 'created')
def __init__(self, *args, **kwargs):
super(ProductForm, self).__init__(*args, **kwargs)
self.fields['description'].widget = TextInput(attrs={
'id': 'myCustomId',
'class': 'myCustomClass',
'name': 'myCustomName',
'placeholder': 'myCustomPlaceholder'})
Field ids should be generated automatically by django, to override other fields:
class ProductForm(ModelForm):
class Meta:
model = Product
exclude = ('updated', 'created')
def __init__(self, *args, **kwargs):
super(ProductForm, self).__init__(*args, **kwargs)
self.fields['name'].widget.attrs\
.update({
'placeholder': 'Name',
'class': 'input-calss_name'
})
I really like Dmitriy Sintsov's answer but it doesn't work. Here's a version that does work:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in iter(self.fields):
self.fields[field].widget.attrs.update({
'class': 'form-control'
})
update
add this condition for better
if self.fields[field].widget.__class__.__name__ in ('AdminTextInputWidget' , 'Textarea' , 'NumberInput' , 'AdminURLFieldWidget', 'Select'):
self.fields[field].widget.attrs.update({ 'class': 'form-control' })
You can update forms.py as below
class ProductForm(ModelForm):
class Meta:
model = Product
exclude = ('updated', 'created')
widgets={
"name":forms.TextInput(attrs={'placeholder':'Name','name':'Name','id':'common_id_for_imputfields','class':'input-class_name'}),
"description":forms.TextInput(attrs={'placeholder':'description','name':'description','id':'common_id_for_imputfields','class':'input-class_name'}),
}
Slightly modified version of excellent mariodev answer, adding bootstrap class to all form fields, so I do not have to re-create form input widgets for each field manually (short Python 3.x super()):
class ProductForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].widget.attrs.update({
'class': 'form-control'
})
Adding to answer from Derick Hayes I created a class BasicForm which extends forms.ModelForm that adds the bootstrap classes to every form that extends it.
For my forms I just extend BasicForm instead of model form and automatically get bootstrap classes on all forms. I went a step further and append the classes to any custom css classes which may already be there.
class BaseModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(BaseModelForm, self).__init__(*args, **kwargs)
# add common css classes to all widgets
for field in iter(self.fields):
#get current classes from Meta
classes = self.fields[field].widget.attrs.get("class")
if classes is not None:
classes += " form-control"
else:
classes = "form-control"
self.fields[field].widget.attrs.update({
'class': classes
})
add_class filter for adding a CSS class to form field:
{% load widget_tweaks %}
<form enctype="multipart/form-data" action="{% url 'add_a_product' %}" method="post">
<div id="name">
{{form.name|add_class:"input-calss_name"}}
</div>
<div id="description">
{{form.description|add_class:"input-calss_name"}}
</div>
</form>
django-widget-tweaks library
You can do the following:
class ProductForm(ModelForm):
name = forms.CharField(label='name ',
widget=forms.TextInput(attrs={'placeholder': 'name '}))
I know this is an old question but if someone is still looking to add custom class to all of his form fields, then you can use this one liner
class ProductForm(ModelForm):
class Meta:
model = Product
exclude = ('updated', 'created')
def __init__(self, *args, **kwargs):
super(ProductForm, self).__init__(*args, **kwargs)
custom_attrs = {
'class': 'form-control',
'toggle-data': 'mydiv',
}
# adds our custom_attrs to each element of the form
[self.fields[i].widget.attrs.update(custom_attrs) for i in self.fields]

MultiValueDictKeyError in django modelformset_factory

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.