紧锣密鼓完成小闭环,微型 CSDN 项目快快进入下一阶段

橡皮擦,一个逗趣的互联网高级网虫。新的系列,让我们一起进入 Django 世界。

二十二、导航菜单的增删改查

学习任何编程语言,都要先小碎步快快跑,等到积累足够,就直接奔上一个大山头。

本篇博客要把导航菜单部分进行收尾,上篇已经对导航菜单的增加进行了实现,也同步完成了查询列表功能,不过该页面呈现比较简单,并没有实现分页操作,关于分页部分,在后续的内容进行编写,本文优先实现对导航菜单的编辑与删除。

22.1 路由编写

对于 Django 的 MVT 模式,很多人都有自己的编写习惯,橡皮擦习惯性的从路由开始进行编写。

修改 navbar/urls.py 文件代码。

from django.urls import path
from . import views

urlpatterns = [
    path('add/', views.NavItemCreateView.as_view(), name='navbar-add'),
    path('list/', views.NavItemListView.as_view(), name='navbar-list'),
    path('<int:pk>/update', views.NavItemUpdateView.as_view(), name='navbar-update'),
    path('<int:pk>/delete', views.NavItemDeleteView.as_view(), name='navbar-delete')
]

在上述代码中,新配置了更新与删除的路由,并分别指定了 views.py 中的具体类名。

22.2 补齐 views.py 中的类

修改 views.py 文件,重点补齐路由中调用的类,完整代码如下,NavItemUpdateViewNavItemDeleteView 为新增类代码。

from django.shortcuts import render
from django.views.generic import CreateView, ListView,UpdateView,DeleteView
from utils.mixins import AjaxResponseMixin
from .models import NavItem
from django.http import JsonResponse
from django.urls import reverse, reverse_lazy


# Create your views here.
class NavItemCreateView(AjaxResponseMixin, CreateView):
    model = NavItem
    fields = ["title", "order", "url"]
    template_name_suffix = '_add'
    success_url = "/navbar/list"


class NavItemListView(ListView):
    model = NavItem
    context_object_name = 'navbar_list'

# 更新
class NavItemUpdateView(AjaxResponseMixin,UpdateView):
    model = NavItem
    fields = ["title", "order", "url"]
    context_object_name = "navitem"
    template_name_suffix = "_edit"
    success_url = "/navbar/list"

# 删除
class NavItemDeleteView(AjaxResponseMixin, DeleteView):
    model = NavItem
    success_url = "/navbar/list"
    def delete(self, request, *args, **kwargs):
        super(NavItemDeleteView,self).delete(request,*args,**kwargs)
        return JsonResponse({
            "state":"success"
        })

22.3 补齐编辑逻辑

实现更新页面模板,由过往代码知道模板页面的名称应该为 navitem_edit.html,在该文件中模仿新增页面编写出更新页面。
该页面需要对数据进行回显展示,例如 value="{{navitem.url}}" ,其中 navitemviews.py 文件中通过设置 context_object_name 而来。

{% extends 'csdn/backend/backend_common.html' %} 
{% block option-title%}导航菜单编辑{%endblock%} 
{% block content%}

<div class="col-md-12">
  <form class="form-horizontal" id="data-form">
    {% csrf_token %} 
    <div class="form-group">
      <label for="title" class="col-sm-2 control-label">标题:</label>
      <div class="col-sm-10">
        <input
          type="text"
          class="form-control"
          id="title"
          name="title"
          placeholder="请输入标题"
          value="{{navitem.title}}"
        />
      </div>
    </div>
    <div class="form-group">
      <label for="url" class="col-sm-2 control-label">链接</label>
      <div class="col-sm-10">
        <input
          type="text"
          class="form-control"
          id="url"
          name="url"
          placeholder="请输入链接"
          value="{{navitem.url}}"
        />
      </div>
    </div>
    <div class="form-group">
      <label for="order" class="col-sm-2 control-label">顺序</label>
      <div class="col-sm-10">
        <input
          type="text"
          class="form-control"
          id="order"
          name="order"
          placeholder="请输入顺序"
          value="{{navitem.order}}"
        />
      </div>
    </div>
    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <button class="btn btn-info" id="btn-submit">更新</button>
      </div>
    </div>
  </form>
</div>
{% endblock %} {% block ext_js %}
<script type="text/javascript">
  $('#btn-submit').click(function(e){
      e.preventDefault();
      $.post('{% url 'navbar-update' navitem.pk %}',$("#data-form").serializeArray(),function(data){
          var state = data.state;
          if(state == "success"){
              alert("编辑成功")
              location.href = "/navbar/list"
          }
     },"json")
  })
</script>

{% endblock %}

其中服务器,依据路由访问 http://127.0.0.1:8000/navbar/1/update 进入编辑页面,注意中间的主键ID 1 可以切换为其它数值,每个数值都对应一条数据。

在列表页面实现编辑页面跳转,点击按钮跳转该数据的编辑页面。

<td>
  <a href="{% url 'navbar-update' item.pk %}" class="btn btn-primary" role="button">编辑</a>
  <button class="btn btn-danger" role="button">删除</button>
</td>

22.4 补齐删除逻辑

删除操作也在列表页实现,在每个删除按钮上都绑定记录的主键。

<button class="btn btn-danger" role="button" data-id="{{item.id}}">删除</button>

增加删除操作的 JS 代码如下:

{% block ext_js %}
<script type="text/javascript">
  $(".btn-danger").click(function () {
    var dom_item = this;
    $.post(
      '{% url "navbar-delete" 00 %}'.replace("0", this.dataset["id"]),
      {},
      function (data) {
        var state = data.state;
        if (state === "success") {
          dom_item.parentElement.parentElement.setAttribute("hidden", "");
          alert("删除成功!");
        }
      }
    );
  });
</script>
{% endblock %}

此时如果进行删除操作,会出现如下错误,该错误为 CSRF 验证失败,在新增与更新操作的时候,我们都是通过在 form 表单中增加 {% csrf_token %} 实现该验证,但删除操作是在列表中实现的,无法像表单一样增加 {% csrf_token %} ,故需要调整本部分逻辑代码。

Forbidden (403)
CSRF verification failed. Request aborted.

templates/csdn/common.html 中增加 CSRF 验证逻辑。

<script type="text/javascript">
  var csrftoken = $.cookie("csrftoken");
  function csrfSafeMethod(method) {
    return /^(GET|HEAD|OPTIONS|TRACE)$/.test(method);
  }
  $.ajaxSetup({
    beforeSend: function (xhr, settings) {
      if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
        xhr.setRequestHeader("X-CSRFToken", csrftoken);
      }
    },
  });
</script>

然后去除新增与更新页面 {% csrf_token %} ,重新测试效果,查看是否正常运行。

22.5 补齐后台管理功能

页面添加完毕之后,可以在后台通用框架中新增相关功能。

templates/navbar 文件夹中新增 navbar_link.html 文件 ,编写代码:

<ul class="nav nav-sidebar">
  <li id="navbar-list">
    <a href="{% url 'navbar-list'%}">导航菜单列表</a>
  </li>
  <li id="navbar-add">
    <a href="{% url 'navbar-add'%}">导航菜单添加</a>
  </li>
</ul>

打开 templates/csdn/backend/nav.html 文件,引入 navbar_link.html 文件。

<ul class="nav nav-sidebar">
  <li id="overview">
    <a href="#">工作台</a>
  </li>
</ul>
{% include 'navbar/navbar_link.html' %}

最后在 bacnend.html 文件中导入导航菜单模板。

{% block body %}
<nav class="navbar nav-inverse">
  <div class="contain-fluid">
    <div class="navbar-header">
      <a href="#" class="navbar-brand">后台管理</a>
    </div>
  </div>
</nav>
<div class="container-fluid">
  <div class="row">
    <div class="col-md-2 sidebar">{% include 'csdn/backend/nav.html' %}</div>
    <div class="col-md-10 main">
      <h1 class="page-header">{% block option-title%}{%endblock%}</h1>
      <div class="row placeholders">{% block content%}{%endblock%}</div>
    </div>
  </div>
</div>

{% endblock %}

最终呈现的效果如下:

20210505120820860[1].png

21.6 本篇博客小节

本小节完成了导航的增删改查,并且在后台新增了列表与新增的入口,页面美观度部分非本系列重点知识,所以先实现效果吧。

本文章属于《滚雪球学 Python 第三轮》中的一篇,欢迎继续关注。

今天是持续写作的第 <font color="red">148</font> / 200 天。可以点赞、评论、收藏啦。

继续阅读

  1. 国内,首套,成体系,技术博客写作专栏发布啦
  2. 学弟学妹:大佬们,别劝了,学不动了,学不动了
  3. 自己动手写个微型 CSDN 吧,还能实现网页版 Blink,No.1

本文长尾关键词,提供给机器使用,阅读请忽略
django api django redis django bootstrap
topview django flask django cms
django3 pycharm django django 开源

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352

推荐阅读更多精彩内容