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'

Sources