跳转到内容

Django模型查询

来自代码酷

Django模型查询[编辑 | 编辑源代码]

Django模型查询是Django ORM(对象关系映射)的核心功能之一,允许开发者通过Python代码与数据库交互,而无需直接编写SQL语句。它提供了丰富的API来执行数据库的增删改查(CRUD)操作,同时保持代码的简洁性和可维护性。

基础查询方法[编辑 | 编辑源代码]

Django模型查询主要通过模型的objects管理器进行。以下是几种常用的基础查询方法:

all()[编辑 | 编辑源代码]

获取模型的所有记录:

from myapp.models import Book

# 获取所有图书
all_books = Book.objects.all()

# 输出前5本图书的标题
for book in all_books[:5]:
    print(book.title)

filter()[编辑 | 编辑源代码]

根据条件筛选记录:

# 获取所有价格大于20的图书
expensive_books = Book.objects.filter(price__gt=20)

# 获取作者是"John Doe"的图书
johns_books = Book.objects.filter(author="John Doe")

get()[编辑 | 编辑源代码]

获取单个记录(如果找不到或找到多个会抛出异常):

try:
    # 获取ID为1的图书
    specific_book = Book.objects.get(id=1)
    print(specific_book.title)
except Book.DoesNotExist:
    print("图书不存在")
except Book.MultipleObjectsReturned:
    print("找到多个图书")

查询字段查找[编辑 | 编辑源代码]

Django提供了多种字段查找方式(Field Lookups),用于在filter()exclude()get()中指定条件:

常用字段查找
查找类型 描述 示例
exact 精确匹配 Book.objects.filter(title__exact="Django")
iexact 不区分大小写的精确匹配 Book.objects.filter(title__iexact="django")
contains 包含 Book.objects.filter(title__contains="Python")
icontains 不区分大小写的包含 Book.objects.filter(title__icontains="python")
in 在列表中 Book.objects.filter(id__in=[1, 3, 5])
gt 大于 Book.objects.filter(price__gt=20)
gte 大于等于 Book.objects.filter(price__gte=15)
lt 小于 Book.objects.filter(price__lt=10)
lte 小于等于 Book.objects.filter(price__lte=15)
startswith 以...开头 Book.objects.filter(title__startswith="The")
istartswith 不区分大小写的以...开头 Book.objects.filter(title__istartswith="the")
endswith 以...结尾 Book.objects.filter(title__endswith="Guide")
iendswith 不区分大小写的以...结尾 Book.objects.filter(title__iendswith="guide")
range 范围 Book.objects.filter(publish_date__range=("2020-01-01", "2020-12-31"))
isnull 是否为NULL Book.objects.filter(author__isnull=True)

复杂查询[编辑 | 编辑源代码]

Q对象[编辑 | 编辑源代码]

用于构建复杂的查询条件,支持逻辑或(OR)操作:

from django.db.models import Q

# 查找价格低于10或高于50的图书
books = Book.objects.filter(Q(price__lt=10) | Q(price__gt=50))

# 查找标题包含"Python"但不包含"Django"的图书
books = Book.objects.filter(Q(title__icontains="Python") & ~Q(title__icontains="Django"))

F对象[编辑 | 编辑源代码]

用于在查询中引用字段的值:

from django.db.models import F

# 查找库存数量小于已售数量的图书
books = Book.objects.filter(stock__lt=F('sold'))

# 将所有图书价格增加10
Book.objects.update(price=F('price') + 10)

聚合与注解[编辑 | 编辑源代码]

Django提供了强大的聚合功能:

聚合函数[编辑 | 编辑源代码]

from django.db.models import Avg, Max, Min, Sum

# 计算所有图书的平均价格
avg_price = Book.objects.aggregate(Avg('price'))

# 计算每个作者的图书最高价格
from django.db.models import Count
author_stats = Book.objects.values('author').annotate(
    max_price=Max('price'),
    book_count=Count('id')
)

注解[编辑 | 编辑源代码]

为查询集中的每个对象添加计算字段:

from django.db.models import Value
from django.db.models.functions import Concat

# 为每本图书添加全名字段
books = Book.objects.annotate(
    full_name=Concat('title', Value(' by '), 'author')
)

查询优化[编辑 | 编辑源代码]

select_related[编辑 | 编辑源代码]

用于外键关系的预取(JOIN操作):

# 获取图书及其出版社信息(一对一或外键关系)
books = Book.objects.select_related('publisher')

prefetch_related[编辑 | 编辑源代码]

用于多对多关系的预取:

# 获取图书及其所有标签(多对多关系)
books = Book.objects.prefetch_related('tags')

only/defer[编辑 | 编辑源代码]

控制加载的字段:

# 只加载title字段
books = Book.objects.only('title')

# 加载除description外的所有字段
books = Book.objects.defer('description')

实际案例[编辑 | 编辑源代码]

假设我们有一个图书管理系统,包含以下模型:

from django.db import models

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

class Publisher(models.Model):
    name = models.CharField(max_length=100)
    founded = models.IntegerField()

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
    publish_date = models.DateField()
    price = models.DecimalField(max_digits=5, decimal_places=2)
    stock = models.IntegerField()
    sold = models.IntegerField()
    tags = models.ManyToManyField('Tag')

class Tag(models.Model):
    name = models.CharField(max_length=50)

案例1:图书统计报表[编辑 | 编辑源代码]

from django.db.models import Count, Avg

# 获取每个出版社的图书数量、平均价格和总销量
report = Publisher.objects.annotate(
    book_count=Count('book'),
    avg_price=Avg('book__price'),
    total_sold=Sum('book__sold')
).order_by('-book_count')

for publisher in report:
    print(f"{publisher.name}: {publisher.book_count} books, "
          f"avg price ${publisher.avg_price:.2f}, "
          f"total sold {publisher.total_sold}")

案例2:图书推荐系统[编辑 | 编辑源代码]

# 查找与某本图书有相同标签的其他图书
def get_related_books(book_id, limit=5):
    book = Book.objects.get(id=book_id)
    related_books = Book.objects.filter(
        tags__in=book.tags.all()
    ).exclude(
        id=book_id
    ).distinct().order_by('?')[:limit]
    return related_books

性能考虑[编辑 | 编辑源代码]

graph TD A[查询需求] --> B{是否需要多个表数据?} B -->|是| C{关系类型?} C -->|外键/一对一| D[使用select_related] C -->|多对多| E[使用prefetch_related] B -->|否| F[基本查询] D --> G[考虑only/defer减少字段] E --> G G --> H[考虑索引优化]

数学表达式[编辑 | 编辑源代码]

在聚合查询中,可能会用到一些数学表达式。例如计算折扣后的价格:

折扣价格=原价×(1折扣率100)

在Django中可以实现为:

from django.db.models import F, ExpressionWrapper, DecimalField

discounted_books = Book.objects.annotate(
    discounted_price=ExpressionWrapper(
        F('price') * (1 - F('discount_rate')/100),
        output_field=DecimalField(max_digits=5, decimal_places=2)
    )
)

总结[编辑 | 编辑源代码]

Django模型查询提供了强大而灵活的方式来与数据库交互,关键点包括:

  • 使用objects管理器进行基本查询
  • 掌握字段查找(Field Lookups)构建精确查询条件
  • 使用Q对象和F对象实现复杂查询逻辑
  • 通过聚合和注解实现数据分析功能
  • 使用select_relatedprefetch_related优化查询性能
  • 在实际应用中结合业务需求设计高效查询

通过合理使用这些功能,可以构建出既高效又易于维护的数据库查询代码。