124π
If you canβt use a third-party app and want to add a class (e.g., "form-control") to every field in a form in a DRY manner, you can do so in the form class __init__()
method like so:
class ExampleForm(forms.Form):
# Your declared form fields here
...
def __init__(self, *args, **kwargs):
super(ExampleForm, self).__init__(*args, **kwargs)
for visible in self.visible_fields():
visible.field.widget.attrs['class'] = 'form-control'
You might need to handle checking for existing classes in attrs too, if for some reason youβll be adding classes both declaratively and within __init__()
. The above code doesnβt account for that case.
Worth mentioning:
You specified that you donβt want to use third-party packages. However, Iβll take one second to mention that one of the simplest ways of automatically making forms render in the style of Bootstrap is to use django-crispy-forms, like this:
# settings.py
CRISPY_TEMPLATE_PACK = 'bootstrap3'
# forms.py
from crispy_forms.helper import FormHelper
class ExampleForm(forms.Form):
# Your declared form fields here
...
helper = FormHelper()
# In your template, this renders the form Bootstrap-style:
{% load crispy_forms_tags %}
{% crispy form %}
44π
you can add CSS classes in forms.py
subject = forms.CharField(label='subject',
max_length=100,
widget=forms.TextInput(
attrs={'class': "form-control"}))
- [Django]-Dynamically add field to a form
- [Django]-Django: Query using contains each value in a list
- [Django]-Gunicorn.errors.HaltServer: <HaltServer 'Worker failed to boot.' 3> django
20π
Since it took me more hours, than I would like to (django newbie), to figure this out, I will place my outcome here aswell.
Setting widget to each field just to add one class over and over again is against programming rule of repeating and leads to many unneccessary rows. This especially happens when working with bootstrap forms.
Here is my (working) example for adding not only bootstrap classes:
forms.py
class CompanyForm(forms.Form):
name = forms.CharField(label='JmΓ©no')
shortcut = forms.CharField(label='Zkratka')
webpage = forms.URLField(label='WebovΓ© strΓ‘nky')
logo = forms.FileField(label='Logo')
templatetags/custom_tags.py
from django import template
from django.urls import reverse
register = template.Library()
@register.filter('input_type')
def input_type(ob):
'''
Extract form field type
:param ob: form field
:return: string of form field widget type
'''
return ob.field.widget.__class__.__name__
@register.filter(name='add_classes')
def add_classes(value, arg):
'''
Add provided classes to form field
:param value: form field
:param arg: string of classes seperated by ' '
:return: edited field
'''
css_classes = value.field.widget.attrs.get('class', '')
# check if class is set or empty and split its content to list (or init list)
if css_classes:
css_classes = css_classes.split(' ')
else:
css_classes = []
# prepare new classes to list
args = arg.split(' ')
for a in args:
if a not in css_classes:
css_classes.append(a)
# join back to single string
return value.as_widget(attrs={'class': ' '.join(css_classes)})
reusable_form_fields.html (template)
{% load custom_tags %}
{% csrf_token %}
{% for field in form %}
<div class="form-group row">
{% if field|input_type == 'TextInput' %}
<div for="{{ field.label }}" class="col-sm-2 col-form-label">
{{ field.label_tag }}
</div>
<div class="col-sm-10">
{{ field|add_classes:'form-control'}}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>
{% else %}
...
{% endif %}
</div>
{% endfor %}
- [Django]-Generating a Random Hex Color in Python
- [Django]-Function decorators with parameters on a class based view in Django
- [Django]-Why use Django on Google App Engine?
6π
Crispy forms are the way to go . Tips for Bootstrap 4. Adding to @Christian Abbottβs answer, For forms , bootstrap says, use form-group and form-control .
This is how it worked for me .
My forms.py
class BlogPostForm(forms.ModelForm):
class Meta:
model = models.Post
fields = ['title', 'text', 'tags', 'author', 'slug']
helper = FormHelper()
helper.form_class = 'form-group'
helper.layout = Layout(
Field('title', css_class='form-control mt-2 mb-3'),
Field('text', rows="3", css_class='form-control mb-3'),
Field('author', css_class='form-control mb-3'),
Field('tags', css_class='form-control mb-3'),
Field('slug', css_class='form-control'),
)
My post_create.html
{% extends 'blog/new_blog_base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="container">
<form method='POST' enctype="multipart/form-data">
{% csrf_token %}
{{ form.media }}
{% crispy form %}
<hr>
<input type="submit" name="Save" value="Save" class='btn btn-primary'> <a href="{% url 'home' %}" class='btn btn-danger'>Cancel</a>
</form>
</div>
{% endblock %}
Note : If you are using CK Editor RichTextField() for your model field , then that field wont be affected . If anyone knows about it , do update this .
- [Django]-Django Model MultipleChoice
- [Django]-'RelatedManager' object is not iterable Django
- [Django]-Add inline model to django admin site
4π
You can also explicity mention the field that you want to apply the class to
class ProfileForm(ModelForm):
class Meta:
model = Profile
fields = ['avatar','company']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['avatar'].widget.attrs.update({'class': 'form-control'})
self.fields['company'].widget.attrs.update({'class':'form-control'})
- [Django]-Django β Clean permission table
- [Django]-Django Rest Framework β no module named rest_framework
- [Django]-How to reload modules in django shell?
3π
I understood "no third-party libs", but this one django-widget-tweaks
really WORTH MENTIONING
is simple, DRY and powerfull.
give you full control over the widget rendering doesnt matter which css framework you are using β¦ still simple
- you manage many html attributes you want on HTML not Django forms.
- User template "filters" not template tags (as a "normal" form var)
- You control the input and labels
-> https://github.com/jazzband/django-widget-tweaks
Sample β¦
{{form.hours|attr:"class:form-control form-control-sm"}}
- [Django]-How to get the currently logged in user's id in Django?
- [Django]-How to create user from django shell
- [Django]-What is reverse()?
2π
This is very practical:
class CreateSomethingForm(forms.ModelForm):
class Meta:
model = Something
exclude = []
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self.fields.values():
field.widget.attrs['class'] = 'form-control'
In this way you donβt have to go field by field.
- [Django]-DRF: Simple foreign key assignment with nested serializers?
- [Django]-Using Django auth UserAdmin for a custom user model
- [Django]-Generics vs viewset in django rest framework, how to prefer which one to use?
1π
I found it easier to identify the element via css and add the styling there. With django forms you get a unique id for each form field (user form prefixes if you display the form multiple times in your template).
# views.py
def my_view_function(request):
form_a = MyForm(prefix="a")
form_b = MyForm(prefix="b")
context = {
"form_a": form_a,
"form_b": form_b
}
return render(request, "template/file.html", context)
style
// file.css
form input#by_id {
width: 100%;
}
- [Django]-Passing STATIC_URL to file javascript with django
- [Django]-Authorization Credentials Stripped β django, elastic beanstalk, oauth
- [Django]-How can I handle Exceptions raised by dango-social-auth?
1π
This is a answer complemeting @Christian Abbott correct answer.
If you use a lot of forms, a option for not having to override init every single time may be to create your own form class:
class MyBaseForm(forms.Form):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for visible in self.visible_fields():
visible.field.widget.attrs['class'] = 'form-control'
Then you can inherit from this class and it is going to automatically make the styles for you.
class ExampleForm(MyBaseForm):
# Your declared form fields here
...
Same thing can be done with ModelForm by simply creating a MyBaseModelForm that inherits from ModelForm.
- [Django]-Attempt to write a readonly database β Django w/ SELinux error
- [Django]-How to reset migrations in Django 1.7
- [Django]-How to check if ManyToMany field is not empty?
1π
You can add classes in your forms.py
inside the Meta class:
class Form(forms.ModelForm):
class Meta:
model = ModelForm
fields = "__all__"
widgets = {
'name': forms.TextInput(attrs={'class':'form-control'})
}
- [Django]-Django Cannot set values on a ManyToManyField which specifies an intermediary model. Use Manager instead
- [Django]-Django project models.py versus app models.py
- [Django]-Execute code when Django starts ONCE only?
0π
One way is to create base form class and manually update the fieldβs attribute inside __init__
method.
Another is by using already existing libraries like this one:
https://github.com/dyve/django-bootstrap3
There are plenty of these libraries around github. Look around.
- [Django]-What is the difference between static files and media files in Django?
- [Django]-Django Rest Framework and JSONField
- [Django]-Auto-create primary key used when not defining a primary key type warning in Django
0π
Ok some time has passed but i had the same issues. I came to this solution:
class FormCssAttrsMixin():
cssAttrs = {}
def inject_css_attrs(self):
# iterate through fields
for field in self.fields:
widget = self.fields[field].widget
widgetClassName = widget.__class__.__name__
# found widget which should be manipulated?
if widgetClassName in self.cssAttrs.keys():
# inject attributes
attrs = self.cssAttrs[widgetClassName]
for attr in attrs:
if attr in widget.attrs: # attribute already existing
widget.attrs.update[attr] = widget[attr] + " " + attrs[attr] # append
else: # create attribute since its not existing yet
widget.attrs[attr] = attrs[attr]
class MyForm(FormCssAttrsMixin, forms.Form):
# add class attribute to all django textinputs widgets
cssAttrs = {"TextInput": {"class": "form-control"}}
name = forms.CharField()
email = forms.CharField()
address = forms.CharField()
country = forms.CharField()
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.inject_css_attrs()
With this Mixin class you can manipulate the attributes of form widgets in a generic way. Simply add a dictionary as class variable which contains the desired attributes and values per widget.
This way you can add your css classes at the same location where you define your fields. Only downside is, that you have to call the "inject_css_attrs" method somewhere but i think that is ok.
- [Django]-Stack trace from manage.py runserver not appearing
- [Django]-Get model's fields in Django
- [Django]-How do I POST with jQuery/Ajax in Django?
0π
A generalized version of @christian-abbott response:
class ExampleForm(forms.Form):
_HTML_CLASSES = ('form-control', 'something-else')
# Your declared form fields here
...
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for visible in self.visible_fields():
missing_classes = list(self._HTML_CLASSES)
if 'class' in visible.field.widget.attrs:
current_classes = visible.field.widget.attrs['class'].split(' ')
for current_class in current_classes:
if current_class in missing_classes:
missing_classes.remove(current_class)
else:
current_classes = []
visible.field.widget.attrs['class'] = ' '.join(current_classes + missing_classes)
- [Django]-How does the get_or_create function in Django return two values?
- [Django]-Django datetime issues (default=datetime.now())
- [Django]-Django model object with foreign key creation
0π
If you just need to change the class for bootstrap purposes, you can just add a script to the template.
<script>
const elementsInputs = document.querySelectorAll('input[id^="id_"]');
elementsInputs.forEach(element => {
element.classList.add("form-control");
});
const elementsLabels = document.querySelectorAll('label[for^="id_"]');
elementsLabels.forEach(element => {
element.classList.add("form-label");
});
</script>
then the form fields in the template should be something like:
<div class="fieldWrapper">
{{ form.subject.errors }}
{{ form.subject.label_tag }}
{{ form.subject }}
</div>
as described in Django.
- [Django]-How to change empty_label for modelForm choice field?
- [Django]-How to redirect with post data (Django)
- [Django]-Multiple annotate Sum terms yields inflated answer
0π
You can do it without any external libraries or code changes, right in the template. Like this:
{% for field in form %}
<div class="input_item">
<p class="title">{{ field.label }}:</p>
<div class="form-group">
<{{ field|cut:"<"|cut:">" }} class="form-control">
</div>
</div>
{% endfor %}
However, it is not the best solution. If you can create templatetag β go for it.
- [Django]-What does Django's @property do?
- [Django]-Django URL Redirect
- [Django]-Is this the right way to do dependency injection in Django?
0π
Like this:
title.widget.attrs['class'] = 'form-control'
Just change title to the name of your input, and form-control to whatever class you want to add to this input field.
- [Django]-Django template includes slow?
- [Django]-Error: No module named staticfiles
- [Django]-Retrieving parameters from a URL
-2π
you can use row-cols-5
<div class="row row-cols-5">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
<div class="col">4</div>
<div class="col">5</div>
</div>
- [Django]-Django REST Framework β 405 METHOD NOT ALLOWED using SimpleRouter
- [Django]-Token Authentication for RESTful API: should the token be periodically changed?
- [Django]-How to check whether the user is anonymous or not in Django?
-3π
I know that author asked about Bootstrap for own Form, but there is an additional way to include Bootstrap class tag in Django form for authentication, password reset etc.
If we create template with standard form:
<form action="" method="post">
{% csrf_token %}
{{ form }}
</form>
then in browser source code we can see all the form fields with the tags:
<form action="" method="post">
<input type="hidden" name="csrfmiddlewaretoken" value="xxx">
<tr><th><label for="id_old_password">Old password:</label></th><td><input type="password" name="old_password" autofocus required id="id_old_password"></td></tr>
<tr><th><label for="id_new_password1">New password:</label></th><td><input type="password" name="new_password1" required id="id_new_password1"></td></tr>
<tr><th><label for="id_new_password2">New password confirmation:</label></th><td><input type="password" name="new_password2" required id="id_new_password2"></td></tr>
</form>
Variable {{ form }}
in our template now can be replaced with this code and Bootstrap classes we needed:
<div class="fieldWrapper form-group" aria-required="true">
<label for="id_old_password">Old password:</label><span class="required">*</span>
<input type="password" **class="form-control"** name="old_password" autofocus required id="id_old_password">
</div>
Maybe it could be useful for redesign built-in static forms.
- [Django]-Django β Overriding the Model.create() method?
- [Django]-Django FileField with upload_to determined at runtime
- [Django]-Django REST framework: non-model serializer