Files
djangoadmin-wiki/DjangoAdmin_Django_NaiveVue/zh/volume2/view.md
T
2026-09-12 23:12:15 +08:00

270 lines
9.0 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):
"""案例分页数据查询视图"""
permission_required = ("sys:example:page",)
@operation_log(title="案例管理-查询分页列表", log_type=LogType.QUERY)
def get(self, request):
result = services.get_example_page(request)
return result
@method_decorator(check_login, name='get')
class ExampleListView(View):
"""案例列表获取视图(支持筛选,不分页)"""
def get(self, request):
result = services.get_example_list(request)
return R.ok(data=result)
@method_decorator(check_login, name="get")
class ExampleDetailView(PermissionRequired, View):
"""案例详情查询视图"""
permission_required = ("sys:example:detail",)
@operation_log(title="案例管理-查询记录详情", log_type=LogType.QUERY)
def get(self, request, id):
data = services.get_example_detail(id)
return R.ok(data=data)
@method_decorator(check_login, name="post")
class ExampleAddView(PermissionRequired, View):
"""添加案例视图"""
permission_required = ("sys:example:add",)
@operation_log(title="案例管理-添加记录", log_type=LogType.ADD)
def post(self, request):
if DJANGO_DEMO:
return R.failed("演示环境,暂无操作权限")
result = services.add_example(request)
return result
@method_decorator(check_login, name="put")
class ExampleUpdateView(PermissionRequired, View):
"""更新案例视图"""
permission_required = ('sys:example:update',)
@operation_log(title="案例管理-更新记录", log_type=LogType.UPDATE)
def put(self, request):
if DJANGO_DEMO:
return R.failed("演示环境,暂无操作权限")
result = services.update_example(request)
return result
@method_decorator(check_login, name="delete")
class ExampleDeleteView(PermissionRequired, View):
"""删除案例视图"""
permission_required = ('sys:example:delete',)
@operation_log(title="案例管理-删除记录", log_type=LogType.DELETE)
def delete(self, request, id):
if DJANGO_DEMO:
return R.failed("演示环境,暂无操作权限")
result = services.delete_examples(id)
return result
@method_decorator(check_login, name="put")
class ExampleStatusView(PermissionRequired, View):
"""设置案例状态视图"""
permission_required = ('sys:example:status',)
def put(self, request):
if DJANGO_DEMO:
return R.failed("演示环境,暂无操作权限")
result = services.update_example_status(request)
return result
@method_decorator(check_login, name='get')
class ExampleDataView(View):
"""案例列表获取视图"""
def get(self, request):
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 层。