Django项目之订单管理part3

embedded/2025/3/16 18:33:06/

一.前言

前面两章已经把登录给做完了,这一章节要说的是登录的校验和登录以后的菜单展示,内容还是很多的。

二.菜单和权限

2.1 是否登录

当我们进入其他的页面,我们首先要判断是否登录,这个时候我们就要借助中间件来做session和cookie的判断。

process_request,基于他实现用户是否已登录,继续;未登录则返回登录界面。
    - return None,继续向后访问
    - return 对象,直接返回。
    
process_view,权限校验
    - return None,继续向后访问
    - return 对象,直接返回。
    - 在他的request对象中有 resolver_match  ,包含当前请求的视图路由信息  .name->sms_login
    
process_response

 那我们就先来编写中间件,我们现在setting里面注册中间件,并且加上自己的默认配置

这个自己加的配置是我们方便我们更改的,我们在昨天的视图函数里面也更改成seetings.xxx,自定义的通常都会加上前缀,避免于django内部定义的产生冲突。

这样我们就成功编写中间件来判断是否成功登录了

2.2 动态菜单 

2.2.1 基础编写

这里我就不先说权限了,而是先说动态菜单,因为权限和菜单是绑定的,先说完菜单才更好讲权限,要让不同角色用户看到不同的菜单。

我们就要想如何让不同角色用户进入的菜单不同呢?我们前面铺垫了那么久,在最开始项目的时候也说了,首先我们可以在settings里面用上一个写上一个menu的字典,用户和管理员分别对应不同的标题和url,然后我们可以选择用if判断和for循环把页面展示到html里面去,但是我们觉得这样太麻烦了,可以借助自定义模板语法,用inclusion_tag把一个个小片段放入到html里面,那我们读取信息在哪里读取呢?我们登录成功之后,是不是在中间件里面把用户信息放入reuqest里面了,刚好我们每次传入模板的时候都要加上这个request,这样不就很简单了嘛(如果不记得自定义模板可以去看前面的文章)。

我们想要菜单的样子如上图这样,我们就应该想想要如何设计了,首先我们先不管美化,先想想如何设计数据的位置。 

我们发现这个是一级菜单和二级菜单,一级菜单没有啥链接,但是有一个小的图标,二级菜单就是一个链接,那我们要设计这个肯定就是得在settings里面的menu来设计了。

那我们就可以这么设计,icon我们可以借助fontawesome里面的图标

Font Awesome图片库使用 - Font Awesome中文文档网https://fontawesome.uihtm.com/icons.html

也就可以用这个里面的class进行替代,当然如果有其他的也可以用其他的类似于链接呀等等,根据自己的情况来。

但是我们还会在每个链接加上一个name属性,这个我们后面要用到,也就是每个页面底下都会有很多链接,我们通过这个name来找到父标签让其默认选中,现在不懂没事,后面讲到的时候肯定就懂了。

这样就写出了一个很基础的页面 

2.2.2 美化

我们美化的话肯定得要html,css和js,这里不会一一编写,只会说清楚逻辑,然后直接给代码。

我们肯定得把美化的公共页面写入母板,然后后面来继承就好了。那我们先创建一个layout.html,再在这个基础上进行美化。

那我们就先导入一下fontawesome,然后还有一些事先先好的css,js等

layout.html 

menu.html 

home.html 

具体的所有代码等讲完了再给大家

具体的长这样,虽然不是很好看,但是也能看了,这样我们就可以实现在setting里面改配置来改页面了

2.2.3 默认选中

这里先讲一个基础的版本的,等讲完权限管理再来讲一个一个版本的

我们这里先给大家截屏代码再给大致思路

这样就好了,我们现在来说为什么,我们默认选中可以用当前的url和设置中的url进行匹配,如果一样那么就把class属性改成active,这是因为我们在common.js里已经写过了,所以直接用就好了,那我们 user_menu_list=copy.deepcopy(settings.YY_MENU[request.userinfo.role])为什么要copy一下呢?

这里给了一段代码大家运行一下就知道了

这个是deepseek给出的答案:

在这个代码中,ab 都是指向同一个字典对象的引用。因为在 Python 中,赋值语句 b = a 并不会复制字典的内容,而是将 b 绑定到与 a 相同的字典对象上。

所以,修改 b 中的内容也会影响到 a,因为它们指向同一个字典。

所以我们只能copy一下!

2.2.4 顶部导航 

我们想在顶部实现这么一个效果,肯定是要在layout里面写代码,这里还是直接给代码了 

然后我们肯定还是要写一个注销功能的视图函数,这个就很好写了

只需要清除session会话信息,然后重定向到登录就好了。

2.3 权限校验

2.3.1 权限和菜单选中

一个权限,就是一个URL

用户具有的权限=用户可以访问这个URL

那我们就可以在配置文件写上一个字典,键值就用url对应的name,为什么不直接用url呢?因为如果用url,有的url是可变的,这将没法搞。

我们就这么用,parent就是子路由的父亲,类似于order下面有order_add等等子路由,这样的目的是为了我们点击子路由时也能够默认选中父亲的标签,还可以进行路径导航,这个我们接下来再说。

我们就需要在process_view里面进行路由匹配,然后判断是否有权限,再来获取最上层的父节点,最后存入request对象里面。但是我们发现点击子节点的时候,左边菜单是没有默认选中的。 

我们就可以这么判断,只需要对应好,就可以解决默认选中的问题了。 

2.3.2 路径导航 

 

我们在中间件中获得全部的url的name,然后反转一下放入request对象中

我们就让最后一个点击加上#,减少对服务器的压力,同时以后最后一个肯定是类似于编辑那种,我们也不好根据id反向生成url 

然后再用 inclusion_tag

生成一个导航页面 

 

放入母板中的这里,这样就实现了路径导航啦

但是我们还有几个问题没有处理,我们这里说一下

1.当我们点击注销的时候,会发现无权访问,这个是因为注销我们没有添加到权限菜单里面,但是我们如果我们都添加有点难搞,所以我们可以写成一个公共的,再添加进去,这样就可以省下来不少事

这样就可以啦

2.当我们登陆的时候,会无法访问登录页面,这个在我们当时 process_request里面说过了,我们当时设置了一个白名单,让不需要登陆的链接也可以进去,那我们在 process_view也要判断一下白名单

这样就可以了啦!

三.级别管理 

3.1 级别管理的基础页面

from django.db import models


class ActiveBaseModel(models.Model):
    active = models.SmallIntegerField(verbose_name="状态", default=1, choices=((1, "激活"), (0, "删除"),))

    class Meta:
        abstract = True
        
class Level(ActiveBaseModel):
    """ 级别表 """
    title = models.CharField(verbose_name="标题", max_length=32)
    percent = models.IntegerField(verbose_name="折扣")

我们肯定是要对这个表进行操作,那我们还是老规矩,得先写页面,但是在写页面的时候,我们先把前面测试的那些页面都删掉

 我们这样就可以 实现一个基础的页面了,那我们接下来就是要弄这个新建了,我们还是要新建一个这个页面,这里刚好可以和大家讲解一下modelform和form的区别。

3.2 新建级别

3.2.1 form 

这个是我们写的html,和验证码登录的时候类似。

这个是我们用form写的,但是这种只用到数据库的,我们用modelform更加简单。

3.2.2 modelform  

from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidatorclass ActiveBaseModel(models.Model):"""用来继承的表"""active = models.SmallIntegerField(verbose_name='状态', default=1,choices=((1, '激活'), (0, '删除')))  # 用来进行逻辑删除而不是物理删除class Meta:abstract = True  # 把 ActiveBaseModel 设置为抽象类,防止在数据库中创建表
class Level(ActiveBaseModel):"""级别表"""title = models.CharField(verbose_name='标题', max_length=32)percent = models.IntegerField(verbose_name='折扣',help_text='请输入1~100整数表示百分比',validators=[MinValueValidator(1),  # 最小值为 1MaxValueValidator(100)  # 最大值为 100])

 

- ModelForm,表的增删改查方便。
- Form,请求校验 -> 复杂SQL操作。

我们也可以在数据库里添加上form表中的一些校验,原来的label就相当于是verbose_name,并且最后保存到数据库只需要form.sava(),这样就很简单了

思考:无论在使用Form和ModelForm时,想要让页面好看,就需要将每个字段的插件中给他设置form-control样式。  

这里直接给代码,以form的格式给,modelform也是一模一样

python">from django.shortcuts import render, redirect
from django.urls import reverse
from web import models
from django import forms
from django.core.validators import MinValueValidator, MaxValueValidatorclass LevelForm(forms.Form):title=forms.CharField(label='标题',required=True,)percent=forms.IntegerField(label='折扣',required=True,validators=[MinValueValidator(1), MaxValueValidator(100)],help_text='请输入1~100整数表示百分比')def __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)# {'title':对象,"percent":对象}for name, field in self.fields.items():field.widget.attrs['class'] = "form-control"field.widget.attrs['placeholder'] = "请输入{}".format(field.label)

3.2.3 boostrap样式优化 

先和大家讲一下面向对象小知识点super

 

 

 

 

通过这个知识点我们知道了super的继承方法

 

3.3 编辑级别 

还是首先要定义一个url,再加上权限,这里我就不截屏了。

因为我们编辑的页面和增加的页面是一样的,所以我们就把之前的level_add.html改成level_form.html了,我们进来之后页面和下面这样

 

但是我们肯定是想要在页面上显示当前的默认值,方便我们进行修改
form或modelForm显示默认值

form = LevelForm(initial={'title': "xxx"}) 

modelForm显示默认值

level_object = models.Level.objects.filter(id=pk).first()
form = LevelModelForm(instance=level_object) 

 

我们也是可以form.save(),但是和新增不同的是,修改的话必须加上instance

form=LevelModelForm(data=request.POST,instance=level_object)

 3.4 删除级别

因为我们是逻辑删除,所以不能用delete,这里我们也写的简单,不用对话框来确认,后面会再来改的,这样就实现了级别列表

四 知识点的梳理和扩展

  • ModelForm

  • super关键字 + 类继承

4.1 Form和ModelForm的功能

  • Form

    编写字段
    生成HTML标签 + 插件 + 和参数的配置
    表单的验证
  • ModelForm

    不编写字段,直接引用Model字段【优秀】
    生成HTML标签 + 插件 + 和 参数的配置
    表单的验证
    保存(新增、更新)
    • 不编写字段,直接引用Model字段

      class LevelModelForm(forms.ModelForm):class Meta:model = models.Levelfields = ['title', 'percent']fields = "__all__"exclude = ['active']
      class LevelModelForm(BootStrapForm, forms.ModelForm):xxx = forms.CharField(label='xxx')
      ​class Meta:model = models.Level# fields = "__all__"# exclude = ['active']fields = ['title', 'xxx', 'percent', ]
      class LevelModelForm(BootStrapForm, forms.ModelForm):title = forms.ChoiceField(label='xxx', choices=((1, "xxx"), (2, "xxxxxx")))
      ​class Meta:model = models.Level# fields = "__all__"# exclude = ['active']fields = ['title', 'percent', ]
    • 生成HTML标签 + 插件 + 和 参数的配置

      class LevelModelForm(BootStrapForm, forms.ModelForm):class Meta:model = models.Levelfields = ['title', 'percent', ]widgets = {'name': forms.PasswordInput(render_value=True)}
    • 表单验证

      class LevelModelForm(BootStrapForm, forms.ModelForm):class Meta:model = models.Levelfields = ['title', 'percent', ]
      ​def clean_percent(self):value = self.cleaned_data['percent']return value
      class LevelModelForm(BootStrapForm, forms.ModelForm):title = forms.CharField(validators=[])class Meta:model = models.Levelfields = ['title', 'percent', ]
      ​def clean_percent(self):value = self.cleaned_data['percent']return value
    • 保存(新增、更新)

      form = LevelModelForm(data=request.POST)
      form.save()
      form = LevelModelForm(data=request.POST,install=对象)
      form.save()
      form = LevelModelForm(data=request.POST) # 或有 ,install=对象
      ​
      form.instance.percent = 10
      form.save()
      class LevelModelForm(BootStrapForm, forms.ModelForm):confirm_percent = forms.CharField(label="确认")
      ​class Meta:model = models.Levelfields = ['title', 'percent']​
      def level_add(request):if request.method == "GET":form = LevelModelForm()return render(request, 'form.html', {"form": form})
      ​form = LevelModelForm(data=request.POST)if not form.is_valid():return render(request, 'form.html', {"form": form})
      ​# {'title': '1', 'percent': 2, 'confirm_percent': '3'}print(form.cleaned_data)# form.instance.percent = 10form.save()
      ​return redirect(reverse('level_list'))

4.2 super关键字

根据类的MRO(类的继承关系)顺序,从下到上去找。
​
扩展:Python中的类的继承关系是通过 c3算法 计算出来。

五.总结 

今天说的内容有点多,还是和大家讲了很多知识点,大家要记住这个知识点,代码啥的我就不贴了。最后直接给项目把!

六.补充 

下一期将和大家开始讲登录的校验以及菜单,希望大家的关注加收藏,不懂得看我的名字和签名,一起交流学习

 

 


http://www.ppmy.cn/embedded/173130.html

相关文章

c语言整理

前言: 【b站鹏哥c语言】,记录知识点情况 目录: 关于代码的部分 目录 1、简单函数,比较两个整数的最大值 2、简单if语句题目 内容: 15集的内容整理 15. 【初识C语言】作业讲解_哔哩哔哩_bilibili 数据类型&…

【视频】V4L2、ffmpeg、OpenCV中对YUV的定义

1、常见的YUV格式 1.1 YUV420 每像素16位 IMC1:YYYYYYYY VV-- UU– IMC3:YYYYYYYY UU-- VV– 每像素12位 I420: YYYYYYYY UU VV =>YUV420P YV12: YYYYYYYY VV UU =>YUV420P NV12: YYYYYYYY UV UV =>YUV420SP(最受欢迎格式) NV21: YYYYYYYY VU VU =>YUV420SP…

洛谷 P1068 [NOIP 2009 普及组] 分数线划定 python

关于lambda用于排序的用法 Python 使用 lambda 表达式进行列表排序 | 菜鸟教程 n, m map(int,input().split()) rem [] res [] for i in range(n):rem.append(list(map(int,input().split())))#对rem进行以分数为降序,报名号为升序的排序 rem.sort(key lambda…

大模型token和字符串的关系

一 主要区别 token 是使用分词器拆分后的最小单位,不同的分词方式会导致同样的字符具有不同的token数量。如你好,可以拆分为【你、好】两个token, 【你好】一个token。 同一个文本的 Token 数量可能远少于字符数(英文&#xff09…

Langchian构建代理

文章目录 概要ReAct 代理 ReAct 使用ReAct基本用法提示词模板内存使用迭代使用返回执行每一步情况限制输出行数设置运行超时时间 不使用代理下LLM如何结合工具案例案例2 概要 单靠语言模型无法采取行动 - 它们只输出文本。 LangChain 的一个重要用例是创建 代理。 代理是使用大…

MySQL进阶——数据备份与恢复(超详细!!!)

本文将详细介绍 MySQL 数据备份与恢复的相关知识点。 本文目录 1. 备份类型2. 备份策略设计3. 恢复方法4. 备份工具对比5. 逻辑备份6. 恢复 1. 备份类型 逻辑备份:导出数据库的逻辑结构,以SQL语句的形式呈现,可读性强。适用于小数据量或跨版…

【论文阅读方法】沐神课程:如何读论文

一篇论文的一般结构 titleabstractintroductionmethodexperienceconclusion 三明治论文阅读法 第一遍:海选 titleabstractconclusion——确定要不要读第二遍:精读 对整个文章过一遍,知道每一块在做什么 可以从标题开始读到最后,注…

RabbitMQ (Java)学习笔记

目录 一、概述 ①核心组件 ②工作原理 ③优势 ④应用场景 二、入门 1、docker 安装 MQ 2、Spring AMQP 3、代码实现 pom 依赖 配置RabbitMQ服务端信息 发送消息 接收消息 三、基础 work Queue 案例 消费者消息推送限制(解决消息堆积方案之一&#…