Files
djangoadmin-wiki/DjangoAdmin_Django_NaiveVue/zh/volume2/view.md
T
2026-09-13 18:12:07 +08:00

482 lines
14 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.
# 视图层(View)
视图层是模块开发的第四步,负责处理 HTTP 请求并调用 Service 层的业务逻辑。项目使用 Django 的类视图(Class-Based Views),每个视图类对应一个 API 端点。
## 文件位置
```
application/example/views.py
```
## 完整代码
```python
from django.utils.decorators import method_decorator
from django.views import View
from application.example import services
from config.env import DJANGO_DEMO
from middleware.login_middleware import check_login
from middleware.permission_middleware import PermissionRequired
from utils import R
from application.operation_log.constants import LogType
from application.operation_log.decorators import operation_log
# =============================================================
# 分页查询视图
# =============================================================
@method_decorator(check_login, name="get")
class ExamplePageView(PermissionRequired, View):
"""
案例分页数据查询视图
处理GET请求,返回案例列表的分页数据。
支持按案例名称、案例类型、案例状态等条件筛选。
URL: /example/page
请求方法: GET
权限要求:sys:example:page
"""
# 方法权限标识
permission_required = ("sys:example:page",)
@operation_log(
title="案例管理-查询分页列表",
log_type=LogType.QUERY
)
def get(self, request):
"""
处理GET请求,返回案例分页数据
Args:
request: HttpRequest对象,包含分页参数和筛选条件
- pageNo: 当前页码
- pageSize: 每页记录数
- name: 案例名称(可选,模糊查询)
- type: 案例类型(可选,精确匹配)
- status: 案例状态(可选,精确匹配)
Returns:
JsonResponse: 包含分页数据的JSON响应
"""
result = services.get_example_page(request)
return result
# =============================================================
# 列表查询视图(不分页)
# =============================================================
@method_decorator(check_login, name='get')
class ExampleListView(View):
"""
案例列表获取视图(支持筛选,不分页)
处理GET请求,返回所有案例的列表数据。
支持按案例名称、案例类型、案例状态等条件筛选。
URL: /example/list
请求方法: GET
权限要求:需要登录
"""
def get(self, request):
"""
处理GET请求,返回案例列表
Args:
request: HttpRequest对象
Returns:
JsonResponse: 包含案例列表的JSON响应
"""
result = services.get_example_list(request)
return R.ok(data=result)
# =============================================================
# 详情查询视图
# =============================================================
@method_decorator(check_login, name="get")
class ExampleDetailView(PermissionRequired, View):
"""
案例详情查询视图
处理GET请求,根据案例ID返回案例详细信息。
URL: /example/detail/<int:id>
请求方法: GET
权限要求:sys:example:detail
"""
# 方法权限标识
permission_required = ("sys:example:detail",)
@operation_log(
title="案例管理-查询记录详情",
log_type=LogType.QUERY
)
def get(self, request, id):
"""
处理GET请求,返回案例详情
Args:
request: HttpRequest对象
id: 案例ID(URL参数)
Returns:
JsonResponse: 包含案例详情的JSON响应
"""
data = services.get_example_detail(id)
return R.ok(data=data)
# =============================================================
# 添加视图
# =============================================================
@method_decorator(check_login, name="post")
class ExampleAddView(PermissionRequired, View):
"""
添加案例视图
处理POST请求,创建新的案例记录。
请求体需包含案例信息(name、avatar、type、status、sort等)。
URL: /example/add
请求方法: POST
权限要求:sys:example:add
"""
# 方法权限标识
permission_required = ("sys:example:add",)
@operation_log(
title="案例管理-添加记录",
log_type=LogType.ADD
)
def post(self, request):
"""
处理POST请求,添加案例
Args:
request: HttpRequest对象,请求体包含案例信息
Returns:
JsonResponse: 操作结果的JSON响应
"""
# 演示模式检查
if DJANGO_DEMO:
return R.failed("演示环境,暂无操作权限")
result = services.add_example(request)
return result
# =============================================================
# 更新视图
# =============================================================
@method_decorator(check_login, name="put")
class ExampleUpdateView(PermissionRequired, View):
"""
更新案例视图
处理PUT请求,更新现有案例信息。
请求体需包含案例ID和更新内容。
URL: /example/update
请求方法: PUT
权限要求:sys:example:update
"""
# 方法权限标识
permission_required = ('sys:example:update',)
@operation_log(
title="案例管理-更新记录",
log_type=LogType.UPDATE
)
def put(self, request):
"""
处理PUT请求,更新案例
Args:
request: HttpRequest对象,请求体包含更新信息
Returns:
JsonResponse: 操作结果的JSON响应
"""
# 演示模式检查
if DJANGO_DEMO:
return R.failed("演示环境,暂无操作权限")
result = services.update_example(request)
return result
# =============================================================
# 删除视图
# =============================================================
@method_decorator(check_login, name="delete")
class ExampleDeleteView(PermissionRequired, View):
"""
删除案例视图
处理DELETE请求,删除指定案例(逻辑删除)。
支持批量删除,多个ID用逗号分隔。
URL: /example/delete/<str:id>
请求方法: DELETE
权限要求:sys:example:delete
"""
# 方法权限标识
permission_required = ('sys:example:delete',)
@operation_log(
title="案例管理-删除记录",
log_type=LogType.DELETE
)
def delete(self, request, id):
"""
处理DELETE请求,删除案例
Args:
request: HttpRequest对象
id: 案例ID字符串,支持逗号分隔的多个ID(如 "1,2,3")
Returns:
JsonResponse: 操作结果的JSON响应
"""
# 演示模式检查
if DJANGO_DEMO:
return R.failed("演示环境,暂无操作权限")
result = services.delete_examples(id)
return result
# =============================================================
# 状态更新视图
# =============================================================
@method_decorator(check_login, name="put")
class ExampleStatusView(PermissionRequired, View):
"""
设置案例状态视图
处理PUT请求,更新案例的启用/禁用状态。
URL: /example/status
请求方法: PUT
权限要求:sys:example:status
"""
# 方法权限标识
permission_required = ('sys:example:status',)
def put(self, request):
"""
处理PUT请求,更新案例状态
Args:
request: HttpRequest对象,请求体包含案例ID和新状态
Returns:
JsonResponse: 操作结果的JSON响应
"""
# 演示模式检查
if DJANGO_DEMO:
return R.failed("演示环境,暂无操作权限")
result = services.update_example_status(request)
return result
# =============================================================
# 数据列表视图(下拉选择用)
# =============================================================
@method_decorator(check_login, name='get')
class ExampleDataView(View):
"""
案例列表获取视图
处理GET请求,返回所有启用案例的列表数据。
用于下拉选择等前端组件。
URL: /example/data
请求方法: GET
权限要求:需要登录
"""
def get(self, request):
"""
处理GET请求,返回案例数据列表
Args:
request: HttpRequest对象
Returns:
JsonResponse: 包含案例列表的JSON响应
"""
result = services.get_example_data()
return R.ok(data=result)
```
## 代码解析
### 视图类继承
```python
@method_decorator(check_login, name="get")
class ExamplePageView(PermissionRequired, View):
```
| 基类/装饰器 | 来源 | 提供能力 |
|:----|:----|:----|
| `View` | Django 内置 | 类视图基类,提供 get/post/put/delete 方法分发 |
| `PermissionRequired` | `middleware/permission_middleware.py` | 权限控制混入类 |
| `@method_decorator(check_login, name="get")` | `middleware/login_middleware.py` | JWT 登录认证 |
### 三层防护机制
```
请求 → check_login(登录校验) → PermissionRequired(权限校验) → operation_log(操作日志) → 业务逻辑
```
#### 1. 登录校验(check_login)
```python
@method_decorator(check_login, name="get")
```
`check_login` 装饰器从请求头 `Authorization: Bearer <token>` 中提取 JWT token,验证其有效性。验证失败返回 `401 Unauthorized`。
```python
def check_login(func):
def wrapper(request, *args, **kwargs):
ignoreURL = ['/login', '/captcha']
if request.path not in ignoreURL:
access_token = request.headers['Authorization']
access_token = access_token.replace('Bearer ', "")
result = parse_payload(access_token)
code = result['code']
if code != 0:
return R.failed(code=401, msg=result['msg'])
return func(request, *args, **kwargs)
return wrapper
```
#### 2. 权限校验(PermissionRequired)
```python
class ExamplePageView(PermissionRequired, View):
permission_required = ("sys:example:page",)
```
`PermissionRequired` 混入类重写了 `has_permission()` 方法,检查当前用户是否拥有所需的权限节点。用户 ID 为 1 的超级管理员自动放行。
```python
class PermissionRequired(PermissionRequiredMixin):
def has_permission(self):
permissions = self.get_permission_required()
user_id = get_user_id(self.request)
# 超级管理员自动放行
if user_id and user_id != 1:
from application.menu import services
permission_list = services.get_user_permissions(user_id)
for permission in permissions:
if permission not in permission_list:
return False
return True
def handle_no_permission(self):
return R.failed("暂无操作权限", 401)
```
#### 3. 操作日志(operation_log)
```python
@operation_log(title="案例管理-查询分页列表", log_type=LogType.QUERY)
def get(self, request):
...
```
`@operation_log` 装饰器自动记录操作日志,包括操作标题、操作类型、请求参数、响应结果、耗时等信息。
| 参数 | 说明 |
|:----|:----|
| `title` | 操作标题,如"案例管理-添加记录" |
| `log_type` | 操作类型,参考 `LogType` 常量 |
| `source` | 操作来源,0=后台系统 |
### 操作类型常量
```python
class LogType:
OTHER = 0 # 其他操作
QUERY = 1 # 查询操作
ADD = 2 # 新增操作
UPDATE = 3 # 修改操作
SAVE = 4 # 保存操作
DELETE = 5 # 删除操作
BATCH_DELETE = 6 # 批量删除
STATUS = 7 # 设置状态
RESET_PWD = 8 # 重置密码
IMPORT = 9 # 导入操作
EXPORT = 10 # 导出操作
UPLOAD = 11 # 上传操作
```
### 演示环境检查
```python
if DJANGO_DEMO:
return R.failed("演示环境,暂无操作权限")
```
写操作(add、update、delete、status)需要检查 `DJANGO_DEMO` 配置。当 `.env` 中设置 `DJANGO_DEMO=True` 时,所有写操作返回失败提示。
### 视图类分类
| 视图类 | HTTP 方法 | 权限 | 说明 |
|:----|:----|:----|:----|
| `ExamplePageView` | GET | `sys:example:page` | 分页查询 |
| `ExampleListView` | GET | 无(仅登录) | 列表查询(不分页) |
| `ExampleDetailView` | GET | `sys:example:detail` | 详情查询 |
| `ExampleAddView` | POST | `sys:example:add` | 添加记录 |
| `ExampleUpdateView` | PUT | `sys:example:update` | 更新记录 |
| `ExampleDeleteView` | DELETE | `sys:example:delete` | 删除记录 |
| `ExampleStatusView` | PUT | `sys:example:status` | 状态更新 |
| `ExampleDataView` | GET | 无(仅登录) | 数据列表(下拉选择) |
### 权限节点格式
```
sys:<module>:<action>
```
| 部分 | 说明 | 示例 |
|:----|:----|:----|
| `sys` | 固定前缀 | `sys` |
| `<module>` | 模块名称 | `example` |
| `<action>` | 操作类型 | `page`、`list`、`detail`、`add`、`update`、`delete`、`status` |
## 开发要点
1. **每个视图类只处理一个 HTTP 方法**:单一职责原则
2. **使用 `@method_decorator(check_login, name="方法名")` 进行登录校验**:确保用户已登录
3. **需要权限控制的视图继承 `PermissionRequired`**:并设置 `permission_required`
4. **写操作必须检查 `DJANGO_DEMO`**:演示环境禁止写操作
5. **使用 `@operation_log` 记录操作日志**:便于审计和追踪
6. **视图层只做请求分发**:业务逻辑全部委托给 Service 层
7. **直接返回 Service 层的结果**:不要在视图层处理业务逻辑
## 总结
视图层使用 Django 类视图,组合三层防护机制:登录校验(check_login)、权限控制(PermissionRequired)、操作日志(operation_log)。每个视图类只处理一个 HTTP 方法,写操作需要检查 DJANGO_DEMO 配置。视图层只做请求分发,业务逻辑全部委托给 Service 层。