Django blog项目《二十一》:后台admin《文档管理功能实现 》

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

一、分析

1. 业务流程

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

    • 根据提供信息进行文档查找(参照文章管理)
  • 从后端查取数据返回到前端,进行页面填充
  1. 请求方式、地址、参数

    • 请求方式:GET

    • 请求地址:/admin/doc/

    • 权限:view_doc

    • 请求参数:

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

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

    • 请求方式:DELETE

    • 请求地址:/admin/doc/edit/<int:doc_id>/

    • 权限:delete_doc

    • 请求参数:

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

    • 判断文档标题、文档描述、文档封面图、文档url是否为空
  • 判断数据库中是否存在id=doc_id的数据

    • 进行表单校验
  • 成功后将数据保存进数据库

    • 将数据返回到前端
  1. 请求方式、地址、参数

    • 请求方式:PUT

    • 请求地址:/admin/doc/edit/<int:doc_id>/

    • 权限:change_doc

    • 请求参数:

      参数名 类型 是否必传 备注
      doc_id int 必传 路径参数
      title char 必传 请求体里
      digest char 必传 请求体里
      image_url url 必传 请求体里
      file_url url 必传 请求体里
  2. 前端功能实

    • 判断文档标题、文档描述、文档封面图、文档url是否为空

    • 发起ajax PUT请求

      • 跳转到文档管理页面
  3. 后端逻辑处理

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

    • 判断文档标题、文档描述、文档封面图、文档url是否为空
    • 进行表单校验
    • 成功后将数据保存进数据库
    • 将数据返回到前端
  2. 请求方式、地址、参数

    • 请求方式:POST

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

    • 权限:add_docs

    • 请求参数:

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

    • 判断文档标题、文档描述、文档封面图、文档url是否为空

    • 发起ajax POST请求

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

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

    • 携带文档发送ajax POST请求到后端

    • 成功后将新的文档url放进对应的元素中

    • 判断文档文件是否存在

    • 判断文档格式是否正确

    • 判段文档大小是否满足要求

    • 通过fastdfs进行文档上传到服务器

    • 返回数据到前端

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

    • 请求方式:POST

    • 请求地址:/admin/upload/doc/

    • 请求参数:

      参数名 类型 是否必传 备注
      doc_file file 必传 请求体里

二、文档展示功能实现

1. urls配置
from django.urls import path

from admin import views

app_name = "admin"

urlpatterns = [

    path("doc/", views.DocIndexView.as_view(), name="doc"),
    path("doc/edit/<int:doc_id>/", views.DocEditView.as_view(), name="doc_edit"),
    path("doc/pub/", views.DocPubView.as_view(), name="doc_pub"),
    path("upload/doc/", views.UploadDocServerView.as_view(), name="upload_doc"),

]

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, LoginRequiredMixin

from news import models
from admin import contains
from docs.models import Docs
from settings import FDFS_URL
from utils.fast.fdfs import client
from admin.forms import ArticleEditForm, DocEditForm, CourseEditForm
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 DocIndexView(PermissionRequiredMixin, View):
    """
    doc show index
    route:/admin/doc/
    permissions:view_docs
    """
    permission_required = ("docs.view_docs",)
    raise_exception = True

    def get(self, request):
        # 1. 从数据库中获取到文档的数据
        docs = Docs.objects.only("id", "title", "create_time", "author__username").filter(is_delete=False)

        # 2. 获取前端传来的数据:判断1个获取一个:start_time、end_time、doc_title、doc_author
        # 判断起始时间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 = ""

        # 判断结束时间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 = ""

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

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

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

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

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

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

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

        page_obj = Paginator(docs, contains.PER_PAGE_NUMBER)

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

        pages_data = get_page_data(page_obj, doc_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 = {
   
            'doc_info': doc_info,
            'paginator': page_obj,
            'start_time': start_time,
            'end_time': end_time,
            'title': title,
            'author': author,
            'other_param': urlencode({
   
                'start_time': start_time,
                'end_time': end_time,
                'title': title,
                'author': author,
            })
        }
        data.update(pages_data)

        return render(request, 'admin/doc/doc_index.html', context=data)
3. 前端逻辑处理
$(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);


    //文档删除
    let $delBtn = $(".btn-del");
    $delBtn.click(function () {
   
        let _this = this;
        let sDocId = $(this).data("doc-id");
        fAlert.alertConfirm({
   
            title: "确定删除该文档吗?",
            type: "error",
            confirmButtonText: "确认删除",
            cancelButtonText: "取消",
            confirmCallback: function confirmCallback() {
   
                $.ajax({
   
                    url: "/admin/doc/edit/" + sDocId + '/',
                    type: "DELETE",
                    dataType: "json",
                })
                    .done(function (res) {
   
                        if (res.errno === "200") {
   
                            message.showSuccess("成功删除文档!");
                            $(_this).parents("tr").remove()
                        } else {
   
                            swal.showInputError("删除失败:" + res.errmsg);
                        }
                    })
                    .fail(function () {
   
                        alert("服务器超时,请重试!")
                    })


            }
        })


    });


    // 获取cookie
    function getCookie(name) {
   
        let cookieValue = null;
        if (document.cookie && document.cookie !== '') {
   
            let cookies = document.cookie.split(';');
            for (let i = 0; i < cookies.length; i++) {
   
                let cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
   
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }

    function csrfSafeMethod(method) {
   
        // these HTTP methods do not require CSRF protection
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }

    // 添加token到request中
    $.ajaxSetup({
   
        beforeSend: function (xhr, settings) {
   
            if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
   
                xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
            }
        }
    });
});
4. html页面填充
{% extends 'admin/base/base.html' %}
{% load staticfiles %}

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

{% block css %}
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值