Overview
Django 1.9, released on December 1, 2015, strengthens application security with a configurable password validation system. This release lets you define complexity rules for user passwords and adds template improvements with conditional expressions.
Key Features
Password validation
The AUTH_PASSWORD_VALIDATORS setting defines a list of validators applied automatically when creating or changing a password. Django provides built-in validators and allows creating custom ones.
python
# settings.py
AUTH_PASSWORD_VALIDATORS = [
{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
'OPTIONS': {'min_length': 10}},
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
]
# Custom validator
from django.core.exceptions import ValidationError
class SpecialCharacterValidator:
"""Require at least one special character."""
def validate(self, password, user=None):
special_chars = set('!@#$%^&*()_+-=[]{}|;:,.<>?')
if not any(c in special_chars for c in password):
raise ValidationError(
'The password must contain at least one special character.',
code='no_special_char',
)
def get_help_text(self):
return 'The password must contain at least one special character.'
Permission mixins for class-based views
Password validators are accompanied by improved form widgets. Additionally, permission mixins for class-based views are added with LoginRequiredMixin, PermissionRequiredMixin, and UserPassesTestMixin.
python
from django.contrib.auth.mixins import (
LoginRequiredMixin,
PermissionRequiredMixin,
)
from django.views.generic import ListView, CreateView
class DocumentList(LoginRequiredMixin, ListView):
"""Accessible only to logged-in users."""
model = Document
template_name = 'documents/list.html'
login_url = '/login/'
class CreateReport(PermissionRequiredMixin, CreateView):
"""Requires the 'reports.add_report' permission."""
model = Report
fields = ['title', 'content']
permission_required = 'reports.add_report'
