class Customer(models.Model):
name = models.CharField(max_length=100)
class Order(models.Model):
customer = models.ForeignKey(
Customer,
on_delete=models.CASCADE, # what happens to Orders when their Customer is deleted
related_name="orders", # customer.orders.all() instead of customer.order_set.all()
)
class Tag(models.Model):
name = models.CharField(max_length=50)
class Product(models.Model):
tags = models.ManyToManyField(Tag, related_name="products")
class Profile(models.Model):
user = models.OneToOneField("auth.User", on_delete=models.CASCADE)
on_delete options, and why the choice actually mattersmodels.CASCADE # delete this row too when the related row is deleted
models.PROTECT # raise ProtectedError — refuse to delete the related row at all
models.SET_NULL # set this FK to NULL (requires null=True on the field)
models.SET_DEFAULT # set this FK to its default value
Picking CASCADE for every foreign key by default is a common early mistake — it's exactly right for genuinely dependent data (deleting an Order should delete its OrderLine items), but deleting a Customer and silently cascading away every historical Order they ever placed is rarely the intended behavior for financial/audit data; PROTECT or SET_NULL is often the safer default there.
related_name and reverse relationshipsA ForeignKey automatically creates a reverse accessor on the other side of the relationship — by default named <lowercase model>_set, or the explicit related_name if given:
customer = Customer.objects.get(pk=1)
customer.orders.all() # every Order pointing at this customer, via related_name="orders"
# without related_name, this would be customer.order_set.all()
Two ForeignKeys from the same model to the same target must have distinct related_names (or Django raises an error at startup) — this is the most common reason related_name shows up explicitly in real code rather than being left to its default.