Overview

Django 1.5, released on February 26, 2013, is a pivotal release for the framework. Its headline feature is the configurable user model via the AUTH_USER_MODEL setting, finally addressing one of the community's oldest requests. This release also brings experimental Python 3 support and streaming responses.

Key Features

Custom user model

The AUTH_USER_MODEL setting allows replacing the default User model with a fully custom one. You can use email as the primary identifier, add business-specific fields from the start, or tailor the model to the application's specific needs.

python
# settings.py
AUTH_USER_MODEL = 'accounts.CustomUser'

# accounts/models.py
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.db import models

class CustomUserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError('An email address is required')
        user = self.model(
            email=self.normalize_email(email), **extra_fields
        )
        user.set_password(password)
        user.save(using=self._db)
        return user

class CustomUser(AbstractBaseUser):
    email = models.EmailField(unique=True)
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    is_active = models.BooleanField(default=True)

    objects = CustomUserManager()
    USERNAME_FIELD = 'email'

    def __str__(self):
        return self.email

Streaming responses

The StreamingHttpResponse class allows sending an HTTP response in chunks, without loading the entire content into memory. This is especially useful for exporting large CSV files or generating bulky reports.

python
import csv
from django.http import StreamingHttpResponse

def generate_csv_rows(queryset):
    """Generate CSV rows one at a time."""
    yield ['Name', 'Email', 'Joined']
    for user in queryset.iterator():
        yield [
            user.last_name,
            user.email,
            user.date_joined.isoformat(),
        ]

class CSVBuffer:
    """Adapter for streaming CSV output."""
    def write(self, value):
        return value

def export_users(request):
    queryset = CustomUser.objects.all()
    writer = csv.writer(CSVBuffer())
    rows = (writer.writerow(row) for row in generate_csv_rows(queryset))
    response = StreamingHttpResponse(rows, content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="users.csv"'
    return response

Sources