Django 4.2 LTS: Psycopg3 and Model Comments
Django 4.2 is the new LTS release, supported until April 2026. Notable additions include Psycopg 3 support, model field comments, and transaction hooks. Here’s what you need to know.
Psycopg 3 Support
Django now supports both Psycopg 2 and 3:
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql', # Works with both
'NAME': 'mydb',
# Psycopg 3 used automatically if installed
}
}
Why Psycopg 3
| Feature | Psycopg 2 | Psycopg 3 |
|---|---|---|
| Async support | Limited | Native |
| Connection pooling | External | Built-in |
| Type adaptation | Complex | Simpler |
| Maintenance | Legacy | Active |
Migration
# Replace psycopg2
pip uninstall psycopg2-binary
pip install psycopg[binary] # or psycopg[c] for compiled
Most code works unchanged.
Database Field Comments
Document your schema in the database:
class Product(models.Model):
name = models.CharField(
max_length=255,
db_comment="Product display name"
)
price = models.DecimalField(
max_digits=10,
decimal_places=2,
db_comment="Price in default currency (USD)"
)
sku = models.CharField(
max_length=50,
unique=True,
db_comment="Stock Keeping Unit - unique product identifier"
)
class Meta:
db_table = "products"
db_table_comment = "Product catalog including pricing and inventory"
-- Generated SQL
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL, -- COMMENT 'Product display name'
...
);
COMMENT ON TABLE products IS 'Product catalog including pricing and inventory';
Comments appear in database tools and documentation.
Transaction Hooks
Execute code when transactions complete:
from django.db import transaction
def create_user_with_welcome_email(name, email):
with transaction.atomic():
user = User.objects.create(name=name, email=email)
Profile.objects.create(user=user)
# Only send email if transaction commits
transaction.on_commit(lambda: send_welcome_email(user))
# Email sent after the with block exits (if no exception)
Robust Hooks
transaction.on_commit(
lambda: send_notification(user_id),
robust=True # Continue even if callback fails
)
Composite Primary Keys (Preview)
Experimental support for multi-column primary keys:
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.IntegerField()
class Meta:
constraints = [
models.CompoundPrimaryKey('order', 'product'), # Experimental
]
Generate-Only Fields
Fields populated by the database:
class Article(models.Model):
title = models.CharField(max_length=255)
created_at = models.DateTimeField(
db_default=Now() # Database generates this
)
slug = models.GeneratedField(
expression=Lower(F("title")),
output_field=models.CharField(max_length=255),
db_persist=True # Stored, not computed on read
)
Validation Improvements
StepValueValidator
from django.core.validators import StepValueValidator
class Measurement(models.Model):
# Value must be a multiple of 0.5
temperature = models.DecimalField(
max_digits=5,
decimal_places=1,
validators=[StepValueValidator(0.5)]
)
Constraint Validation Messages
class Reservation(models.Model):
start = models.DateTimeField()
end = models.DateTimeField()
class Meta:
constraints = [
models.CheckConstraint(
check=Q(end__gt=F('start')),
name='valid_date_range',
violation_error_message="End must be after start"
)
]
Admin Improvements
Dark Mode
Automatic dark mode based on system preference:
# No configuration needed - follows prefers-color-scheme
Faceted Filters
class ArticleAdmin(admin.ModelAdmin):
list_filter = [
('status', admin.EmptyFieldListFilter), # Filter by empty/non-empty
('category', admin.RelatedFieldListFilter), # With counts
]
Async QuerySet Methods
Continued async ORM expansion:
# New in 4.2
await Article.objects.acontains(article)
await Article.objects.aexists()
# Async iteration with generator
async for article in Article.objects.filter(published=True):
await process(article)
Migration Squashing
Improved support for squashing migrations:
python manage.py squashmigrations myapp 0001 0050
Better handling of:
- RunPython operations
- elidable operations
- Circular dependencies
Other Notable Changes
URL Dispatcher
# Path converters can now be complex
path('items/<list:ids>/', views.items) # Custom converter for lists
Template Engine
# Improved render speed for complex templates
# No code changes required
Security
# CSRF token masking to prevent BREACH
CSRF_COOKIE_MASKED = True # Default in 4.2
Upgrade Path
From 4.0/4.1
Straightforward:
pip install Django>=4.2,<4.3
python manage.py migrate
From 3.2 LTS
More changes. Check deprecation warnings:
python -W error::DeprecationWarning manage.py check
Key breaking changes:
CSRF_TRUSTED_ORIGINSneeds scheme- Form rendering uses templates
- Some imports moved
LTS Timeline
Django 3.2 LTS: Supported until April 2024
Django 4.2 LTS: Supported until April 2026
Django 5.2 LTS: Expected April 2025
For production apps, 4.2 is the target.
Final Thoughts
Django 4.2 is a solid LTS release. Psycopg 3 support is the headline, but the quality-of-life improvements (comments, transaction hooks, validation) make daily development smoother.
If you’re on 3.2, now’s a good time to plan the upgrade.
Django 4.2: Three years of stability and support.