一、Django ORM 常用字段类型
1. 基础字段类型
字段类型 | 说明 | 示例 |
---|---|---|
CharField | 字符串字段,必须指定 max_length | name = models.CharField(max_length=50) |
IntegerField | 整数字段 | age = models.IntegerField() |
BooleanField | 布尔值字段 | is_active = models.BooleanField() |
DateField / DateTimeField | 日期/日期时间字段,auto_now_add=True 自动设置创建时间 | created_at = models.DateTimeField(auto_now_add=True) |
EmailField | 专用于邮箱的 CharField (自带基础格式验证) | email = models.EmailField() |
TextField | 长文本字段(不限长度) | content = models.TextField() |
FileField / ImageField | 文件/图片上传字段(需 Pillow 库支持 ImageField ) | avatar = models.ImageField(upload_to='avatars/') |
2. 关联字段类型
字段类型 | 说明 | 示例 |
---|---|---|
ForeignKey | 外键(一对多关联) | author = models.ForeignKey('Author', on_delete=models.CASCADE) |
OneToOneField | 一对一关联(常用于扩展用户模型) | profile = models.OneToOneField(User, on_delete=models.CASCADE) |
ManyToManyField | 多对多关联(自动创建中间表) | tags = models.ManyToManyField('Tag') |
关键参数说明:
on_delete
: 关联对象删除时的行为(必填),常见选项:CASCADE
: 级联删除(默认)SET_NULL
: 设为null
(需字段允许null=True
)PROTECT
: 阻止删除
related_name
: 反向查询时的名称(默认模型名_set
,如book_set
)
二、跨表引用技巧
1. 正向查询(直接通过外键访问)
# 模型定义
class Author(models.Model):name = models.CharField(max_length=100)class Book(models.Model):title = models.CharField(max_length=100)author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name="books")# 示例:查询某本书的作者
book = Book.objects.get(id=1)
author_name = book.author.name # 直接通过外键访问
2. 反向查询(通过关联模型反向访问)
# 示例:查询某作者的所有书籍
author = Author.objects.get(id=1)
books = author.books.all() # 使用 related_name 定义的名称(默认是 book_set)
3. 跨表过滤(使用双下划线 __)
# 查询所有书籍的作者名为 "鲁迅" 的书籍
books = Book.objects.filter(author__name="鲁迅")# 查询作者出版过书籍数量大于 5 的作者
authors = Author.objects.annotate(book_count=Count('books')).filter(book_count__gt=5)
三、_
和 __
的使用技巧
1. 单下划线 _
- 用途:用于关联字段的数据库列名或 ORM 内部操作。
- 示例:
# 访问外键的数据库列名(author_id) book = Book.objects.get(id=1) author_id = book.author_id # 直接获取外键值(无需访问关联对象)# 查询时直接使用字段名 Book.objects.filter(author_id=1)
2. 双下划线 __
- 用途:跨表查询时连接关联模型的字段(可链式跨多张表)。
- 示例:
# 查询作者所在城市为 "北京" 的书籍 Book.objects.filter(author__city="北京")# 多级跨表:查询书籍的作者的出版社名称 Book.objects.filter(author__publisher__name="人民出版社")
3. 双下划线与查询表达式结合
# 查询价格大于 100 且作者年龄小于 30 的书籍
Book.objects.filter(price__gt=100, author__age__lt=30)# 查询书名以 "Django" 开头或作者邮箱包含 "@example.com"
from django.db.models import Q
Book.objects.filter(Q(title__startswith="Django") | Q(author__email__contains="@example.com"))
四、总结
核心技巧
-
字段类型选择:
- 根据数据类型选择合适字段(如
CharField
vsTextField
)。 - 关联字段注意
on_delete
和related_name
的设置。
- 根据数据类型选择合适字段(如
-
跨表查询:
- 正向查询:直接通过外键字段访问关联对象。
- 反向查询:使用
related_name
或默认的模型名_set
。 - 复杂查询:通过
__
跨表连接字段。
-
_
vs__
:_
用于数据库列名或单级字段访问(如author_id
)。__
用于跨表查询(如author__name
)。
性能优化
- 使用
select_related
预加载外键数据(减少查询次数):books = Book.objects.select_related('author').all() # 一次性加载作者信息
- 使用
prefetch_related
预加载多对多关系:authors = Author.objects.prefetch_related('books').all() # 预加载所有书籍
通过灵活组合这些技巧,可以高效操作 Django ORM 处理复杂的数据关系!
好的!反向查询是 Django ORM 中通过关联模型(比如外键的“被关联方”)去访问发起关联的模型的关键操作。它让跨表查询更灵活,下面用详细的示例和场景帮你彻底理解。
一、反向查询的核心原理
假设有两个模型:Author
(作者)和 Book
(书籍),通过外键关联:
class Author(models.Model):name = models.CharField(max_length=100)class Book(models.Model):title = models.CharField(max_length=100)author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
- 正向查询:从
Book
访问Author
(直接通过外键字段author
)。 - 反向查询:从
Author
访问所有关联的Book
对象(需要借助related_name
或默认的book_set
)。
二、反向查询的两种方式
1. 使用默认的 模型名_set
如果未设置 related_name
,Django 会自动生成反向查询管理器,格式为:关联模型名的小写 + _set
。
# 假设 Book 模型的外键未设置 related_name
class Book(models.Model):author = models.ForeignKey(Author, on_delete=models.CASCADE)# 反向查询:通过 author.book_set 访问所有书籍
author = Author.objects.get(id=1)
books = author.book_set.all() # 获取该作者的所有书籍
2. 使用自定义的 related_name
通过设置 related_name
,可以指定更直观的反向查询名称:
class Book(models.Model):author = models.ForeignKey(Author, on_delete=models.CASCADE,related_name='books' # 自定义反向查询名称)# 反向查询:通过 author.books 访问所有书籍
author = Author.objects.get(id=1)
books = author.books.all() # 更直观的命名
三、反向查询的常见操作
1. 获取关联对象集合
# 查询作者 "鲁迅" 的所有书籍
author = Author.objects.get(name="鲁迅")
books = author.books.all() # 返回 QuerySet
2. 过滤关联对象
# 查询作者 "鲁迅" 的出版年份大于 2020 的书籍
books = author.books.filter(publish_year__gt=2020)
3. 创建新的关联对象
# 为作者 "鲁迅" 创建一本新书
new_book = author.books.create(title="狂人日记", publish_year=1918)
4. 统计关联对象数量
# 统计作者 "鲁迅" 的书籍数量
book_count = author.books.count()
四、反向查询在跨表过滤中的使用
反向查询结合双下划线 __
,可以在查询条件中直接穿透关联模型。
场景1:查询所有写过“小说”类书籍的作者
# 模型扩展:书籍增加分类字段
class Book(models.Model):CATEGORY_CHOICES = [('novel', '小说'),('tech', '科技'),]category = models.CharField(max_length=10, choices=CATEGORY_CHOICES)author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')# 反向查询:直接通过 Author 模型过滤
authors = Author.objects.filter(books__category='novel').distinct()
books__category
:从Author
穿透到Book
的category
字段。distinct()
:避免重复作者(如果同一作者有多本小说)。
场景2:查询书籍平均评分大于 4.5 的作者
from django.db.models import Avg# 模型扩展:书籍增加评分字段
class Book(models.Model):rating = models.FloatField(default=0)author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')# 使用 annotate + 反向查询
authors = Author.objects.annotate(avg_rating=Avg('books__rating')
).filter(avg_rating__gt=4.5)
五、反向查询的性能优化
1. 使用 prefetch_related
预加载数据
避免 N+1 查询问题(遍历作者时,每次访问 author.books
都会触发一次查询):
# 未优化:触发多次查询
authors = Author.objects.all()
for author in authors:print(author.books.all()) # 每次循环触发一次查询# 优化后:一次性预加载所有作者的书籍
authors = Author.objects.prefetch_related('books').all()
for author in authors:print(author.books.all()) # 无额外查询
2. 结合 select_related
和 prefetch_related
select_related
:用于外键(一对一、多对一)的预加载。prefetch_related
:用于多对多、反向查询的预加载。
# 同时预加载作者和书籍的出版社(假设 Book 有外键到 Publisher)
authors = Author.objects.prefetch_related(Prefetch('books', queryset=Book.objects.select_related('publisher'))
).all()
六、总结:反向查询的核心技巧
操作 | 代码示例 | 说明 |
---|---|---|
基本反向查询 | author.books.all() | 获取所有关联对象 |
过滤关联对象 | author.books.filter(title__contains="Django") | 根据条件筛选关联对象 |
跨表过滤 | Author.objects.filter(books__rating__gt=4) | 在查询条件中使用反向关联字段 |
聚合统计 | Author.objects.annotate(book_count=Count('books')) | 统计每个作者的书籍数量 |
预加载优化 | prefetch_related('books') | 减少数据库查询次数 |
关键点:
- 始终优先使用
related_name
自定义反向查询名称(代码更清晰)。 - 在复杂查询中灵活使用双下划线
__
穿透关联模型。 - 大数据量时用
prefetch_related
或select_related
优化性能。
通过反向查询,你可以轻松实现从“一”对“多”或“多对多”关系的反向导航,让数据关联操作更加灵活高效!