目录

  1. 什么是 Django ORM 的多表关系?
  2. 一对多关系
  3. 多对多关系
  4. 一对一关系
  5. 使用 Django ORM 进行多表查询
  6. 常见问题与解决方案
  7. 参考资料

1. 什么是 Django ORM 的多表关系?

Django ORM 允许你在数据库中使用多个相关的表,并通过模型类进行表示。这些关系可以是 一对多多对多一对一。这些关系可以通过定义外键(ForeignKey)、多对多字段(ManyToManyField)和一对一字段(OneToOneField)来实现。

Django ORM 提供了强大的查询接口来处理多表关联查询。你可以通过关联模型的字段实现联合查询(JOIN)来获取相关数据。


2. 一对多关系

在一对多关系中,一个表的记录可以与另一个表的多个记录相关联。例如,一个博客文章可以有多个评论,但每个评论只属于一个文章。

2.1 定义一对多关系

使用 ForeignKey 实现一对多关系。假设我们有两个模型:AuthorBook,一个作者可以有多本书,但是每本书只能有一个作者。

# myapp/models.py
from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)  # 外键关系,表示一对多

    def __str__(self):
        return self.title

2.2 使用外键查询

# 查询某个作者的所有书籍
author = Author.objects.get(id=1)
books = author.book_set.all()  # 使用 related_name 默认属性获取相关联的 Book
for book in books:
    print(book.title)

在这里,author.book_set.all() 获取与指定作者关联的所有书籍。Django 自动为外键关系提供了 book_set,它是与 Author 模型相关联的所有 Book 实例的查询集。


3. 多对多关系

在多对多关系中,两个表中的记录都可以与对方的多个记录相关联。例如,学生可以选修多门课程,而每门课程也可以有多个学生。

3.1 定义多对多关系

使用 ManyToManyField 实现多对多关系。假设我们有 StudentCourse 模型,一个学生可以选修多门课程,且每门课程可以有多个学生。

# myapp/models.py
from django.db import models

class Student(models.Model):
    name = models.CharField(max_length=100)
    courses = models.ManyToManyField('Course', related_name='students')  # 多对多关系

    def __str__(self):
        return self.name

class Course(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

3.2 使用多对多查询

# 获取某个学生选修的所有课程
student = Student.objects.get(id=1)
courses = student.courses.all()
for course in courses:
    print(course.name)

# 获取某门课程的所有学生
course = Course.objects.get(id=1)
students = course.students.all()
for student in students:
    print(student.name)

在这里,student.courses.all() 获取该学生选修的所有课程,而 course.students.all() 获取该课程的所有学生。


4. 一对一关系

在一对一关系中,一个表的记录与另一个表的记录一一对应。例如,每个用户都有一个个人资料,且每个个人资料仅属于一个用户。

4.1 定义一对一关系

使用 OneToOneField 实现一对一关系。假设我们有 UserProfile 模型,一个用户只能有一个个人资料。

# myapp/models.py
from django.db import models

class User(models.Model):
    username = models.CharField(max_length=100)

    def __str__(self):
        return self.username

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)  # 一对一关系
    bio = models.TextField()

    def __str__(self):
        return f"Profile of {self.user.username}"

4.2 使用一对一查询

# 获取某个用户的个人资料
user = User.objects.get(id=1)
profile = user.profile  # 使用自动生成的 related_name 'profile'
print(profile.bio)

# 获取某个个人资料所属的用户
profile = Profile.objects.get(id=1)
user = profile.user
print(user.username)

在这里,user.profile 通过自动生成的 related_name 获取与用户相关联的个人资料,而 profile.user 获取与个人资料相关联的用户。


5. 使用 Django ORM 进行多表查询

Django ORM 支持多表查询,你可以使用关联模型的字段进行联合查询。以下是常见的多表查询方法:

5.1 select_related – 一对多和一对一关系的优化

select_related 用于一对多和一对一关系的查询,它通过一次数据库查询获取相关的模型数据,避免了多次查询,提高查询效率。

# 获取所有书籍及其作者(优化查询)
books = Book.objects.select_related('author').all()
for book in books:
    print(book.title, book.author.name)

在这个查询中,select_related 会在一次查询中获取所有书籍及其作者的信息。

5.2 prefetch_related – 多对多关系的优化

prefetch_related 用于多对多关系的查询,它可以在一次查询中获取相关的多个对象。

# 获取所有学生及其选修的课程(优化查询)
students = Student.objects.prefetch_related('courses').all()
for student in students:
    print(student.name)
    for course in student.courses.all():
        print(course.name)

prefetch_related 会执行两次查询:一次获取所有学生,另一次获取所有与这些学生相关的课程。


6. 常见问题与解决方案

1. 外键字段 related_name 不工作

  • 如果你自定义了 related_name 属性,请确保你在访问时使用了正确的字段名。默认情况下,外键的反向关系使用模型名称加 _set 后缀。

2. select_relatedprefetch_related 的区别

  • select_related 用于一对多和一对一关系的优化,它通过 SQL JOIN 一次查询相关对象。
  • prefetch_related 用于多对多和反向一对多关系,它执行两次查询,减少数据库查询次数。

3. 外键删除时的行为

  • ForeignKeyon_delete 参数控制了外键相关对象删除时的行为,常用的选项包括 CASCADE(级联删除)、SET_NULL(设置为 NULL)等。

7. 参考资料

出站链接

站内链接