python
37 lines · 7 steps
Enforcing one default address per user in Django
A Django model uses a partial unique constraint so each user can have only one default address of each kind.
Explained by
highlit
1from django.db import models
2from django.db.models import Q
3from django.conf import settings
4
5
6class Address(models.Model):
7 class Kind(models.TextChoices):
8 SHIPPING = "shipping", "Shipping"
9 BILLING = "billing", "Billing"
10
11 user = models.ForeignKey(
12 settings.AUTH_USER_MODEL,
13 on_delete=models.CASCADE,
14 related_name="addresses",
15 )
16 kind = models.CharField(max_length=16, choices=Kind.choices)
17 line1 = models.CharField(max_length=255)
18 line2 = models.CharField(max_length=255, blank=True)
19 city = models.CharField(max_length=120)
20 postal_code = models.CharField(max_length=20)
21 country = models.CharField(max_length=2)
22 is_default = models.BooleanField(default=False)
23
24 class Meta:
25 constraints = [
26 models.UniqueConstraint(
27 fields=["user", "kind"],
28 condition=Q(is_default=True),
29 name="unique_default_address_per_user_kind",
30 ),
31 ]
32 indexes = [
33 models.Index(fields=["user", "kind"]),
34 ]
35
36 def __str__(self):
37 return f"{self.get_kind_display()} address for {self.user_id}"
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A UniqueConstraint with a condition becomes a partial index, enforcing uniqueness only for rows that match.
- 2TextChoices gives you a validated enum plus a human-readable display method for free.
- 3Pushing business rules like 'one default per kind' into the database prevents race conditions application code can't reliably catch.
Related explainers
python
from fastapi import FastAPI, WebSocket, WebSocketDisconnect app = FastAPI()
Building a WebSocket chat with FastAPI
websockets
broadcast
connection-management
Intermediate
9 steps
python
import time import uuid from django.utils.deprecation import MiddlewareMixin
Attaching per-request context in Django
middleware
request lifecycle
multi-tenancy
Intermediate
7 steps
python
import random from typing import Iterator, List
How reservoir sampling picks k items
reservoir-sampling
streaming
randomness
Intermediate
5 steps
python
import secrets from django.contrib.auth import authenticate, login from django.core.cache import cache
Two-factor login with OTP in Django
two-factor-auth
one-time-passwords
caching
Intermediate
9 steps
python
import re from functools import total_ordering from typing import Optional
Parsing and comparing semantic versions
regex
operator-overloading
sorting
Intermediate
7 steps
python
from typing import Any, Sequence, Mapping def render_markdown_table(
Rendering an aligned Markdown table in Python
string formatting
data transformation
closures
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/enforcing-one-default-address-per-user-in-django-explained-python-b96b/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.