Note: This question shouldn't be conflated with past questions that are similar but before Django 1.11, when they released template-based form rendering.
I understand that Django now has template-based form rendering. From what I understand, this is supposed to fix the issue of having to inject CSS classes from the view or the form, rather than keeping all of the HTML/CSS in the templates.
That is my goal: to keep my forms and views focused on what is displayed, and my templates focused on how that is displayed. So I want to keep all HTML/CSS in my templates.
So, my questions are:
form-text
) to all TextInput
widgets from the template system?alert-warning
) to all error messages (validation failures) from the template system?I may have misunderstood something about this new feature, so if I did, feel free to let me know if this isn't how it works or if I am asking the impossible. Ideally, I would like to implement these form rendering changes to the master template.
views.py
:
class SignUp(generic.edit.CreateView):
model = models.User
template_name = 'usermgmt/sign_up.html'
form_class = forms.UserCreateForm
success_url = '/sign_up_done/'
templates/master.html
(I want to put something in here that causes all TextInput
widgets to get a class):
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<title>{% block title %}{% endblock %} | Website</title>
</head>
<body>
<div class="content-wrapper clearfix">
{% block main %}{% endblock %}
</div>
</body>
</html>
templates/usermgmt/sign_up.html
:
{% extends 'master.html' %}
{% block title %}Sign Up{% endblock %}
{% block main %}
<h1>Sign Up</h1>
<p>Enter your email to sign up!</p>
<form class="form-group" method="post">
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}">
{{ form.as_p }}
<button class="btn btn-primary" type="submit">Sign Up</button>
</form>
{% endblock %}
A widget is Django's representation of an HTML input element. The widget handles the rendering of the HTML, and the extraction of data from a GET/POST dictionary that corresponds to the widget. The HTML generated by the built-in widgets uses HTML5 syntax, targeting <! DOCTYPE html> .
{{ form.as_p }} – Render Django Forms as paragraph. {{ form.as_ul }} – Render Django Forms as list.
attrs . A dictionary containing HTML attributes to be set on the rendered DateInput and TimeInput widgets, respectively. If these attributes aren't set, Widget. attrs is used instead.
Continuing from José Tomás Tocino's answer above, In Django 1.11 I found that my directory structure needed to be:
main/templates/django/forms/widgets/text.html
As far as I've understood from the release notes of Django 1.11 and from my own testing, the new features only allows us to easily customize the way widgets are rendered by simply providing HTML files for each widget type. In previous Django versions you had to provide a subclass of forms.widget.Widget
and assign that widget to your model/form fields one by one (IIRC).
If you wanna make all TextInput
widgets have a specific class, you're gonna have to add your custom text.html
(and probably your own attrs.html
as well).
For example, let's say I have a myforms
project with a main
app. According to the docs:
If you use the TemplatesSetting renderer, overriding widget templates works the same as overriding any other template in your project. You can’t override built-in widget templates using the other built-in renderers.
So we need to set our renderer in the settings.py
file:
FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'
But if we only do that, we'd need to provide templates for all input elements. According to the docs:
Using this renderer along with the built-in widget templates requires [...] [adding] 'django.forms' in INSTALLED_APPS and at least one engine with APP_DIRS=True.
So we add django.forms
to INSTALLED_APPS
. Now, in order to add our customization for, say, text input elements, we need to create the file main/templates/django/forms/widgets/text.html
and add our custom HTML code there, like:
<input type="text" class="myclass" value="{{widget.value}}">
So, if we show a form in a template, that code will appear whenever a CharField
need to be rendered, for example.
But all of this doesn't matter if you need a per-field level of control, for example if each field needs a different class. In that case, you should combine what I wrote with django-widget-tweaks so you can have more flexible widget customization.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With