Files
djangoadmin-wiki/DjangoAdmin_Django_EleVue/zh/volume7/model.md
T
2026-09-12 23:12:15 +08:00

253 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Model层规范
## 概述
Model 层负责定义数据库表结构,所有业务模型继承 `BaseModel` 抽象基类,自动获得公共字段(id、create_user、create_time、update_user、update_time、is_delete)。
:::tip 设计原则
- 所有模型继承 `BaseModel`
- 字段命名使用 snake_case
- 每个字段必须有 `db_comment` 注释
- 使用 `get_table_name()` 生成表名
:::
## BaseModel 基类
`application/models.py` 定义了 `BaseModel` 抽象基类:
```python
from django.db import models
class BaseModel(models.Model):
"""基础模型抽象类"""
# 主键ID字段
id = models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name='主键ID',
db_comment='主键ID'
)
# 创建人字段
create_user = models.CharField(
null=True, max_length=50, default=None,
verbose_name='创建人', db_comment='创建人'
)
# 创建时间字段
create_time = models.DateTimeField(
null=True, auto_now_add=True,
verbose_name="创建时间", db_comment='创建时间'
)
# 更新人字段
update_user = models.CharField(
null=True, max_length=50, default=None,
verbose_name='更新人', db_comment='更新人'
)
# 更新时间字段
update_time = models.DateTimeField(
null=True, auto_now=True,
verbose_name="更新时间", db_comment='更新时间'
)
# 逻辑删除标识
is_delete = models.BooleanField(
default=0, db_default=0,
verbose_name="逻辑删除",
db_comment='逻辑删除:0-正常 1-已删除'
)
class Meta:
abstract = True
```
## 完整示例
以案例模块为例,`application/example/models.py`:
```python
from django.db import models
from application.models import BaseModel
from utils.common import get_table_name
class Example(BaseModel):
"""案例模型类"""
# 案例名称
name = models.CharField(
null=False, max_length=100, db_index=True,
verbose_name="案例名称",
help_text="案例名称",
db_comment='案例名称'
)
# 案例图片
avatar = models.CharField(
null=True, blank=True, max_length=255,
verbose_name="案例图片",
help_text="案例图片",
db_comment='案例图片'
)
# 案例类型
TYPE_CHOICES = (
(1, "类型1"),
(2, "类型2"),
(3, "类型3"),
(4, "类型4"),
)
type = models.IntegerField(
null=False, choices=TYPE_CHOICES,
verbose_name="案例类型:1-类型1 2-类型2 3-类型3 4-类型4",
help_text="案例类型:1-类型1 2-类型2 3-类型3 4-类型4",
db_comment='案例类型:1-类型1 2-类型2 3-类型3 4-类型4'
)
# 案例状态
STATUS_CHOICES = (
(1, "正常"),
(2, "禁用"),
)
status = models.IntegerField(
null=False, choices=STATUS_CHOICES,
verbose_name="案例状态:1-正常 2-禁用",
help_text="案例状态:1-正常 2-禁用",
db_comment='案例状态:1-正常 2-禁用'
)
# 排序
sort = models.IntegerField(
null=False,
verbose_name="排序",
help_text="排序",
db_comment='排序'
)
class Meta:
db_table = get_table_name('example')
db_table_comment = "案例表"
verbose_name = "案例表"
verbose_name_plural = verbose_name
ordering = ("sort",)
def __str__(self):
return f"案例{self.name}"
```
## 字段定义规范
### 字段类型映射
| 数据库类型 | Django 字段类型 | 说明 |
|:----|:----|:----|
| varchar | CharField | 短文本,需指定 max_length |
| text | TextField | 长文本 |
| int | IntegerField | 整数 |
| datetime | DateTimeField | 日期时间 |
| date | DateField | 日期 |
| float | FloatField | 浮点数 |
| decimal | DecimalField | 精确小数 |
| boolean | BooleanField | 布尔值 |
### 字段属性
| 属性 | 说明 | 示例 |
|:----|:----|:----|
| `null` | 数据库是否允许 NULL | `null=True` |
| `blank` | 表单验证是否允许空 | `blank=True` |
| `max_length` | 最大长度 | `max_length=100` |
| `default` | 默认值 | `default=0` |
| `db_index` | 是否创建索引 | `db_index=True` |
| `choices` | 选项列表 | `choices=STATUS_CHOICES` |
| `verbose_name` | 字段中文名 | `verbose_name="案例名称"` |
| `help_text` | 帮助文本 | `help_text="案例名称"` |
| `db_comment` | 数据库字段注释 | `db_comment='案例名称'` |
### 选项字段定义
```python
# 状态字段
STATUS_CHOICES = (
(1, "正常"), # 正常状态
(2, "禁用"), # 禁用状态
)
status = models.IntegerField(
null=False, choices=STATUS_CHOICES,
verbose_name="状态:1-正常 2-禁用",
db_comment='状态:1-正常 2-禁用'
)
```
:::tip 选项定义约定
- 选项定义为类属性,命名为 `{FIELD}_CHOICES`
- 选项格式为 `(value, label)` 元组
- 字段注释中包含选项说明(如 `1-正常 2-禁用`)
:::
## Meta 类配置
```python
class Meta:
# 数据表名(使用 get_table_name 自动生成)
db_table = get_table_name('example')
# 表注释(Django 4.1+)
db_table_comment = "案例表"
# Admin 后台显示名称
verbose_name = "案例表"
verbose_name_plural = verbose_name
# 默认排序
ordering = ("sort",)
```
### get_table_name 函数
`utils/common.py` 中的 `get_table_name` 函数自动拼接表前缀:
```python
from config.env import DATABASE_PREFIX
def get_table_name(table_name):
"""获取带前缀的表名"""
return f"{DATABASE_PREFIX}{table_name}"
```
例如:`DATABASE_PREFIX = "django_"` 时,`get_table_name('example')` 返回 `"django_example"`。
## 索引定义
```python
class Example(BaseModel):
name = models.CharField(max_length=100, db_index=True) # 单列索引
class Meta:
indexes = [
models.Index(fields=['status', 'type'], name='idx_status_type'), # 复合索引
]
```
## 信号机制
项目使用 `class_prepared` 信号自动重排字段顺序,将公共字段(id、create_user 等)移到业务字段之后:
```python
from django.db.models.signals import class_prepared
def _reorder_fields(sender, **kwargs):
"""重排模型字段顺序,将公共字段移到最后"""
# ... 实现逻辑 ...
class_prepared.connect(_reorder_fields)
```
## 总结
Model 层通过继承 `BaseModel` 获得公共字段,使用 `get_table_name()` 生成带前缀的表名。字段定义需包含 `db_comment` 注释、`verbose_name` 中文名。选项字段使用 `choices` 参数定义,排序使用 `Meta.ordering` 配置。