6👍
Monkeypatching Widget is your best bet:
from django.forms.widgets import Widget
from django.contrib.admin.widgets import AdminFileWidget
from django.forms import HiddenInput, FileInput
old_build_attrs = Widget.build_attrs
def build_attrs(self, extra_attrs=None, **kwargs):
attrs = old_build_attrs(self, extra_attrs, **kwargs)
# if required, and it's not a file widget since those can have files
# attached without seeming filled-in to the browser, and skip hidden "mock"
# fileds created for StackedInline and TabbedInline admin stuff
if (self.is_required
and type(self) not in (AdminFileWidget, HiddenInput, FileInput)
and "__prefix__" not in attrs.get("name", "")):
attrs['required'] = 'required'
return attrs
Widget.build_attrs = build_attrs
20👍
Django form elements are written against <input />
as it exists in HTML 4, where type="text"
was the correct option for e-mail addresses. There was also no required="true"
.
If you want custom HTML attributes, you need the attrs
keyword argument to the widget. It would look something like this:
email = forms.EmailField(
max_length=100,
required=True,
widget=forms.TextInput(attrs={ 'required': 'true' }),
)
You can check out more documentation about widgets here. Discussion of attrs
is near the bottom of that page.
Regarding type="email"
, you might be able to send that to your attrs
dictionary and Django will intelligently override its default. If that isn’t the result you get, then your route is to subclass forms.TextInput
and then pass it to the widget
keyword argument.
- Django database delete specific number of entries
- Django Rest Framework: How to enable swagger docs for function based views
- Installed Virtualenv and activating virtualenv doesn't work
10👍
Combining Daniel and Daniel answers, I usually use this mixin for my forms:
from django.contrib.admin.widgets import AdminFileWidget
from django.forms.widgets import HiddenInput, FileInput
class HTML5RequiredMixin(object):
def __init__(self, *args, **kwargs):
super(HTML5RequiredMixin, self).__init__(*args, **kwargs)
for field in self.fields:
if (self.fields[field].required and
type(self.fields[field].widget) not in
(AdminFileWidget, HiddenInput, FileInput) and
'__prefix__' not in self.fields[field].widget.attrs):
self.fields[field].widget.attrs['required'] = 'required'
if self.fields[field].label:
self.fields[field].label += ' *'
So when i have to create a new form or modelform i just use:
class NewForm(HTML5RequiredMixin, forms.Form):
...
7👍
Since Django 1.10, this is built-in.
From the release notes:
Required form fields now have the required HTML attribute. Set the new Form.use_required_attribute attribute to False to disable it.
6👍
There’s also the template-only solution using a filter. I recommend django-widget-tweaks
:
{% load widget_tweaks %}
{{ form.email|attr:'required:true' }}
That was easy.
- Making Twitter, Tastypie, Django, XAuth and iOS work to Build Django-based Access Permissions
- Tiny MCE popups blank in Django admin
- Why can't I upload jpg files to my Django app via admin/?
- Django ALLOWED_HOSTS for Amazon ELB
4👍
As you’ve realized, setting your Field required attribute to True
is only for backend validation, as explained in the Django documentation.
What you really want is to add a required attribute to the Widget of the field:
email.widget.attrs["required"] = "required"
But if you really want to write elegant, DRY code, you should make a base form class that dynamically looks for all your required fields and modifies their widget required attribute for you (you can name it whatever you wish, but “BaseForm” seems apt):
from django.forms import ModelForm
class BaseForm(ModelForm):
def __init__(self, *args, **kwargs):
super(BaseForm, self).__init__(*args, **kwargs)
for bound_field in self:
if hasattr(bound_field, "field") and bound_field.field.required:
bound_field.field.widget.attrs["required"] = "required"
And then have all your Form objects descend from it:
class UserForm(BaseForm):
class Meta:
model = User
fields = []
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
email = forms.EmailField(required=True, max_length=100)
- Django admin list_filter – filter field by is empty (None or empty string "")
- Django. Error message for login form
- Mysql_exceptions.OperationalError: (1045, "Access denied for user 'root'@'localhost' (using password: YES)")