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

Walkthrough

Space play step click any line
Three takeaways
  1. 1A UniqueConstraint with a condition becomes a partial index, enforcing uniqueness only for rows that match.
  2. 2TextChoices gives you a validated enum plus a human-readable display method for free.
  3. 3Pushing business rules like 'one default per kind' into the database prevents race conditions application code can't reliably catch.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Enforcing one default address per user in Django — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code