Django ORM 详细教程
Django ORM 是 Django 框架内置的对象关系映射工具,它提供了一种 Pythonic 的方式来与数据库交互,而无需直接编写 SQL。本教程将全面介绍 Django ORM 的使用方法。
目录
- 模型定义
- 模型字段
- 模型关系
- 迁移操作
- 基本CRUD
- 查询集(QuerySet)
- 高级查询
- 聚合与注解
- 事务管理
- 性能优化
- 原生SQL
1. 模型定义
创建模型
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField(unique=True)
birth_date = models.DateField()
bio = models.TextField(blank=True)
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
publish_date = models.DateField()
price = models.DecimalField(max_digits=5, decimal_places=2)
is_published = models.BooleanField(default=True)
def __str__(self):
return self.title
元选项
class Book(models.Model):
class Meta:
ordering = ['-publish_date']
verbose_name = '图书'
verbose_name_plural = '图书'
indexes = [
models.Index(fields=['title'], name='title_idx'),
]
unique_together = [['title', 'author']]
2. 模型字段
常用字段类型
字段类型 |
描述 |
CharField |
字符串字段,必须指定 max_length |
TextField |
大文本字段 |
IntegerField |
整数 |
DecimalField |
十进制小数,需指定 max_digits 和 decimal_places |
BooleanField |
布尔值 |
DateField |
日期 |
DateTimeField |
日期时间 |
EmailField |
带有 Email 验证的 CharField |
URLField |
带有 URL 验证的 CharField |
FileField |
文件上传字段 |
ImageField |
继承 FileField,验证是否为有效图像 |
字段选项
models.CharField(
max_length=100,
null=True,
blank=True,
default='unknown',
choices=[
('M', 'Male'),
('F', 'Female'),
('O', 'Other')
],
unique=True,
db_index=True,
verbose_name='名称'
)
3. 模型关系
一对一关系
class Profile(models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
primary_key=True
)
address = models.CharField(max_length=100)
phone = models.CharField(max_length=20)
一对多关系
class Publisher(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
publisher = models.ForeignKey(
Publisher,
on_delete=models.CASCADE,
related_name='books'
)
多对多关系
class Student(models.Model):
name = models.CharField(max_length=100)
courses = models.ManyToManyField(
'Course',
through='Enrollment',
through_fields=('student', 'course')
)
class Course(models.Model):
title = models.CharField(max_length=100)
class Enrollment(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE)
course = models.ForeignKey(Course, on_delete=models.CASCADE)
date_enrolled = models.DateField()
grade = models.CharField(max_length=2, blank=True)
4. 迁移操作
创建迁移
python manage.py makemigrations
应用迁移
python manage.py migrate
迁移命令
命令 |
描述 |
showmigrations |
显示所有迁移状态 |
sqlmigrate <app> <migration> |
显示迁移的SQL语句 |
migrate <app> <migration> |
迁移到特定版本 |
migrate --fake |
标记迁移为已完成但不执行 |
migrate --plan |
显示迁移计划 |
5. 基本CRUD
创建(Create)
author = Author.objects.create(
name='J.K. Rowling',
email='jk@example.com',
birth_date='1965-07-31'
)
book = Book(
title='Harry Potter',
author=author,
publish_date='1997-06-26',
price=19.99
)
book.save()
Book.objects.bulk_create([
Book(title='Book1', author=author, publish_date='2020-01-01', price=10),
Book(title='Book2', author=author, publish_date='2020-02-01', price=15)
])
读取(Read)
book = Book.objects.get(pk=1)
book = Book.objects.get(title__exact='Harry Potter')
books = Book.objects.all()
books = Book.objects.filter(price__gt=10)
更新(Update)
book = Book.objects.get(pk=1)
book.price = 25.99
book.save()
Book.objects.filter(publish_date__year=2020).update(price=20)
author = Author.objects.get(name='J.K. Rowling')
Book.objects.filter(pk=1).update(author=author)
删除(Delete)
book = Book.objects.get(pk=1)
book.delete()
Book.objects.filter(price__lt=10).delete()
6. 查询集(QuerySet)
链式调用
books = Book.objects.filter(
publish_date__year__gte=2000
).exclude(
price__gt=30
).order_by(
'-publish_date'
)
常用查询方法
方法 |
描述 |
all() |
返回所有记录 |
filter(**kwargs) |
返回满足条件的记录 |
exclude(**kwargs) |
返回不满足条件的记录 |
order_by(*fields) |
排序 |
values(*fields) |
返回字典列表 |
values_list(*fields) |
返回元组列表 |
distinct() |
去重 |
select_related() |
预取外键关联 |
prefetch_related() |
预取多对多关联 |
annotate() |
添加注解 |
aggregate() |
聚合计算 |
count() |
计数 |
exists() |
判断是否存在 |
first() |
第一条记录 |
last() |
最后一条记录 |
延迟查询
books = Book.objects.all()
print(books)
for book in books:
print(book)
if books:
print("有数据")
list(books)
7. 高级查询
字段查找(Field Lookups)
Book.objects.filter(title__exact='Harry Potter')
Book.objects.filter(title='Harry Potter')
Book.objects.filter(title__contains='Potter')
Book.objects.filter(title__startswith='Harry')
Book.objects.filter(title__endswith='Potter')
Book.objects.filter(title__iexact='harry potter')
Book.objects.filter(price__isnull=True)
Book.objects.filter(price__range=(10, 20))
from datetime import date
Book.objects.filter(publish_date__year=2020)
Book.objects.filter(publish_date__gte=date(2020, 1, 1))
Book.objects.filter(title__regex=r'^(An?|The) ')
Q对象(复杂查询)
from django.db.models import Q
Book.objects.filter(Q(price__lt=10) | Q(price__gt=20))
Book.objects.filter(Q(title__contains='Potter') & Q(price__lt=20))
Book.objects.filter(~Q(publish_date__year=2020))
F对象(字段比较)
from django.db.models import F
Book.objects.filter(price__gt=F('discount_price'))
Book.objects.update(price=F('price') * 1.1)
8. 聚合与注解
聚合函数
from django.db.models import Count, Avg, Max, Min, Sum
Book.objects.aggregate(Avg('price'))
Book.objects.aggregate(
avg_price=Avg('price'),
max_price=Max('price'),
min_price=Min('price')
)
Author.objects.annotate(num_books=Count('book')).filter(num_books__gt=5)
注解(Annotations)
from django.db.models import Value
from django.db.models.functions import Concat
books = Book.objects.annotate(
price_with_tax=F('price') * 1.2,
full_title=Concat('title', Value(' by '), 'author__name')
)
expensive_books = Book.objects.annotate(
price_with_tax=F('price') * 1.2
).filter(
price_with_tax__gt=30
)
9. 事务管理
自动提交模式(默认)
book = Book.objects.get(pk=1)
book.price = 25.99
book.save()
手动事务
from django.db import transaction
try:
with transaction.atomic():
book1 = Book.objects.select_for_update().get(pk=1)
book1.price += 10
book1.save()
book2 = Book.objects.get(pk=2)
book2.price -= 5
book2.save()
except Exception as e:
print(f"Error: {e}")
保存点
with transaction.atomic():
sid = transaction.savepoint()
try:
book1 = Book.objects.get(pk=1)
book1.price += 10
book1.save()
book2 = Book.objects.get(pk=2)
book2.price -= 15
book2.save()
except:
transaction.savepoint_rollback(sid)
raise
10. 性能优化
books = Book.objects.all()
for book in books:
print(book.author.name)
books = Book.objects.select_related('author').all()
for book in books:
print(book.author.name)
authors = Author.objects.all()
for author in authors:
print(author.book_set.all())
authors = Author.objects.prefetch_related('book_set').all()
for author in authors:
print(author.book_set.all())
只获取需要的字段
books = Book.objects.all()
books = Book.objects.only('title', 'price')
books = Book.objects.defer('bio')
批量操作
Book.objects.bulk_create([
Book(title='Book1', price=10),
Book(title='Book2', price=15)
])
books = Book.objects.filter(publish_date__year=2020)
for book in books:
book.price *= 1.1
Book.objects.bulk_update(books, ['price'])
11. 原生SQL
执行原生查询
from django.db import connection
books = Book.objects.raw('SELECT * FROM myapp_book WHERE price > %s', [10])
with connection.cursor() as cursor:
cursor.execute("UPDATE myapp_book SET price = price * 1.1 WHERE price < %s", [20])
row = cursor.fetchone()
自定义SQL表达式
from django.db.models import Func
class UpperCase(Func):
function = 'UPPER'
template = '%(function)s(%(expressions)s)'
Author.objects.annotate(
upper_name=UpperCase('name')
)
总结
Django ORM 提供了强大而直观的数据库访问方式,通过本教程你应该掌握了:
- 如何定义模型和关系
- 基本的CRUD操作
- 复杂的查询方法
- 聚合与注解
- 事务管理
- 性能优化技巧
要深入学习 Django ORM,建议:
- 阅读 Django 官方文档的模型部分
- 实践各种查询场景
- 使用 Django Debug Toolbar 分析查询性能
- 学习如何为复杂查询添加数据库索引