Django ORM 详解:一对一、一对多、多对多
在 Django 的 ORM(对象关系映射)中,数据库的表之间通常需要建立关联关系。最常见的三种关系是:
- 一对一(OneToOneField):一个对象只能对应另一个对象,例如 一个用户只能有一个个人资料。
- 一对多(ForeignKey):一个对象可以关联多个对象,但多个对象只能属于同一个,例如 一个作者可以写多本书,但一本书只能有一个作者。
- 多对多(ManyToManyField):多个对象可以相互关联,例如 一个学生可以选多门课程,一门课程也可以有多个学生。
本文将以 循序渐进、通俗易懂 的方式,详细讲解 Django ORM 中如何使用 一对一、一对多、多对多 关系,并结合 代码示例和数据表结构 帮助你理解。
1. 一对一关系(OneToOneField)
什么是一对一?
一对一(1:1)关系,即 一个对象只能关联另一个对象,不能再关联其他对象。例如:
- 一个用户 只能有 一个个人资料,反过来也一样。
- 一个国家 只能有 一个首都,不能有多个。
模型设计
假设我们要管理用户的个人资料,每个用户只能对应一个个人资料,我们可以这样设计模型:
from django.db import models
from django.contrib.auth.models import User  # 导入 Django 自带的用户模型class Profile(models.Model):user = models.OneToOneField(User, on_delete=models.CASCADE)  # 一对一关系phone = models.CharField(max_length=15, blank=True, null=True)address = models.TextField(blank=True, null=True)def __str__(self):return self.user.username
解释
- OneToOneField(User, on_delete=models.CASCADE):- Profile关联- User,每个- User只能有一个- Profile。
- on_delete=models.CASCADE:如果- User被删除,- Profile也会被删除。
数据库表结构
Django 在 Profile 表中添加了 user_id 外键,并加上了 唯一约束:
CREATE TABLE Profile (id INTEGER PRIMARY KEY AUTOINCREMENT,user_id INTEGER UNIQUE NOT NULL,  -- 唯一外键,确保一对一关系phone VARCHAR(15),address TEXT,FOREIGN KEY (user_id) REFERENCES auth_user(id) ON DELETE CASCADE
);
如何使用
创建数据
user = User.objects.create(username="john_doe")  # 创建用户
profile = Profile.objects.create(user=user, phone="123456789", address="New York")  # 关联个人资料
查询数据
# 通过 user 获取 profile
user.profile.address  # 通过 profile 获取 user
profile.user.username  
删除数据
user.delete()  # 删除用户时,Profile 也会被删除
2. 一对多关系(ForeignKey)
什么是一对多?
一对多(1:N)关系,即 一个对象可以关联多个对象,但 多个对象只能属于一个对象。例如:
- 一个作者可以写多本书,但一本书只能有一个作者。
- 一个公司有多个员工,但一个员工只能属于一个公司。
模型设计
假设我们要管理作者和书籍,每个作者可以写多本书:
class Author(models.Model):name = models.CharField(max_length=100)def __str__(self):return self.nameclass Book(models.Model):title = models.CharField(max_length=200)author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name="books")  # 一对多关系def __str__(self):return self.title
解释
- ForeignKey(Author, on_delete=models.CASCADE):- Book通过外键- author关联- Author。
- related_name="books":这样- author.books.all()可以直接获取该作者的所有书籍。
- on_delete=models.CASCADE:如果- Author被删除,所有他的- Book也会被删除。
数据库表结构
Django 在 Book 表中添加 author_id 外键:
CREATE TABLE Book (id INTEGER PRIMARY KEY AUTOINCREMENT,title VARCHAR(200),author_id INTEGER NOT NULL,  -- 外键FOREIGN KEY (author_id) REFERENCES Author(id) ON DELETE CASCADE
);
如何使用
创建数据
author = Author.objects.create(name="J.K. Rowling")
book1 = Book.objects.create(title="Harry Potter 1", author=author)
book2 = Book.objects.create(title="Harry Potter 2", author=author)
查询数据
# 获取作者的所有书籍
author.books.all()# 获取某本书的作者
book1.author.name
3. 多对多关系(ManyToManyField)
什么是多对多?
多对多(M:N)关系,即 多个对象可以关联多个对象。例如:
- 一个学生可以选多门课程,一门课程也可以有多个学生。
- 一个用户可以加入多个群聊,一个群聊也可以有多个用户。
方法 1:Django 自动创建中间表
Django 可以 自动创建中间表 来管理多对多关系:
class Student(models.Model):name = models.CharField(max_length=100)def __str__(self):return self.nameclass Course(models.Model):title = models.CharField(max_length=200)students = models.ManyToManyField(Student, related_name="courses")  # 多对多关系def __str__(self):return self.title
自动生成的中间表
Django 自动创建 一个 隐藏的中间表:
CREATE TABLE course_students (id INTEGER PRIMARY KEY AUTOINCREMENT,student_id INTEGER NOT NULL,course_id INTEGER NOT NULL,FOREIGN KEY (student_id) REFERENCES Student(id),FOREIGN KEY (course_id) REFERENCES Course(id)
);
如何使用
添加关系
student1 = Student.objects.create(name="Alice")
course1 = Course.objects.create(title="Math")course1.students.add(student1)
查询数据
# 获取 Alice 选修的课程
student1.courses.all()# 获取选修 Math 课程的所有学生
course1.students.all()
方法 2:手动定义中间表
当 ManyToManyField 需要存储额外信息(如选课时间、成绩)时,需要手动创建中间表:
class Enrollment(models.Model):student = models.ForeignKey(Student, on_delete=models.CASCADE)course = models.ForeignKey(Course, on_delete=models.CASCADE)enrolled_at = models.DateTimeField(auto_now_add=True)  # 选课时间grade = models.CharField(max_length=5, blank=True, null=True)  # 选课成绩
查询数据
# 获取学生的选课及成绩
Enrollment.objects.filter(student=student1).values("course__title", "grade")
总结
| 关系类型 | 适用场景 | Django ORM 字段 | 
|---|---|---|
| 一对一 | 用户 - 个人资料 | OneToOneField | 
| 一对多 | 作者 - 书籍 | ForeignKey | 
| 多对多 | 学生 - 课程 | ManyToManyField | 
掌握这些 ORM 关系,可以帮助你更好地设计数据库结构,提高项目的可维护性!🚀
