Django ORM 完全指南:模型与查询

小飞兽 Django 6 次阅读 2026-07-29

Django ORM(Object-Relational Mapping)是 Django 框架的核心功能之一,它允许开发者使用 Python 对象操作数据库,无需编写原生 SQL 语句。本文全面讲解 Django ORM 的使用方法。

字段类型一览

from django.db import models

class Author(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField(unique=True)
bio = models.TextField(blank=True)
birth_date = models.DateField(null=True)
website = models.URLField(blank=True)
is_active = models.BooleanField(default=True)
score = models.IntegerField(default=0)
balance = models.DecimalField(max_digits=10, decimal_places=2)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
avatar = models.ImageField(upload_to="avatars/", null=True)
slug = models.SlugField(unique=True)

关系字段

class Article(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name="articles")
# ForeignKey: 一对多,Author 删除时 Article 也删除
# related_name 让反向查询: author.articles.all()

category = models.ForeignKey("Category", on_delete=models.SET_NULL, null=True)
# SET_NULL: Category 删除时,Article.category 设为 NULL

tags = models.ManyToManyField("Tag", related_name="articles", blank=True)
# ManyToManyField: 多对多关系

class Meta:
ordering = ["-created_at"]
indexes = [
models.Index(fields=["-created_at"]),
models.Index(fields=["author", "-created_at"]),
]

基本 CRUD 操作

# 创建
author = Author.objects.create(name="张三", email="zhangsan@example.com")
article = Article(title="Django教程", content="内容...", author=author)
article.save()

读取(QuerySet)

all_authors = Author.objects.all() author = Author.objects.get(id=1) # 不存在抛异常 first_three = Author.objects.all()[:3] active = Author.objects.filter(is_active=True) active_count = Author.objects.filter(is_active=True).count()

更新

author.name = "李四" author.save()

批量更新(更高效)

Author.objects.filter(is_active=False).update(is_active=True)

删除

article.delete() Author.objects.filter(is_active=False).delete()

高级查询方法

from django.db.models import Q, F, Count, Sum, Avg, Max, Min

链式过滤

articles = Article.objects.filter( author__name="张三", created_at__year=2024, views__gte=100, ).exclude(category__name="未分类").order_by("-created_at")

Q 对象(OR 查询)

results = Article.objects.filter( Q(title__contains="Django") | Q(title__contains="Python"), Q(views__gte=100) & ~Q(status="draft") )

F 表达式(字段间比较)

Article.objects.all().update(views=F("views") * 2)

聚合查询

stats = Article.objects.aggregate( total_views=Sum("views"), avg_views=Avg("views"), max_views=Max("views"), article_count=Count("id") )

stats = {total_views: 50000, avg_views: 2500, max_views: 10000, article_count: 20}

分组查询(annotate)

author_stats = Author.objects.annotate( article_count=Count("articles"), total_views=Sum("articles__views") ).order_by("-article_count")

性能优化:预加载

# select_related: 一对多/一对一,SQL JOIN
articles = Article.objects.select_related("author", "category").all()
for article in articles:
    # 不再产生额外查询
    print(article.author.name, article.category.name)

prefetch_related: 多对多/反向 ForeignKey

articles = Article.objects.prefetch_related("tags").all() for article in articles: for tag in article.tags.all(): print(tag.name)

常见问题

    • Q: get() 和 filter().first() 有什么区别?
      A:get() 只能返回一条记录,多条或零条都会抛异常;filter().first() 返回第一条或 None,更安全。
    • Q: 如何执行原生 SQL?
      A:使用 Model.objects.raw() 或 connection.cursor()。但应优先使用 ORM,仅在复杂查询无法用 ORM 表达时才使用原生 SQL。
    • Q: objects.all() 和 objects.filter() 有性能差异吗?
      A:在数据库层面相同,filter() 只是加了一个 WHERE 1=1 的条件。
    • Q: 如何处理数据库事务?
      A:使用 transaction.atomic() 装饰器或上下文管理器:
      from django.db import transaction
      

      @transaction.atomic
      def transfer_money(from_id, to_id, amount):
      with transaction.atomic():
      pass

    延伸阅读

  • Django 模型字段参考
  • Django 数据库性能优化:N+1 查询问题分析与解决