Widget classes allow for CSS styling via the attrs
attribute. That works pretty well for form fields. Is there a way achieve the same effect with form.as_div()
?
form.as_div()
wraps div
tags around the widgets. I would like to do something like:
<div class="wgt-div">
<label for="number-input">Add number</label>
<input id="number-input" type="number"/>
</div>
note the CSS class “wgt-div
” attached to the div
and not the widgets. Is this viable? How?
here is what I have, so far:
from django.utils.safestring import SafeString
class BaseTestFormSetforms(forms.BaseModelFormSet):
"""Basis for the set of forms used for Test"""
def as_div(self):
"""Add CSS Styling to divs"""
return SafeString(super().as_div().replace("<div>", "<div class='widget-group'>"))
A hack! One snag … some of the div lines have no newline character (“\n
”), hence the source html is not completely neat. I wonder what the native as_div()
function looks like
The as_div
function is really simple - it renders a template. (see django.forms.utils.RenderableFormMixin
)
Take a look at the div.html
file in django.forms.templates.django.forms
. You’ll see that the div
wrapper uses the attribute css_classes
to define what to use in the class
attribute of the div.
Also see The Forms API | Django documentation | Django
1 Like
I looked at it before implementing the subclass above. I wasn’t sure how the css_classes worked. It appears to be addressing fields contained in the wrapper and not the div wrapper itself
Did you look at the referenced div.html
file? The template makes it clear how it’s being used.
I get it now.
I needed to set the required_css_class
attribute in the form (See this). Otherwise, the following line in div.html
remained a puzzle:
this line:
<div{% with classes=field.css_classes %}{% if classes %} class="{{ classes }}"{% endif %}{% endwith %}>
something had to set values before field.css_classes
function returns the value. Automatically generated forms don’t have that advantage. I was using modelformset_factory
without setting a custom form
. Hence, django
was generating those forms from the models using the default values for . required_css_class
(i.e not set)
Invariably, one must define a form class to take advantage of custom as_div()
styling. I see no way of setting required_css_class
after instantiating the form
If you really wanted to address this in a different way, you could iterate over the fields over all the forms in the formset after creating it, and set that attribute on the individual fields.
While this is close, it does not solve my problem especially for formsets
with “can_delete
” fields.
The delete field has a separate div
wrapping. That presents more styling challenges for me. I want all the fields in a member form inside a div
. Looks like I have to iterate on the template. AArghhh!
Hey! I solved using the next lines:
from django.utils.safestring import SafeString
class MyForm(forms.Form):
#class to every widget
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
for visible in self.visible_fields():
visible.field.widget.attrs['class'] = 'form-control'
#class on every div when I use {{ form.as_div }} on html template
def as_div(self):
return SafeString(super().as_div().replace("<div>", "<div class='form-group'>"))
...
1 Like