Rendering individual fields in template in a custom form - django

I am having trouble rendering individual fields in my template. I have a custom form that renders a multichoice widget and Charfield. I want to render the widget and Charfield individually, so I can place the Charfield on the right of the widget rather than on the bottom (which is what Django does by default). Is there a way to call individual fields in my form in the template?
forms.py
class UpdateStateOptionWithOutcomesForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
disease=kwargs.pop('disease', None)
super(UpdateStateOptionWithOutcomesForm, self).__init__(*args, **kwargs)
self.fields['relevantoutcome']=forms.ModelMultipleChoiceField(queryset=Outcome.objects.filter(relevantdisease_id=disease),required=True, widget=forms.CheckboxSelectMultiple)
self.fields['relevantoutcome'].label="Treatment Outcomes"
outcome_qs=Outcome.objects.filter(relevantdisease_id=disease)
for outcome in outcome_qs:
self.fields['outcomevalue_%s' % outcome.pk] = forms.CharField(required=False)
self.fields['outcomevalue_%s' % outcome.pk].label = "Outcome Value"

{{ form.fieldname }} will render only the field widget by its name.
Check out Customizing the form template.

The following code could be helpful to someone. Here is a way to get a rendering field with fieldname from a form:
form.fields[fieldname].get_bound_field(form, fieldname)

Related

Initialize django CheckboxSelectMultiple with everything unchecked?

I have a model form that is rendering a ModelMultipleChoiceField as a CheckboxSelectMultiple
class VisitForm(ModelForm):
def __init__(self, queryset=None, *args, **kwargs):
super(VisitForm, self).__init__(*args, **kwargs)
if queryset:
self.fields['students'] = forms.ModelMultipleChoiceField(
queryset=queryset,
widget=forms.CheckboxSelectMultiple()
)
It's rendered very simply in the template right now:
<div class="form-group">
{{field.label}}
{{field}}
</div>
It initializes okay with the selections I expect to be there - but by default both options are checked
I am trying to figure out how to intialize the boxes so they are unchecked by default.
What is the best way to accomplish this?
It's initialized in the view like this:
visitor = Visitor.objects.get(unique_id=unique_id)
students = Student.objects.filter(parents__unique_id=unique_id)
form = VisitForm(initial={'visitor':visitor, 'students':students}, queryset=students)
You are passing the students queryset as the initial data, so Django selects every student in the queryset.
You could use an empty queryset Student.objects.none(), but it is even easier to remove students from the initial dictionary:
form = VisitForm(initial={'visitor':visitor}, queryset=students)

Setting HTML required attribute in Django formsets

To achieve client-side validation making the user to fill out non-null fields before submitting, I use the following code:
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
for field_name, field in self.fields.items():
field.widget.attrs['class'] = 'form-control'
if field.required == True:
field.widget.attrs['required'] = ''
This translates to the following html in the template:
<input class="form-control" ........ required="">
Now, when I use formsets, the required HTML attribute does not appear in the tempalte. The question is, how do I make Django formsets inherit this required attribute from the original forms - if it's possible whatsoever?
MyFormSet = modelformset_factory(MyModel, fields=(...))
formset = MyFormSet(queryset = MyModel.objects.filter(...))
How about creating formset from MyForm?
MyFormSet = forms.formset_factory(MyForm)
After spending three hours, I've solved the issue by setting a custom form in modelformset_factory. Maybe it will be useful for someone else
MyFormSet = modelformset_factory(MyModel, MyForm)
formset = MyFormSet(queryset = MyModel.objects.filter(...))
Specifying MyForm effectively tells Django to inherit all widget attributes that you have once declared in the MyForm definition.
Using formset_factory is for some reasons a headache for me, primarily because it accepts values instead of querysets which means I have to bother about foreign key relationships.

Avoid display of help_text in django crispy forms

I am customizing the RegistrationForm from django-registration-redux with django-crispy-forms. For that I have defined a FormHelper which is working fine:
class MyRegistrationForm(RegistrationForm):
def __init__(self, *args, **kwargs):
super(MyRegistrationForm, self).__init__(*args, **kwargs)
helper = self.helper = FormHelper()
# Moving field labels into placeholders
layout = helper.layout = Layout()
for field_name, field in self.fields.items():
layout.append(Field(field_name, placeholder=field.label))
helper.template_pack = 'bootstrap3'
helper.form_show_labels = False
My form is shown as I want: no labels, bootstrap3 and placeholders derived from label.
Now I would also like to suppress the help_text, which is coming from the Field definition. There is a somehow related flag here (help_text_inline), but that is not intended to disable the display of the help text. I can not find a flag to completely disable the display of the help text in the FormHelper documentation. Is this at all possible?
Removing the help text from the Field definition is not really an option, since I am inheriting the RegistrationForm and I do not want to modify it too much.

Unable to Disable a RadioSelect Widget Using Forms Class in Django

I have a form that contains a RadioSelect field. I am not able to disable this field in this form either in the init() method (<1>/<3>/<4>) and/or in the creation of the RadioSelect form element (<2>). There is one subclass to this form, but it does not use the radioButton field in question. I have been working on identifying what the issue is for the past 4 hours to no available. What could I have missed?
Below is a snippet of the code that I am using:
class ExampleForm (ParentForm1, ParentForm2, ParentForm3):
def __init__(self,*args, **kwargs):
super(ExampleForm, self).__init__(*args, **kwargs)
#<1>
self.fields['radioButton'].widget.attrs['disabled'] = 'disabled'
#<3>
#self.fields["radioButton"].widget.attrs['disabled'] = True
#<4>
#self.fields['radioButton'].widget.attrs.update({'disabled':'disabled', 'readonly':'readonly'})
#<2>
radioButton = forms.ChoiceField(label=_("Gender"),
initial='M',
required=False,
choices=GENDER_LIST,
widget=forms.RadioSelect(attrs={"disabled":"disabled"}))
I am using Django 1.4.
#<1>
self.fields['radioButton'].widget.attrs['disabled'] = 'disabled'
#<2>
self.fields["radioButton"].widget.attrs['disabled'] = True
#<3>
self.fields["radioButton"].widget.attrs = {'disabled':'disabled'}
The above methods work in disabling the RadioSelect field. It turns out that a JavaScript script was removing the "disabled" attribute for the RadioSelect field.

Dynamic choices for Django SelectMultiple Widget

I'm building a form (not modelForm) where i'd like to use the SelectMultiple Widget to display choices based on a query done during the init of the form.
I can think of a few way to do this but I am not exactly clear on the right way to do it. I see different options.
I get the "choices" I should pass to the widget in the form init but I am not sure how I should pass them.
class NavigatorExportForm(forms.Form):
def __init__(self,user, app_id, *args,**kwargs):
super (NavigatorExportForm,self ).__init__(*args,**kwargs) # populates the form
language_choices = Navigator.admin_objects.get(id=app_id).languages.all().values_list('language', flat=True)
languages = forms.CharField(max_length=2, widget=forms.SelectMultiple(choices=???language_choices))
Why not use a ModelMultipleChoiceField instead?
You could do simply this :
class NavigatorExportForm(forms.Form):
languages = forms.ModelMultipleChoiceField(queryset=Language.objects.all())
def __init__(self, app_id, *args, **kwargs):
super(NavigatorExportForm, self).__init__(*args, **kwargs)
# Dynamically refine the queryset for the field
self.fields['languages'].queryset = Navigator.admin_objects.get(id=app_id).languages.all()
This way you don't only restrict the choices available on the widget, but also on the field (that gives you data validation).
With this method, the displayed string in the widget would be the result of the __unicode__ method on a Language object. If it's not what you want, you could write the following custom field, as documented in ModelChoiceField reference :
class LanguageMultipleChoiceField(forms.ModelMultipleChoiceField):
def label_from_instance(self, obj):
return obj.language_code # for example, depending on your model
and use this class instead of ModelMultipleChoiceField in your form.
def __init__(self,user, app_id, *args,**kwargs):
super (NavigatorExportForm,self ).__init__(*args,**kwargs)
self.fields['languages'].widget.choices = Navigator.admin_objects.get(id=app_id).languages.all().values_list('language', flat=True)
that seems to do the trick, but even by not specifying a max_length, the widget only display the first letter of the choices...