Django 模型
以下是用中文详细讲解 Django 模型(Models)的指南,涵盖模型的定义、作用、常用字段类型、关系、查询、迁移以及最佳实践。我会保持简洁清晰,适合初学者和进阶用户,并提供实用示例。如果你有特定问题或需要更深入的内容,请随时告知!
什么是 Django 模型?
Django 模型是定义数据库结构的 Python 类,遵循 Django 的 ORM(对象关系映射)机制。每个模型类映射到数据库中的一张表,类的属性(字段)映射到表的列。
- 作用:
- 定义数据结构(表、字段、关系)。
- 提供 Pythonic 方式操作数据库(增删改查)。
- 自动生成数据库迁移文件,同步模型与数据库。
- 特点:
- 基于 Python 类,继承
django.db.models.Model
。 - 支持多种数据库(SQLite、PostgreSQL、MySQL 等)。
- 内置强大的查询 API。
1. 定义模型
模型通常定义在应用的 models.py
文件中。
示例:myapp/models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=100)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Item(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
is_active = models.BooleanField(default=True)
def __str__(self):
return self.name
- 说明:
- 每个类继承
models.Model
。 - 字段(如
CharField
、DecimalField
)定义表的列。 __str__
方法定义对象的字符串表示,便于调试和管理后台显示。
常用字段类型
- 文本:
CharField(max_length)
:定长字符串(如用户名)。TextField()
:长文本(如描述)。- 数字:
IntegerField()
:整数。DecimalField(max_digits, decimal_places)
:小数(如价格)。FloatField()
:浮点数。- 日期/时间:
DateField()
:日期。DateTimeField()
:日期和时间。TimeField()
:时间。- 参数:
auto_now=True
(每次保存更新)、auto_now_add=True
(创建时设置)。 - 布尔:
BooleanField()
:真/假。- 关系(详见下文):
ForeignKey()
:一对多。ManyToManyField()
:多对多。OneToOneField()
:一对一。- 其他:
FileField()
:文件上传。ImageField()
:图片上传(需安装 Pillow)。JSONField()
:存储 JSON 数据。
字段常用参数
max_length
:字符串最大长度。blank=True
:允许表单字段为空(前端验证)。null=True
:允许数据库字段为 NULL(慎用)。default
:默认值。unique=True
:字段值唯一。choices
:限制字段值范围(如枚举)。
STATUS_CHOICES = (
('draft', '草稿'),
('published', '已发布'),
)
status = models.CharField(max_length=20, choices=STATUS_CHOICES)
2. 模型关系
Django 支持三种主要数据库关系。
2.1 一对多(ForeignKey)
- 定义:
ForeignKey(ToModel, on_delete)
。 - 作用:表示一个模型实例关联到另一个模型的单个实例。
- 示例:
Item
属于一个Category
。
category = models.ForeignKey(Category, on_delete=models.CASCADE)
- on_delete 选项:
models.CASCADE
:删除主表记录时,从表记录也删除。models.PROTECT
:阻止删除主表记录。models.SET_NULL
:从表字段置为 NULL(需null=True
)。models.SET_DEFAULT
:置为默认值。
2.2 多对多(ManyToManyField)
- 定义:
ManyToManyField(ToModel)
。 - 作用:表示多对多关系,Django 自动创建中间表。
- 示例:一个
Item
可以有多个标签,一个标签可用于多个Item
。
tags = models.ManyToManyField('Tag')
2.3 一对一(OneToOneField)
- 定义:
OneToOneField(ToModel, on_delete)
。 - 作用:表示唯一关联(如用户与其个人资料)。
- 示例:
user = models.OneToOneField('auth.User', on_delete=models.CASCADE)
3. 数据库迁移
模型定义后,需通过迁移将结构同步到数据库。
- 生成迁移文件:
python manage.py makemigrations
- 检查
models.py
的变化,生成迁移文件(如migrations/0001_initial.py
)。
- 应用迁移:
python manage.py migrate
- 执行迁移文件,创建或更新数据库表。
- 查看迁移:
python manage.py showmigrations
- 调试迁移:
sqlmigrate
:查看迁移的 SQL 语句。bash python manage.py sqlmigrate myapp 0001
4. 查询数据库
Django 提供强大的 ORM 查询 API,通过模型的 objects
管理器操作数据库。
4.1 基本查询
- 获取所有记录:
items = Item.objects.all()
- 过滤:
active_items = Item.objects.filter(is_active=True)
- 获取单条记录:
item = Item.objects.get(id=1) # 抛出异常如果不存在
item = Item.objects.filter(id=1).first() # 返回 None 如果不存在
4.2 高级查询
- 条件查询:
filter(field__exact=value)
:精确匹配。filter(field__contains='text')
:包含文本。filter(price__gte=10)
:大于等于。- 示例:
python items = Item.objects.filter(price__gte=10, category__name='书籍')
- 排序:
items = Item.objects.order_by('-price') # 降序
- 限制结果:
items = Item.objects.all()[:5] # 前 5 条
4.3 关系查询
- 访问关联对象:
item = Item.objects.get(id=1)
category_name = item.category.name # 访问 ForeignKey
- 反向查询:
category = Category.objects.get(id=1)
items = category.item_set.all() # 获取所有关联的 Item
4.4 创建/更新/删除
- 创建:
Item.objects.create(name='书', price=29.99, category=category)
- 更新:
item = Item.objects.get(id=1)
item.price = 39.99
item.save()
- 删除:
item = Item.objects.get(id=1)
item.delete()
5. 在视图和模板中使用
视图(myapp/views.py
)
from django.shortcuts import render
from .models import Item
def item_list(request):
items = Item.objects.filter(is_active=True)
return render(request, 'myapp/item_list.html', {'items': items})
模板(myapp/templates/myapp/item_list.html
)
{% extends 'base.html' %}
{% block content %}
<h1>商品列表</h1>
<ul>
{% for item in items %}
<li>{{ item.name }} - ¥{{ item.price }} ({{ item.category.name }})</li>
{% empty %}
<li>暂无商品</li>
{% endfor %}
</ul>
{% endblock %}
6. 管理后台集成
将模型注册到 Django 管理后台,方便管理数据。
示例:myapp/admin.py
from django.contrib import admin
from .models import Category, Item
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ['name', 'created_at'] # 显示字段
search_fields = ['name'] # 搜索字段
@admin.register(Item)
class ItemAdmin(admin.ModelAdmin):
list_display = ['name', 'price', 'category', 'is_active']
list_filter = ['is_active', 'category'] # 过滤器
search_fields = ['name', 'description']
- 作用:
list_display
:自定义列表页面显示的字段。list_filter
:添加过滤器。search_fields
:启用搜索功能。
访问 http://127.0.0.1:8000/admin/
(需创建超级用户:python manage.py createsuperuser
)即可管理数据。
7. 最佳实践
- 字段设计:
- 使用
blank=True
和null=True
区分表单和数据库行为。 - 为外键设置
related_name
自定义反向查询名称:python category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='items')
- 模型组织:
- 一个模型负责单一功能,避免过于复杂。
- 使用
Meta
类自定义表名、排序等:class Item(models.Model): name = models.CharField(max_length=100) class Meta: db_table = 'custom_items' # 自定义表名 ordering = ['-price'] # 默认排序</code></pre></li>
- 迁移管理:
- 定期清理无用迁移文件(
squashmigrations
)。 - 多人协作时注意迁移冲突,合并后再提交。
- 性能优化:
- 使用
select_related()
优化一对多查询:python items = Item.objects.select_related('category').all()
- 使用
prefetch_related()
优化多对多查询:python items = Item.objects.prefetch_related('tags').all()
- 避免在循环中查询数据库。
- 安全性:
- 避免直接在模型中存储敏感信息(如密码)。
- 使用 Django 内置用户模型(
django.contrib.auth.models.User
)处理认证。
8. 常见问题
- 迁移失败:
- 检查
models.py
是否有语法错误。 - 删除
migrations/
文件和数据库后重新迁移(开发环境)。
- 字段类型错误:
- 确保字段类型与实际数据匹配(如
DecimalField
用于货币)。 null=True
慎用,可能导致查询复杂化。
- 查询性能慢:
- 检查是否滥用
all()
或未优化关联查询。 - 使用 Django Debug Toolbar 分析查询。
9. 完整示例
模型(myapp/models.py
)
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Item(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='items')
def __str__(self):
return self.name
视图(myapp/views.py
)
from django.shortcuts import render
from .models import Item
def item_list(request):
items = Item.objects.select_related('category').all()
return render(request, 'myapp/item_list.html', {'items': items})
模板(myapp/templates/myapp/item_list.html
)
{% extends 'base.html' %}
{% block content %}
<h1>商品列表</h1>
<ul>
{% for item in items %}
<li>{{ item.name }} - ¥{{ item.price }} ({{ item.category.name }})</li>
{% endfor %}
</ul>
{% endblock %}
迁移
python manage.py makemigrations
python manage.py migrate
总结
Django 模型通过 ORM 简化数据库操作,定义数据结构(字段、关系)并提供强大的查询 API。正确配置字段、关系和迁移,结合视图和模板,可以快速构建数据驱动的应用。遵循最佳实践(如优化查询、合理设计模型)能提高开发效率和性能。
如果你需要更深入的内容(如高级查询、自定义模型方法、信号处理)或调试模型相关问题,请告诉我!