Django blog项目《十八》:后台admin《文章管理功能实现》

文章管理功能,实现文章的增、删、改、查和图片上传到服务器功能功能的实现

一、分析

1. 业务流程

1.文章展示
  1. 业务流程

    • 前端通过form表单提交数据

    • 判断起始查询时间是否满足要求并转化为时间格式

    • 判断起始查询时间是否满足要求并转化为时间格式

    • 判断起始时间和结束时间输入的三种情况:1.起始时间有、结束无;2.起始时间无、结束时间有;3.起始时间大于结束时间

    • 模糊查询文章标题,并判断文章标题是否存在

    • 模糊查询文章作者,并判断文章作者是否存在,

    • 对数据进行分页处理

    • 将时间转化为字符串

    • 构建参数和url路径参数传递给前端

  2. 请求方式、地址、参数

    • 请求方式:GET

    • 请求地址:/admin/article/

    • 权限:view_articles

    • 请求参数:

      参数名 类型 是否必传 备注
      start_time datatime 不是必传
      end_time datatime 不是必传 form表单参数
      title char 不是必传 form表单参数
      author char 不是必传 form表单参数
      tag int 不是必传 form表单参数
2. 文章删除功能
  1. 业务流程

    • 从前端传递一个带有文章id的delete请求
    • 判断数据库中是否有该数据
    • 逻辑删除该文章,并返回数据到前端
  2. 请求方式、地址、参数

    • 请求方式:DELETE

    • 请求地址:/admin/article/edit/<int:article_id>/

    • 权限:delete_articles

    • 请求参数:

      参数名 类型 是否必传 备注
      article_id int 必传 路径参数
3. 文章修改功能
  1. 业务流程

    • 判断文章标题是否为空

    • 判断文章标摘要是否为空

    • 判断文章标签是否为空或者为0

    • 判断文章缩略图是否为空

    • 判断文章内容是否为空

    • 将前端传来的数据转化为字典传递给form表单进行校验

    • 校验成功后更新进数据库

    • 返回数据到前端

  2. 请求方式、地址、参数

    • 请求方式:PUT

    • 请求地址:/admin/article/edit/<int:article_id>/

    • 权限:change_articles

    • 请求参数:

      参数名 类型 是否必传 备注
      article_id int 必传 路径参数
      title char 必传 请求体里
      digest char 必传 请求体里
      tag int 必传 请求体里
      image_url url 必传 请求体里
      content text 必传 请求体里
  3. 前端功能实

    • 判断文章标题是否为空

    • 判断文章标摘要是否为空

    • 判断文章标签是否为空或者为0

    • 判断文章缩略图是否为空

    • 判断文章内容是否为空

    • 发起ajax PUT请求

      • 跳转到文章管理页面
  4. 后端逻辑处理

    • 接收前端传来的数据并转化为字典
    • 通过form表单校验上面数据
    • 校验成功后将数据保存进数据库
4. 文章发布功能
  1. 业务流程

    • 判断文章标题是否为空
    • 判断文章标摘要是否为空
    • 判断文章标签是否为空或者为0
    • 判断文章缩略图是否为空
    • 判断文章内容是否为空
    • 将前端传来的数据转化为字典传递给form表单进行校验
    • 校验成功后更新进数据库
    • 返回数据到前端
  2. 请求方式、地址、参数

    • 请求方式:PUT

    • 请求地址:/admin/article/pub/

    • 权限:change_articles

    • 请求参数:

      参数名 类型 是否必传 备注
      title char 必传 请求体里
      digest char 必传 请求体里
      tag int 必传 请求体里
      image_url url 必传 请求体里
      content text 必传 请求体里
  3. 前端功能实

    • 判断文章标题是否为空

    • 判断文章标摘要是否为空

    • 判断文章标签是否为空或者为0

    • 判断文章缩略图是否为空

    • 判断文章内容是否为空

    • 发起ajax POST请求

      • 跳转到文章管理页面
  4. 后端逻辑处理

    • 接收前端传来的数据并转化为字典
    • 通过form表单校验上面数据
    • 校验成功后将数据保存进数据库
5. 上传图片到服务器
  1. 业务流程

    • 携带图片文件发送ajax POST请求到后端

    • 成功后将新的图片url放进对应的元素中

    • 判断图片文件是否存在

    • 判断图片格式是否正确

    • 判断图片大小是否满足要求

    • 通过fastdfs进行图片上传到服务器

    • 返回数据到前端

  2. 请求方式、地址、参数

    • 请求方式:POST

    • 请求地址:/admin/article/images/

    • 请求参数:

      参数名 类型 是否必传 备注
      article_id int 必传 请求体里
      priority int 必传 请求体里
  3. 前端处理

    • 获取到图片文件

    • 发送ajax POST请求

      • 新的图片url放进对应的元素中
  4. 后端逻辑

    • 判断图片文件是否存在
    • 判断图片格式是否正确
    • 判断图片大小是否满足要求
    • 通过fastdfs进行图片上传到服务器
    • 返回数据到前端

二、文章展示功能实现

1. urls配置
from django.urls import path

from admin import views

app_name = "admin"

urlpatterns = [

    path("article/", views.ArticleManageView.as_view(), name="article"),
  

]
2. views视图逻辑处理
import json
from datetime import datetime
from urllib.parse import urlencode

from django.views import View
from django.shortcuts import render
from django.core.paginator import Paginator, EmptyPage
from django.contrib.auth.mixins import PermissionRequiredMixin

from news import models
from admin import contains
from admin.forms import ArticleEditForm
from utils.page.per_page import get_page_data
from utils.res_code.res_code import Code, error_map
from utils.res_code.json_function import to_json_data



# 文章展示汇总
class ArticleManageView(PermissionRequiredMixin, View):
    """
    article list manage view
    route:/admin/article/
    permission:view_articles
    """
    permission_required = ("news.view_articles",)
    raise_exception = True

    def get(self, request):
        # 1. 从数据库中查取到文章标签数据:下拉列表
        tags_queryset = models.Tags.objects.only("name").filter(is_delete=False)
        # 2. 从数据库中获取到文章数据:数据展示
        article_queryset = models.Articles.objects. \
            only("id", "title", "create_time", "author__username", "tag__name"). \
            filter(is_delete=False)
        # 3. 获取前端传来的数据:判断1个获取一个:start_time、end_time、article_title、article_author、article_tag

        # 3.1 判断起始时间start_time
        try:
            start_time = request.GET.get("start_time", "").strip()
            start_time = datetime.strptime(start_time, "Y%m%d%")
        except Exception as e:
            # logger.info("起始时间格式错误:{}".format(e))
            start_time = ""

        # 3.2 判断结束时间end_time
        try:
            end_time = request.GET.get("end_time", "").strip()
            end_time = datetime.strptime(end_time, "Y%m%d%")
        except Exception as e:
            # logger.info("起始时间格式错误:{}".format(e))
            end_time = ""

        # 3.3 判断起始时间和结束时间输入的三种情况:1.起始时间有、结束无;2.起始时间无、结束时间有;3.起始时间大于结束时间
        # 3.3.1 起始时间有、结束无
        if start_time and not end_time:
            article_queryset = article_queryset.filter(update_time__lte=start_time)

        # 3.3.2 起始时间无、结束时间有
        if end_time and not start_time:
            article_queryset = article_queryset.filter(update_time__gte=end_time)

        # 3.3.3 起始时间大于结束时间
        if start_time and end_time:
            article_queryset = article_queryset.filter(update_time__range=(start_time, end_time))
            if not article_queryset:
                return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])

        # 4. 对文章标题进行判断/模糊查询
        title = request.GET.get("title", "").strip()
        if title:
            article_queryset = article_queryset.filter(is_delete=False, title__icontains=title)

        # 5. 对文章作者进行判断模糊查询
        author = request.GET.get("author", "").strip()
        if author:
            article_queryset = article_queryset.filter(is_delete=False, author__username__icontains=author)

        # 6. 对文章标签进行判断
        tag_id = int(request.GET.get("tag_id", 0))
        article_queryset = article_queryset.filter(is_delete=False, tag_id=tag_id) or article_queryset.filter(
            is_delete=False)

        # 5. 进行分页处理
        try:
            page_num = int(request.GET.get("page", 1))
        except Exception as e:

            logger.info("页码格式错误:{}".format(e))
            page_num = 1

        page_obj = Paginator(article_queryset, contains.PER_PAGE_NUMBER)

        try:
            article_info = page_obj.page(page_num)
        except EmptyPage:  # 页码为空
            article_info = page_obj.page(page_obj.num_pages)

        pages_data = get_page_data(page_obj, article_info)

        # 将时间转化为字符串
        start_time = start_time.strftime("%Y%m%d") if start_time else ""
        end_time = end_time.strftime("%Y%m%d") if end_time else ""
        # 6. 将数据传递给前端
        data = {
   
            'article_info': article_info,
            'tags': tags_queryset,
            'paginator': page_obj,
            'start_time': start_time,
            'end_time': end_time,
            'title': title,
            'author': author,
            'tag_id': tag_id,
            'other_param': urlencode({
   
                'start_time': start_time,
                'end_time': end_time,
                'title': title,
                'author': author,
                'tag_id': tag_id,

            })
        }
        data.update(pages_data)

        return render(request, 'admin/news/article_manage.html', context=data)

3. js前端逻辑实现

js里面使用到了两个js插件 fsweetalert.jsmessage.js

$(function () {
   
    let $startTime = $("input[name=start_time]");
    let $endTime = $("input[name=end_time]");
    const config = {
   

        autoclose: true,// 自动关闭

        format: 'yyyy/mm/dd',// 日期格式

        language: 'zh-CN',// 选择语言为中文

        showButtonPanel: true,// 优化样式

        todayHighlight: true, // 高亮今天

        calendarWeeks: true,// 是否在周行的左侧显示周数

        clearBtn: true,// 清除

        startDate: new Date(1900, 10, 1),// 0 ~11  网站上线的时候

        endDate: new Date(), // 今天
    };
    $startTime.datepicker(config);
    $endTime.datepicker(config);
}
 )
4. html页面填充
{% extends 'admin/base/base.html' %}
{% load staticfiles %}

{% block title %}
    文章管理页
{% endblock %}

{% block css %}
    <link rel="stylesheet" href="{% static 'css/admin/news/bootstrap-datepicker.min.css' %}">
{% endblock %}

{% block content_header %}
    文章管理
{% endblock %}

{% block content_header_brief %}
    文章的增删改查
{% endblock %}


{% block content %}
    <style>
        .ml20 {
    
            margin-left: 20px;
        }

        .mt20 {
    
            margin-top: 20px;
        }
    </style>
    <div class="content">
        <div class="container-fluid">
            <div class="box">
                <div class="box-header" style="margin: 0;">
                    <form action="" class="form-inline">
                        <div class="form-group ml20 mt20">
                            <label for="select-time">时间:</label>
                            {% if start_time %}
                                <input type="text" class="form-control" placeholder="请选择起始时间" readonly
                                       id="select-time" name="start_time" value="{
    { start_time }}">
                            {% else %}
                                <input type="text" class="form-control" placeholder="请选择起始时间" readonly
                                       id="select-time" name="start_time">
                            {% endif %}
                            -
                            {% if end_time %}
                                <input type="text" class="form-control" placeholder="请选择结束时间" readonly
                                       name="end_time" value="{
    { end_time }}">
                            {% else %}
                                <input type="text" class="form-control" placeholder="请选择结束时间" readonly name="end_time">
                            {% endif %}
                        </div>
                        <div class="form-group ml20 mt20">
                            <label for="title">标题:</label>
                            {% if title %}
                                <input type="text" class="form-control" placeholder="请输入标题" id="title" name
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值