Files
djangoadmin-wiki/DjangoAdmin_Django_NaiveVue/zh/volume3/layer-arch.md
T
2026-09-12 23:12:15 +08:00

452 lines
12 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.
# 第四章 架构设计 - 分层架构详解
## 4.1 分层架构概述
项目采用经典的五层架构设计,各层职责明确,依赖关系清晰:
```
+------------------+
| View Layer | <-- 视图层:接收请求,返回响应
+------------------+
|
v
+------------------+
| Service Layer | <-- 服务层:业务逻辑处理
+------------------+
|
v
+------------------+
| Form Layer | <-- 表单层:数据验证
+------------------+
|
v
+------------------+
| Model Layer | <-- 模型层:数据库操作
+------------------+
|
v
+------------------+
| URL Layer | <-- 路由层:URL映射
+------------------+
```
## 4.2 模型层 (Model Layer)
### 4.2.1 BaseModel 抽象基类
所有业务模型继承自 `BaseModel`(`application/models.py`),自动获得 6 个公共字段:
```python
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 # 抽象模型,不创建数据库表
```
### 4.2.2 业务模型示例
以案例模型为例(`application/example/models.py`):
```python
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="案例名称", db_comment='案例名称'
)
avatar = models.CharField(
null=True, blank=True, max_length=255,
verbose_name="案例图片", db_comment='案例图片'
)
TYPE_CHOICES = ((1, "类型1"), (2, "类型2"), (3, "类型3"), (4, "类型4"))
type = models.IntegerField(
null=False, choices=TYPE_CHOICES,
verbose_name="案例类型", db_comment='案例类型'
)
STATUS_CHOICES = ((1, "正常"), (2, "禁用"))
status = models.IntegerField(
null=False, choices=STATUS_CHOICES,
verbose_name="案例状态", db_comment='案例状态:1-正常 2-禁用'
)
sort = models.IntegerField(
null=False, verbose_name="排序", db_comment='排序'
)
class Meta:
db_table = get_table_name('example') # 自动生成表名
db_table_comment = "案例表"
ordering = ("sort",)
```
### 4.2.3 字段顺序重排
通过 `class_prepared` 信号,自动将公共字段移到业务字段之后:
```python
BASE_FIELD_NAMES = ['id', 'create_user', 'create_time',
'update_user', 'update_time', 'is_delete']
def _reorder_fields(sender, **kwargs):
"""信号处理函数:重排模型字段顺序"""
if not hasattr(sender, '_meta') or sender._meta.abstract:
return
base_fields = []
business_fields = []
for field in sender._meta.local_fields:
if field.name in BASE_FIELD_NAMES:
base_fields.append(field)
else:
business_fields.append(field)
# 重新排列:业务字段在前,公共字段在后
sender._meta.local_fields = business_fields + base_fields
class_prepared.connect(_reorder_fields)
```
## 4.3 表单层 (Form Layer)
### 4.3.1 ModelForm 验证
表单层使用 Django 的 `ModelForm` 进行数据验证(`application/example/forms.py`):
```python
from django import forms
from application.example import models
class ExampleForm(forms.ModelForm):
"""案例表单验证类"""
name = forms.CharField(
required=True, max_length=100,
error_messages={
'required': '案例名称不能为空',
'max_length': '案例名称长度不得超过100个字符',
}
)
type = forms.IntegerField(
required=True, min_value=1, max_value=4,
error_messages={
'required': '案例类型不能为空',
'min_value': '案例类型值不能小于1',
'max_value': '案例类型值不能大于4',
}
)
status = forms.IntegerField(
required=True, min_value=1, max_value=2,
error_messages={
'required': '案例状态不能为空',
}
)
sort = forms.IntegerField(
required=True,
error_messages={'required': '排序不能为空'}
)
class Meta:
model = models.Example
fields = ['name', 'avatar', 'type', 'status', 'sort']
```
### 4.3.2 验证错误处理
```python
# 在Service层使用表单验证
form = ExampleForm(data)
if not form.is_valid():
# 获取第一个错误信息
return R.failed(msg=regular.get_err(form))
```
## 4.4 服务层 (Service Layer)
### 4.4.1 服务函数命名规范
服务层函数遵循统一的命名规范:
| 函数类型 | 命名格式 | 示例 |
|----------|----------|------|
| 分页查询 | `get_<module>_page` | `get_example_page` |
| 列表查询 | `get_<module>_list` | `get_example_list` |
| 详情查询 | `get_<module>_detail` | `get_example_detail` |
| 添加 | `add_<module>` | `add_example` |
| 更新 | `update_<module>` | `update_example` |
| 删除 | `delete_<module>s` | `delete_examples` |
| 状态更新 | `update_<module>_status` | `update_example_status` |
### 4.4.2 分页查询实现
```python
def get_example_page(request):
"""查询案例分页数据"""
try:
page_no = int(request.GET.get('pageNo', 1))
page_size = int(request.GET.get('pageSize', PAGE_SIZE))
# 构建基础查询(只查询未删除的记录)
query = Example.objects.filter(is_delete=False)
query = _apply_filters(query, request)
query = query.order_by("sort")
# 执行分页查询
paginator = Paginator(query, page_size)
page_list = paginator.page(page_no)
# 构建并返回分页数据
page_data = _build_page_data(page_list, paginator, page_no, page_size)
return R.ok(data=page_data)
except Exception as e:
logging.error(f"查询案例分页数据异常: {str(e)}")
return R.failed(msg="查询失败,请稍后重试")
```
### 4.4.3 添加操作实现
```python
def add_example(request):
"""添加案例"""
data, error = parse_request_body(request)
if error:
return R.failed(msg=error)
form = ExampleForm(data)
if not form.is_valid():
return R.failed(msg=regular.get_err(form))
try:
cleaned_data = form.cleaned_data
avatar = cleaned_data.get('avatar')
if avatar:
avatar = save_file(avatar, "example")
Example.objects.create(
name=cleaned_data.get('name'),
avatar=avatar,
type=cleaned_data.get('type'),
status=cleaned_data.get('status'),
sort=cleaned_data.get('sort'),
create_user=get_username(request),
update_user=get_username(request)
)
return R.ok(msg="创建成功")
except Exception as e:
logging.error(f"添加案例异常: {str(e)}")
return R.failed(msg="添加失败,请稍后重试")
```
### 4.4.4 删除操作实现(软删除)
```python
def delete_examples(instance_ids):
"""删除案例(批量删除)"""
if not instance_ids:
return R.failed("记录ID不存在")
try:
id_list = [int(id_str.strip())
for id_str in instance_ids.split(',') if id_str.strip()]
# 批量更新删除标识(逻辑删除)
updated_count = Example.objects.filter(
id__in=id_list, is_delete=False
).update(is_delete=True)
return R.ok(msg=f"本次共删除{updated_count}条数据")
except ValueError:
return R.failed("记录ID格式错误")
```
## 4.5 视图层 (View Layer)
### 4.5.1 视图类结构
视图层使用 Django 的类视图,结合装饰器和混入类实现认证和权限控制:
```python
from django.utils.decorators import method_decorator
from django.views import View
from middleware.login_middleware import check_login
from middleware.permission_middleware import PermissionRequired
@method_decorator(check_login, name="get")
class ExamplePageView(PermissionRequired, View):
"""案例分页数据查询视图"""
permission_required = ("sys:example:page",)
@operation_log(title="案例管理-查询分页列表", log_type=LogType.QUERY)
def get(self, request):
result = services.get_example_page(request)
return result
```
### 4.5.2 视图类职责
| 职责 | 说明 |
|------|------|
| 请求接收 | 接收 HTTP 请求,提取参数 |
| 认证检查 | 通过 `@check_login` 装饰器验证登录状态 |
| 权限检查 | 通过 `PermissionRequired` 混入类验证操作权限 |
| 参数校验 | 简单的参数格式校验(如 ID 有效性) |
| 服务调用 | 调用 Service 层函数处理业务逻辑 |
| 响应返回 | 返回 Service 层返回的响应结果 |
## 4.6 路由层 (URL Layer)
### 4.6.1 模块路由定义
每个模块在 `urls.py` 中定义自己的路由:
```python
# application/example/urls.py
from django.urls import path
from application.example import views
urlpatterns = [
path('page', views.ExamplePageView.as_view()),
path('list', views.ExampleListView.as_view()),
path('detail/<int:id>', views.ExampleDetailView.as_view()),
path('add', views.ExampleAddView.as_view()),
path('update', views.ExampleUpdateView.as_view()),
path('delete/<str:id>', views.ExampleDeleteView.as_view()),
path('status', views.ExampleStatusView.as_view()),
]
```
### 4.6.2 主路由注册
所有模块路由在主路由中注册(`application/urls.py`):
```python
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('application.login.urls')),
path('index/', include('application.index.urls')),
path('example/', include('application.example.urls')),
# ... 其他模块
]
```
## 4.7 数据流向
### 4.7.1 请求数据流
```
HTTP Request
|
v
View.get/post/put/delete
|
v
Service函数
|
v
parse_request_body(request) --> 解析JSON请求体
|
v
Form验证 --> 数据校验
|
v
Model操作 --> 数据库读写
|
v
构建返回数据字典
|
v
R.ok()/R.failed() --> 构造响应
|
v
JsonResponse --> HTTP Response
```
### 4.7.2 响应数据格式转换
```python
# Model对象 -> 字典
record = {
'id': item.id,
'name': item.name,
'avatar': get_file_url(item.avatar),
'createUser': item.create_user, # snake_case -> camelCase
'createTime': format_datetime(item.create_time),
}
# 字典 -> JSON
return R.ok(data=record)
# {
# "code": 0,
# "data": {"id": 1, "name": "...", "createUser": "admin"},
# "msg": "操作成功",
# "ok": true
# }
```