Skip to content
thesarfo

Note

One-to-Many Relationships

Defining a one-to-many relationship with ForeignKey, plus a full ecommerce model set (Product, Customer, Order, Cart) showing on_delete choices.

views 0

Lets say we want a customer to have multiple addresses, we can define a one-to-many relationship by doing the following. First we need to make the field a ForeignKey instead of a OneToOneField, and then not specify a primary key. Not specifying a primary key means that we allow for duplicate primary keys to the same model/entity. See below

class Address(models.Model):
street = models.charField(max_length=255)
city = models.charField(max_length=255)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)

See below of practical examples of an ecommerce one-to-many relationship

from django.db import models
# Create your models here.
class Collection(models.Model):
title = models.CharField(max_length=255)
class Product(models.Model):
title = models.CharField(max_length=255)
description = models.TextField()
price = models.DecimalField(max_digits=6, decimal_places=2)
inventory = models.IntegerField()
last_update = models.DateTimeField(auto_now=True)
# 1toMany rlnshp with Collection
collection = models.ForeignKey(Collection, on_delete=models.PROTECT)
class Customer(models.Model):
#all part of choice fields
MEMBERSHIP_BRONZE = 'B'
MEMBERSHIP_SILVER = 'S'
MEMBERSHIP_GOLD= 'G'
MEMBERSHIP_CHOICES = [
(MEMBERSHIP_BRONZE, 'Bronze'),
(MEMBERSHIP_SILVER, 'Silver'),
(MEMBERSHIP_GOLD, 'Gold'),
]
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.EmailField(unique=True)
phone = models.IntegerField()
birth_date = models.DateField(null=True)
# read about choice fields in django
membership = models.CharField(max_length=1, choices=MEMBERSHIP_CHOICES, default=MEMBERSHIP_BRONZE)
class Order(models.Model):
PAYMENT_STATUS_PENDING = 'P'
PAYMENT_STATUS_COMPLETE = 'C'
PAYMENT_STATUS_FAILED = 'F'
PAYMENT_STATUS_CHOICES = [
(PAYMENT_STATUS_PENDING, 'Pending'),
(PAYMENT_STATUS_COMPLETE, 'Complete'),
(PAYMENT_STATUS_FAILED, 'Failed'),
]
placed_at = models.DateTimeField(auto_now_add=True)
payment_status = models.CharField(max_length=1, choices=PAYMENT_STATUS_CHOICES, default=PAYMENT_STATUS_PENDING)
# defining a 1toMany rlnshp with customer
customer = models.ForeignKey(Customer, on_delete=models.PROTECT)
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.PROTECT)
product = models.ForeignKey(Product, on_delete=models.PROTECT)
quantity = models.PositiveBigIntegerField()
unit_price = models.DecimalField(max_digits=6, decimal_places=2)
class Address(models.Model):
street = models.charField(max_length=255)
city = models.charField(max_length=255)
customer = models.OneToOneField(Customer, on_delete=models.CASCADE, primary_key=True)
class Cart(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
class CartItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
cart = models.ForeignKey(Order, on_delete=models.CASCADE)
quantity = models.PositiveSmallIntegerField()

The on_delete = models.PROTECT means that if the parent class/model is accidentally deleted, the child model will not be deleted as well.