Become a sponsor

文章管理
文章管理模块支持富文本编辑、分类关联、封面图片上传、图集管理等功能。适用于新闻、公告、帮助文档等内容管理场景。
application/article/
├── models.py # 文章模型
├── forms.py # 表单验证
├── services.py # 业务逻辑层(自定义函数)
├── views.py # 视图层
└── urls.py # 路由配置自定义 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-下架 | 文章已下架,前台不可见 | 编辑、重新发布、删除 |
文章模块涉及三类文件字段,处理方式各不相同:
# 新增时
cover = save_file(data.cover, "article") if data.cover else Nonesave_file(url, directory) 的处理逻辑:
temp/),移动到正式目录(upload/article/日期/)图集在数据库中存储为逗号分隔的相对路径字符串:
/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(",")]原始 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"
}| 接口 | 方法 | 权限节点 | 说明 |
|---|---|---|---|
/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. 点击统计:自动统计文章点击次数