7.7 KiB
7.7 KiB
:::tip 文章管理 文章管理模块支持富文本编辑、分类关联、封面图片上传、图集管理等功能。适用于新闻、公告、帮助文档等内容管理场景。 :::
模块结构
application/article/
├── models.py # 文章模型
├── forms.py # 表单验证
├── services.py # 业务逻辑层(自定义函数)
├── views.py # 视图层
└── urls.py # 路由配置
:::warning 自定义 Service 文章模块因涉及文件处理、富文本清洗、图集解析等复杂逻辑,编写自定义 service 函数而非继承通用模式。 :::
文章模型
# application/article/models.py
from application.models import BaseModel
class Article(BaseModel):
"""文章模型类"""
class Meta:
db_table = 'django_article'
category_id = models.IntegerField(null=True, blank=True, verbose_name='分类ID')
title = models.CharField(max_length=150, null=True, blank=True, verbose_name='文章标题')
cover = models.CharField(max_length=255, null=True, blank=True, verbose_name='文章封面')
images = models.TextField(null=True, blank=True, verbose_name='文章图集')
intro = models.CharField(max_length=255, null=True, blank=True, verbose_name='文章导读')
content = models.TextField(null=True, blank=True, verbose_name='文章内容')
author = models.CharField(max_length=100, null=True, blank=True, verbose_name='文章作者')
status = models.IntegerField(default=0, verbose_name='文章状态:0-正常 1-下架')
click = models.IntegerField(default=0, verbose_name='文章点击率')
sort = models.IntegerField(default=0, verbose_name='文章排序')
字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
category_id |
int | 所属分类 ID(关联 category 表) |
title |
str | 文章标题 |
cover |
str | 封面图片路径 |
images |
str | 图集路径(逗号分隔) |
intro |
str | 文章导读/摘要 |
content |
str | 富文本内容(HTML) |
author |
str | 文章作者 |
status |
int | 状态:0-正常 1-下架 |
click |
int | 点击次数(自动统计) |
sort |
int | 排序权重 |
文章状态流转
草稿(0) → 发布(0) → 下架(1) → 重新发布(0)
| 状态 | 说明 | 可执行操作 |
|---|---|---|
| 0-正常 | 文章已发布,前台可见 | 编辑、下架、删除 |
| 1-下架 | 文章已下架,前台不可见 | 编辑、重新发布、删除 |
文件处理机制
文章模块涉及三类文件字段,处理方式各不相同:
1. 封面图片(cover)-- save_file
# 新增时
cover = save_file(data.cover, "article") if data.cover else None
save_file(url, directory) 的处理逻辑:
- 将前端传来的 URL 还原为磁盘绝对路径
- 若文件在临时目录(
temp/),移动到正式目录(upload/article/日期/) - 返回相对路径存入数据库
2. 图集(images)-- _build_images / _parse_images
图集在数据库中存储为逗号分隔的相对路径字符串:
/article/20260907/a.png,/article/20260907/b.png
前端传入数组,后端拼接为字符串存储:
def _build_images(images_list):
"""将图片列表拼接为逗号分隔的字符串"""
if not images_list:
return None
return ",".join([save_file(img, "article") for img in images_list])
def _parse_images(images_str):
"""将逗号分隔的字符串解析为完整 URL 列表"""
if not images_str:
return []
return [get_file_url(img) for img in images_str.split(",")]
3. 富文本内容(content)-- save_content
原始 HTML → 提取图片 → 迁移文件 → 替换路径 → 设置 alt → 存库
from utils.common import save_content
# 处理富文本内容
content = save_content(content, title, "article")
添加文章
def add_article(request):
"""添加文章"""
data, error = parse_request_body(request)
if error:
return R.failed(msg=error)
# 表单验证
form = forms.ArticleForm(data)
if not form.is_valid():
return R.failed(msg=regular.get_err(form))
try:
cleaned_data = form.cleaned_data
# 处理封面图片
cover = save_file(cleaned_data.get('cover'), "article") if cleaned_data.get('cover') else None
# 处理图集
images = _build_images(cleaned_data.get('images'))
# 处理富文本内容
content = save_content(cleaned_data.get('content'), cleaned_data.get('title'), "article")
# 创建文章
Article.objects.create(
category_id=cleaned_data.get('categoryId'),
title=cleaned_data.get('title'),
cover=cover,
images=images,
intro=cleaned_data.get('intro'),
content=content,
author=cleaned_data.get('author'),
status=cleaned_data.get('status', 0),
sort=cleaned_data.get('sort', 0),
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="添加失败,请稍后重试")
查询分页
过滤条件
| 参数 | 类型 | 说明 |
|---|---|---|
title |
模糊搜索 | 文章标题 |
category_id |
精确匹配 | 分类 ID |
status |
精确匹配 | 文章状态 |
排序规则
按 sort 降序 -> id 降序。
响应数据
{
"id": 1,
"title": "DjangoAdmin 3.0 发布",
"cover": "http://domain/uploads/article/20260908/cover.png",
"images": ["http://domain/uploads/article/20260908/1.png"],
"intro": "DjangoAdmin 3.0 正式发布...",
"content": "<p>文章内容...</p>",
"author": "admin",
"status": 0,
"statusText": "正常",
"click": 100,
"sort": 1,
"categoryId": 1,
"categoryName": "产品动态",
"createUser": "admin",
"createTime": "2026-09-08 10:00:00"
}
API 接口
| 接口 | 方法 | 权限节点 | 说明 |
|---|---|---|---|
/article/page |
GET | sys:article:page |
分页查询 |
/article/detail/<int:article_id> |
GET | sys:article:detail |
详情查询 |
/article/add |
POST | sys:article:add |
新增文章 |
/article/update |
PUT | sys:article:update |
编辑文章 |
/article/status |
PUT | sys:article:status |
设置状态 |
/article/delete/<int:article_ids> |
DELETE | sys:article:delete |
删除文章(支持批量) |
前端实现
编辑弹窗
文章编辑弹窗包含:标题、分类选择、封面上传、图集上传、富文本编辑器、状态选择、排序。
<BasicModal @register="registerModal" @ok="handleSubmit" width="800px">
<BasicForm @register="registerForm" />
<!-- 富文本编辑器 -->
<Editor v-model="formData.content" :defaultConfig="editorConfig" />
</BasicModal>
文章列表
文章列表页支持按标题、分类、状态筛选,展示封面缩略图和状态标签。
总结
文章管理模块是项目中典型的「带文件处理」复杂业务模块,核心特点:
1. 自定义 Service:文件处理/富文本清洗/图集解析均为自定义逻辑
2. 三类文件字段:封面(save_file)、图集(逗号分隔)、富文本(save_content)
3. 临时文件迁移:前端上传到临时目录 -> 提交表单后后端迁移到正式目录
4. XSS 防护:富文本经 bleach 白名单清洗
5. 分类关联:通过 category_id 关联分类表
6. 状态管理:支持发布/下架状态切换
7. 点击统计:自动统计文章点击次数