Django 数据模型

🗃️ Django ORM 的力量

Django的ORM(对象关系映射)让你可以使用Python类来定义数据模型,而无需编写SQL。模型是Django应用的核心。

什么是Django模型?

Django模型是Python类,它们:

  • 映射到数据库表
  • 定义表字段和数据类型
  • 包含业务逻辑和方法
  • 提供数据库查询的Pythonic接口

Django ORM 工作流程

Python 模型类

定义数据结构和行为

Django ORM

自动生成SQL

数据库表

存储实际数据

创建第一个模型

1

打开 models.py

在应用目录中编辑models.py文件:

# myapp/models.py
from django.db import models

# 在这里定义你的模型
2

定义模型类

创建一个简单的博客文章模型:

class Post(models.Model):
  title = models.CharField(max_length=200)
  content = models.TextField()
  created_at = models.DateTimeField(auto_now_add=True)
  updated_at = models.DateTimeField(auto_now=True)
  is_published = models.BooleanField(default=False)

  def __str__(self):
    return self.title
模型代码解释:
title - 字符字段,最大长度200
content - 文本字段,无长度限制
created_at - 创建时自动设置时间
updated_at - 每次保存时自动更新
is_published - 布尔值,默认未发布
__str__ - 定义对象的显示名称

常用字段类型

📝
CharField

短文本字段,必须指定max_length

title = models.CharField(max_length=100)
📄
TextField

长文本字段,适合文章内容等

content = models.TextField()
🔢
IntegerField

整数字段

age = models.IntegerField()
💰
DecimalField

十进制数字,适合金额等

price = models.DecimalField(max_digits=10, decimal_places=2)
BooleanField

布尔值字段

is_active = models.BooleanField(default=True)
📅
DateTimeField

日期和时间字段

created = models.DateTimeField(auto_now_add=True)
📧
EmailField

邮箱字段,自动验证格式

email = models.EmailField()
🔗
URLField

URL字段,自动验证格式

website = models.URLField()

字段常用参数

参数 说明 示例
default 字段默认值 default=True
null 是否允许数据库NULL值 null=True
blank 是否允许表单验证为空 blank=True
choices 可选值列表 choices=STATUS_CHOICES
unique 字段值是否唯一 unique=True
verbose_name 可读的字段名称 verbose_name="标题"
help_text 帮助文本 help_text="请输入文章标题"

模型关系

Django 支持三种主要关系类型

一对一

One-to-One

一对多

One-to-Many

多对多

Many-to-Many

一对一关系

一个模型实例关联另一个模型的一个实例

class UserProfile(models.Model):
  user = models.OneToOneField(User, on_delete=models.CASCADE)
  bio = models.TextField()

使用场景: 用户扩展信息、配置信息等

一对多关系

一个模型实例关联多个另一个模型的实例

class Comment(models.Model):
  post = models.ForeignKey(Post, on_delete=models.CASCADE)
  content = models.TextField()

使用场景: 博客文章和评论、订单和商品等

多对多关系

一个模型实例关联多个另一个模型的实例,反之亦然

class Article(models.Model):
  tags = models.ManyToManyField(Tag)
  title = models.CharField(max_length=200)

使用场景: 文章和标签、学生和课程等

on_delete 参数详解

选项 说明 使用场景
CASCADE 级联删除,关联对象一并删除 评论随文章删除
PROTECT 保护模式,阻止删除操作 有订单的用户不能删除
SET_NULL 设置为NULL,需要null=True 文章作者离职,文章保留
SET_DEFAULT 设置为默认值 设置默认分类
SET() 设置为指定值 自定义设置逻辑
DO_NOTHING 什么也不做(不推荐) 数据库级别约束

完整模型示例

# myapp/models.py
from django.db import models
from django.contrib.auth.models import User

class Category(models.Model):
  name = models.CharField(max_length=100, unique=True)
  description = models.TextField(blank=True)

  class Meta:
    verbose_name = "分类"
    verbose_name_plural = "分类"
    ordering = ['name']

  def __str__(self):
    return self.name

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

  def __str__(self):
    return self.name

class Post(models.Model):
  STATUS_CHOICES = [
    ('draft', '草稿'),
    ('published', '已发布'),
    ('archived', '已归档'),
  ]

  title = models.CharField(max_length=200, verbose_name="标题")
  content = models.TextField(verbose_name="内容")
  author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="作者")
  category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, blank=True)
  tags = models.ManyToManyField(Tag, blank=True)
  status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='draft')
  created_at = models.DateTimeField(auto_now_add=True)
  updated_at = models.DateTimeField(auto_now=True)
  published_at = models.DateTimeField(null=True, blank=True)

  class Meta:
    verbose_name = "文章"
    verbose_name_plural = "文章"
    ordering = ['-created_at']
    indexes = [
      models.Index(fields=['status', 'created_at']),
    ]

  def __str__(self):
    return self.title

  def publish(self):
    self.status = 'published'
    self.published_at = timezone.now()
    self.save()

  def is_recent(self):
    return self.created_at >= timezone.now() - timedelta(days=7)
示例代码分析:
Category模型 - 文章分类,包含名称和描述
Tag模型 - 文章标签,多对多关系
Post模型 - 核心文章模型,包含:
  • 状态选择字段(choices)
Meta类 - 模型元数据配置
  • 数据库索引优化
自定义方法 - 业务逻辑封装
  • publish() - 发布文章
  • is_recent() - 检查是否最近创建

模型元数据 (Meta)

📋 Meta 类常用选项

Meta类用于定义模型的元数据,控制模型在数据库和admin中的行为。

选项 说明 示例
db_table 自定义数据库表名 db_table = 'blog_posts'
ordering 默认排序规则 ordering = ['-created_at']
verbose_name 单数可读名称 verbose_name = "文章"
verbose_name_plural 复数可读名称 verbose_name_plural = "文章"
unique_together 联合唯一约束 unique_together = ['user', 'post']
indexes 数据库索引 indexes = [models.Index(fields=['status'])]
constraints 数据库约束 constraints = [models.CheckConstraint(...)]
default_related_name 默认反向关系名称 default_related_name = 'posts'

数据库迁移

迁移工作流程

1
创建迁移文件

检测模型变更并生成迁移文件:

$ python manage.py makemigrations
2
查看迁移SQL

可选:查看将要执行的SQL语句:

$ python manage.py sqlmigrate myapp 0001
3
应用迁移

执行迁移,创建或修改数据库表:

$ python manage.py migrate

迁移文件示例

0001_initial.py

初始迁移,创建所有模型表

# myapp/migrations/0001_initial.py
from django.db import migrations, models

class Migration(migrations.Migration):
  initial = True
  dependencies = []
  operations = [
    migrations.CreateModel(
      name='Post',
      fields=[...],
    ),
  ]

ORM 查询示例

🔍 常用查询操作

Django ORM 提供了丰富的查询API,让你可以使用Python语法操作数据库。

基础查询
# 获取所有对象
posts = Post.objects.all()

# 获取单个对象
post = Post.objects.get(id=1)

# 过滤查询
published_posts = Post.objects.filter(status='published')

# 排除查询
drafts = Post.objects.exclude(status='published')
高级查询
# 关联查询
user_posts = Post.objects.filter(author__username='john')

# 排序和切片
recent_posts = Post.objects.order_by('-created_at')[:5]

# 聚合查询
from django.db.models import Count
post_count = Post.objects.aggregate(Count('id'))

查询性能优化

# 避免 N+1 查询问题
# 不好的写法
posts = Post.objects.all()
for post in posts:
  print(post.author.username) # 每次循环都会查询数据库

# 好的写法 - 使用 select_related
posts = Post.objects.select_related('author').all()
for post in posts:
  print(post.author.username) # 只查询一次数据库

# 多对多关系使用 prefetch_related
posts = Post.objects.prefetch_related('tags').all()

模型设计最佳实践

✅ 应该做的
  • 使用有意义的字段名 - 避免使用缩写
  • 设置适当的verbose_name - 便于admin显示
  • 定义__str__方法 - 便于调试和显示
  • 使用choices代替魔法数字 - 提高可读性
  • 添加数据库索引 - 优化查询性能
  • 使用select_related/prefetch_related - 避免N+1查询
  • 编写模型方法 - 封装业务逻辑
❌ 避免做的
  • 避免过宽的表 - 字段过多影响性能
  • 不要忽略on_delete - 必须指定删除行为
  • 避免过度规范化 - 平衡性能和可维护性
  • 不要硬编码ID - 使用get_or_create等
  • 避免在循环中保存 - 使用bulk_create
  • 不要忘记迁移 - 模型变更后及时迁移
  • 避免长文本索引 - 影响性能
🔒 数据验证规则

在模型层面确保数据完整性:

  • 使用unique=True确保字段唯一性
  • 设置适当的max_length限制
  • 使用choices限制可选值
  • 通过模型clean()方法实现复杂验证
  • 使用数据库约束(unique_together, constraints)

交互式模型构建器

🎯 尝试构建你的模型

选择字段类型和参数,实时生成模型代码:

生成的模型代码:
from django.db import models

class MyModel(models.Model):
  title = models.CharField(max_length=200)

  def __str__(self):
    return self.title

下一步学习

👁️
Admin 后台

学习如何注册模型到Django管理后台

学习Admin
🔍
视图和模板

掌握如何在视图中使用模型数据

学习视图
🧪
模型测试

学习如何为模型编写测试用例

学习测试