# 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` 配置。