Django ORM 对象关系映射


Django ORM

Django ORM(对象关系映射)是 Django 框架中操作数据库的核心工具,它允许开发者通过 Python 代码(而非 SQL)实现对数据库的增删改查。

示例模型:

# models.py
from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)  # 字符串类型
    age = models.IntegerField()  # 整数类型
    email = models.EmailField(null=True, blank=True)  # 允许为空

    def __str__(self):
        return self.name

class Book(models.Model):
    title = models.CharField(max_length=200)
    publish_date = models.DateField()
    price = models.DecimalField(max_digits=10, decimal_places=2)
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name="books")  # 一对多关联(外键)

    class Meta:
        ordering = ["-publish_date"]  # 默认按发布日期倒序排序
        db_table = "my_books"  # 自定义表名(默认是app名_模型名)

    def __str__(self):
        return self.title

一、查询操作

1. 基础查询

  • all():获取所有数据(返回 QuerySet)
all_books = Book.objects.all()  # 等价于 SELECT * FROM my_books;
  • get():获取单个数据(必须匹配 1 条,否则抛DoesNotExistMultipleObjectsReturned异常)
book = Book.objects.get(id=1)  # 等价于 SELECT * FROM my_books WHERE id=1;
  • filter():过滤数据(返回满足条件的 QuerySet)
# 查询价格大于50的书
expensive_books = Book.objects.filter(price__gt=50)
  • exclude():排除满足条件的数据(与filter相反)
# 查询价格不大于50的书
cheap_books = Book.objects.exclude(price__gt=50)

2. 字段查询(双下划线__语法)

通过字段名__条件实现复杂过滤,常见条件:

  • __exact:精确匹配(默认,可省略)
Book.objects.filter(title__exact="Django入门")  # 等价于 title = "Django入门"
  • __contains:包含指定字符串(模糊查询)
Book.objects.filter(title__contains="Django")  # 标题包含"Django"
  • __gt/__lt/__gte/__lte:大于 / 小于 / 大于等于 / 小于等于
Book.objects.filter(price__gte=30, price__lte=100)  # 价格30-100之间
  • __in:在指定列表中
Book.objects.filter(author__id__in=[1, 3, 5])  # 作者id为1、3、5的书
  • __isnull:是否为 NULL
Author.objects.filter(email__isnull=True)  # 未填写邮箱的作者
  • 日期相关:__year/__month/__day
Book.objects.filter(publish_date__year=2023)  # 2023年出版的书

3. 排序

  • order_by():指定排序字段(默认升序,加-表示降序)
# 按价格升序(从低到高)
books_by_price = Book.objects.order_by("price")

# 按发布日期降序(最新的在前)
books_by_date = Book.objects.order_by("-publish_date")

4. 切片与分页

  • 切片:类似列表切片(仅支持正索引,且不支持负步长)
first_3_books = Book.objects.all()[:3]  # 获取前3条数据
  • 分页(用Paginator):
from django.core.paginator import Paginator

all_books = Book.objects.all()
paginator = Paginator(all_books, 10)  # 每页10条
page1 = paginator.page(1)  # 第1页数据
page1.object_list  # 第1页的具体数据

5. 聚合与注解

  • aggregate():对查询集进行聚合计算(返回字典)
from django.db.models import Avg, Sum, Count

# 计算所有书的平均价格
avg_price = Book.objects.aggregate(avg=Avg("price"))  # {'avg': 65.5}

# 计算总共有多少本书
total_books = Book.objects.aggregate(count=Count("id"))  # {'count': 20}
  • annotate():为每个对象添加 “注解”(额外字段)
# 给每个作者添加“书籍数量”注解
authors_with_book_count = Author.objects.annotate(book_count=Count("books"))
# 访问:author.book_count 即可获取该作者的书籍数量

三、新增数据

1. 单个新增

  • 方式 1:实例化模型 + save()
author = Author(name="张三", age=30)
author.save()  # 保存到数据库(执行INSERT)
  • 方式 2:create()(直接创建并保存,更简洁)
book = Book.objects.create(
title="Python高级编程",
publish_date="2023-01-15",
price=89.00,
author=author  # 关联已有的Author对象
)

2. 批量新增

bulk_create,效率更高

books = [
    Book(title="book1", publish_date="2023-01-01", price=50, author=author),
    Book(title="book2", publish_date="2023-01-02", price=60, author=author),
]
Book.objects.bulk_create(books)  # 批量插入(仅1条SQL)

四、更新数据

1. 单个更新

book = Book.objects.get(id=1)
book.price = 99.00  # 修改属性
book.save()  # 保存(执行UPDATE)

2. 批量更新

update(),直接执行 SQL,不加载对象到内存

# 将所有2020年前出版的书价格提高10元
Book.objects.filter(publish_date__year__lt=2020).update(price=F("price") + 10)

五、删除数据

1. 单个删除

book = Book.objects.get(id=1)
book.delete()  # 执行DELETE

2. 批量删除

# 删除价格低于20的书
Book.objects.filter(price__lt=20).delete()

注意:外键关联中,on_delete=models.CASCADE会触发级联删除(如删除作者时,其关联的书籍也会被删除)。

六、关联查询(外键 / 多对多)

1. 一对多

AuthorBook,外键在Book

  • 从 “一” 查 “多”:通过related_name(模型中定义的related_name="books"
author = Author.objects.get(id=1)
author.books.all()  # 获取该作者的所有书籍(等价于 Book.objects.filter(author=author))
  • 从 “多” 查 “一”:直接访问外键字段
book = Book.objects.get(id=1)
book.author  # 获取这本书的作者(返回Author对象)

2. 多对多

TagBook,假设Booktags = models.ManyToManyField(Tag)

  • 添加关联:add()
tag1 = Tag.objects.get(id=1)
tag2 = Tag.objects.get(id=2)
book.tags.add(tag1, tag2)  # 给书籍添加标签
  • 移除关联:remove()
book.tags.remove(tag1)  # 移除标签
  • 清空关联:clear()
book.tags.clear()  # 清空所有标签

七、高级查询(F/Q 表达式)

1. F()

引用字段值(用于字段间比较或更新)

from django.db.models import F

# 查询“销量”大于“库存”的商品(假设有sales和stock字段)
Product.objects.filter(sales__gt=F("stock"))

# 给所有书的销量+10
Book.objects.update(sales=F("sales") + 10)

2. Q()

组合复杂条件(支持|(或)、&(且)、~(非))

from django.db.models import Q

# 查询“价格>100 或 2023年出版”的书
Book.objects.filter(Q(price__gt=100) | Q(publish_date__year=2023))

# 查询“不是张三写的 且 价格<50”的书
Book.objects.filter(~Q(author__name="张三") & Q(price__lt=50))

八、其他常用方法

  • count():获取查询集数量
Book.objects.filter(author__name="张三").count()  # 张三的书籍数量
  • exists():判断查询集是否有数据(比count()>0高效)
if Book.objects.filter(title="Django").exists():
print("存在该书籍")
  • values()/values_list():只获取指定字段(返回字典 / 元组列表,减少内存占用)
# values():返回字典列表({字段:值})
Book.objects.values("title", "price")  # [{'title': 'xxx', 'price': 89}, ...]

# values_list():返回元组列表((值1, 值2)),flat=True可转为单值列表
Book.objects.values_list("title", flat=True)  # ['xxx', 'yyy', ...]

0 条评论

发表评论

暂无评论,欢迎发表您的观点!