Skip to content

文章管理

文章管理模块支持富文本编辑、分类关联、封面图片上传、图集管理等功能。适用于新闻、公告、帮助文档等内容管理场景。

模块结构

application/article/
├── models.py     # 文章模型
├── forms.py      # 表单验证
├── services.py   # 业务逻辑层(自定义函数)
├── views.py      # 视图层
└── urls.py       # 路由配置

自定义 Service

文章模块因涉及文件处理、富文本清洗、图集解析等复杂逻辑,编写自定义 service 函数而非继承通用模式。

文章模型

python
# 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_idint所属分类 ID(关联 category 表)
titlestr文章标题
coverstr封面图片路径
imagesstr图集路径(逗号分隔)
introstr文章导读/摘要
contentstr富文本内容(HTML)
authorstr文章作者
statusint状态:0-正常 1-下架
clickint点击次数(自动统计)
sortint排序权重

文章状态流转

草稿(0) → 发布(0) → 下架(1) → 重新发布(0)
状态说明可执行操作
0-正常文章已发布,前台可见编辑、下架、删除
1-下架文章已下架,前台不可见编辑、重新发布、删除

文件处理机制

文章模块涉及三类文件字段,处理方式各不相同:

1. 封面图片(cover)-- save_file

python
# 新增时
cover = save_file(data.cover, "article") if data.cover else None

save_file(url, directory) 的处理逻辑:

  1. 将前端传来的 URL 还原为磁盘绝对路径
  2. 若文件在临时目录(temp/),移动到正式目录(upload/article/日期/
  3. 返回相对路径存入数据库

2. 图集(images)-- _build_images / _parse_images

图集在数据库中存储为逗号分隔的相对路径字符串:

/article/20260907/a.png,/article/20260907/b.png

前端传入数组,后端拼接为字符串存储:

python
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 → 存库
python
from utils.common import save_content

# 处理富文本内容
content = save_content(content, title, "article")

添加文章

python
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 降序。

响应数据

json
{
    "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/pageGETsys:article:page分页查询
/article/detail/<int:article_id>GETsys:article:detail详情查询
/article/addPOSTsys:article:add新增文章
/article/updatePUTsys:article:update编辑文章
/article/statusPUTsys:article:status设置状态
/article/delete/<int:article_ids>DELETEsys:article:delete删除文章(支持批量)

前端实现

编辑弹窗

文章编辑弹窗包含:标题、分类选择、封面上传、图集上传、富文本编辑器、状态选择、排序。

vue
<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. 点击统计:自动统计文章点击次数

小蚂蚁云团队 · 提供技术支持