Django ORM – 多表实例(手把手讲解)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
前言:为什么需要掌握 Django ORM 的多表操作?
在 Web 开发中,数据库设计往往是系统架构的核心。Django 的 ORM(对象关系映射)作为其核心特性之一,通过 Python 代码抽象了底层 SQL 的复杂性,让开发者能够更高效地操作数据库。然而,当项目涉及多个表之间的复杂关系时,如何通过 Django ORM 实现多表关联、查询和操作,便成为开发者必须掌握的关键技能。
本文将从基础概念出发,通过具体案例和代码示例,逐步讲解 Django ORM 中多表操作的核心知识点。无论是编程初学者还是有一定经验的开发者,都能通过本文快速理解多表实例的实现逻辑,并掌握如何在实际项目中灵活应用。
一对一关系:像书签一样精准关联
概念与比喻
一对一关系(One-to-One)类似于现实生活中的“身份证与个人信息”的绑定:每个身份证号对应唯一一个人,反之亦然。在 Django 中,这种关系通过 OneToOneField
实现,通常用于扩展用户模型或需要单独存储的关联数据。
示例代码
假设我们需要为用户模型添加详细的个人信息:
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(blank=True)
birthday = models.DateField(null=True)
关键点解析
on_delete=models.CASCADE
:当关联的用户被删除时,自动删除该 UserProfile。- 查询示例:通过
user.userprofile
可直接访问关联对象,无需额外查询。
一对多关系:如同图书馆的书籍与作者
概念与比喻
一对多关系(One-to-Many)类似于“作者与书籍”的关系:一个作者可以写多本书,但每本书只能有一个作者。在 Django 中,这种关系通过 ForeignKey
实现,外键字段通常位于“多”的一方(如书籍模型)。
示例代码
以博客系统为例:
class Author(models.Model):
name = models.CharField(max_length=100)
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='articles')
关键点解析
- 反向查询:通过
related_name
可以直接通过作者访问其所有文章,例如author.articles.all()
。 - 逆向操作:若删除作者,其所有文章会被级联删除(因
on_delete=models.CASCADE
)。
多对多关系:像社交网络的“关注”功能
概念与比喻
多对多关系(Many-to-Many)类似于“用户与关注列表”的关系:用户 A 可以关注多个用户,同时也能被其他用户关注。在 Django 中,这种关系通过 ManyToManyField
实现,默认会自动生成中间表。
示例代码
以电商平台的“用户与收藏商品”为例:
class User(models.Model):
username = models.CharField(max_length=50)
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
favorites = models.ManyToManyField(User, related_name='favorite_products')
关键点解析
- 中间表管理:Django 自动创建
product_favorite
表,存储用户与商品的关联关系。 - 查询示例:
# 获取用户收藏的所有商品 user = User.objects.get(username='Alice') products = user.favorite_products.all() # 将商品添加到收藏 product = Product.objects.get(name='iPhone 15') product.favorites.add(user)
跨表查询:如何高效获取关联数据?
选择性查询:避免“笛卡尔积”陷阱
当需要同时获取多表数据时,select_related()
和 prefetch_related()
是两个关键方法:
select_related
:用于一对一或一对多关系,通过 SQL 的 JOIN 操作一次性获取数据。prefetch_related
:用于多对多或反向一对多关系,通过两次查询减少数据库压力。
示例代码
articles = Article.objects.select_related('author').all()
for article in articles:
print(article.author.name) # 不会触发额外查询
聚合与分组:统计作者的文章总数
Django ORM 支持通过 annotate()
和 Count
实现聚合查询:
from django.db.models import Count
authors = Author.objects.annotate(total_articles=Count('articles')).order_by('-total_articles')
for author in authors:
print(f"{author.name} 写了 {author.total_articles} 篇文章")
实战案例:电商系统的订单与用户关系
系统设计需求
假设我们开发一个电商平台,需要实现以下功能:
- 用户可以提交订单,每个订单包含多个商品。
- 每个商品属于一个分类。
模型设计
class Category(models.Model):
name = models.CharField(max_length=50)
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
category = models.ForeignKey(Category, on_delete=models.PROTECT)
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
created_at = models.DateTimeField(auto_now_add=True)
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='items')
product = models.ForeignKey(Product, on_delete=models.PROTECT)
quantity = models.PositiveIntegerField()
关键操作示例
- 创建订单:
user = User.objects.get(username='Bob')
order = Order.objects.create(user=user)
product = Product.objects.get(name='Coffee Mug')
OrderItem.objects.create(order=order, product=product, quantity=2)
- 查询用户所有订单的总金额:
from django.db.models import Sum
total = OrderItem.objects.filter(order__user=user) \
.annotate(total_price=F('product__price') * F('quantity')) \
.aggregate(Sum('total_price'))['total_price__sum']
结论:多表实例是 Django 项目的进阶之路
掌握 Django ORM 的多表操作,不仅是提升开发效率的关键,更是构建复杂系统的基础。通过本文的案例和代码示例,读者可以:
- 理解一对一、一对多、多对多关系的核心逻辑;
- 学会通过
select_related
和prefetch_related
优化查询性能; - 在实际项目中设计合理的模型结构,实现数据关联与复用。
Django ORM 的强大之处在于其简洁性与灵活性,但真正的应用需要开发者结合业务场景不断实践。建议读者通过搭建小型项目(如博客系统或电商应用),逐步巩固多表操作的知识,最终实现从“会用”到“精通”的跨越。