Python入门自学进阶-Web框架——30、DjangoAdmin项目应用-自定义用户认证续

news2024/11/23 10:33:16

一、前面实现的是DjangoAdmin实现的自定义用户认证管理,现在自己来实现管理功能,即在mytestapp中增加用户认证管理功能。

在UserProfile的model中,对password字段增加help_text属性:

password = models.CharField(_('password'), max_length=128,help_text=mark_safe('<a href="password/">重置密码</a>.'))

然后在用户修改页面进行显示:    {{ f }}{{ f.help_text }}<span>{{ f.errors }}</span>

然后点击这个重置密码链接,跳转到一个密码修改页面。

在urls中增加对应的路由项:

path('<str:app_name>/<str:table_name>/<int:id_num>/change/password/',views.passwd_reset,name='passwd_reset'),

编写视图函数passwd_reset:

def passwd_reset(req,app_name,table_name,id_num):
    admin_class = mytestapp_admin.enable_admins[app_name][table_name]
    model_form_class = myutils.create_model_form(req, admin_class)
    obj = admin_class.model.objects.get(id=id_num)
    errors ={}
    if req.method == "POST":
        _password = req.POST.get("password")
        _password2 = req.POST.get("password2")
        if _password == _password2:
            obj.set_password(_password)   # 借助模型中的函数
            obj.save()
            return redirect(req.path.rstrip("password/"))
        else:  # 两次密码输入不相同,报错
            errors['invalid_password'] = "two password not same"
    return render(req,'mytestapp/passwd_reset.html',{'user_obj':obj,'errors':errors})

 前端页面passwd_reset.html:

{% extends 'base.html' %}
{% load tags %}
{% block mybody %}
    <body>
        <nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow">
            <a class="navbar-brand col-md-3 col-lg-2 mr-0 px-3" href="#">我的客户管理系统</a>
            <button class="navbar-toggler position-absolute d-md-none collapsed" type="button" data-toggle="collapse" data-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <ul class="navbar-nav px-3">
                <li class="nav-item text-nowrap">
                    <a class="nav-link" href="#">{{ request.user.userprofile.name }}</a>
                </li>
            </ul>
        </nav>
        <div class="container-fluid" style="margin-top: 20px;margin-left: 50px;">
            <div class="d-flex p-2 bd-highlight">修改用户【{{ user_obj }}】密码</div>
            <div class="d-inline-flex p-2 bd-highlight">
                <form method="post">{% csrf_token %}
                      <div class="form-group">
                        <label for="exampleInputEmail1">新密码</label>
                        <input type="password" class="form-control" name="password">
                      </div>
                      <div class="form-group">
                        <label for="exampleInputPassword1">重复密码</label>
                        <input type="password" class="form-control" name="password2">
                      </div>
                    <div>
                        <ul>
                            {% for k,v in errors.items %}
                            <li>{{ k }}:{{ v }}</li>
                            {% endfor %}
                        </ul>
                    </div>
                      <button type="submit" class="btn btn-primary">Submit</button>
                </form>
            </div>
        </div>
    </body>
{% endblock %}

二、在ModelForm中排除部分字段:

在modelform形成过程中,在Meta中使用exclude进行排除。

class Meta:
    model = admin_class.model
    fields = "__all__"
    exclude = ('qq',)

这样配置后,在前端就不会形成qq这个字段了。使用exclude排除,主要用在增加新记录时,如果某些字段值是数据库插入时自动生成的,如创建日期等,不需要在前端显示添加,或修改时,有些字段设置为readonly,在前端使用disabled进行了输入禁止,但是在提交时,这个字段不提交,就形成null值,与原值不相等导致校验失败,这时可以直接使用exclude排除这些字段,不显示就可以了,相当于update语句不修改这些字段。

做成配置的,在AdminClass中增加exclude_fields=['qq',]

在生成ModelForm模板中,

class Meta:
    model = admin_class.model
    fields = "__all__"
    if admin_class.exclude_fields:
        exclude = admin_class.exclude_fields

三、在显示记录列表中,是按照AdminClass中的list_display中的字段显示的,这些字段都是在数据库表中存在的,如果我们要添加一个数据库表中没有的字段,如何实现?如增加一个enrollment字段,内容显示报名,并是一个链接,点击后跳转到其他页面。

class CustomerAdmin(BaseAdmin):
    list_display = ['qq','name','phone','source','consultant','referral_from','consult_course','tags','status','enroll']
    list_per_page = 4
    list_filter = ['qq','source','status','consult_course','tags']
    list_search = ['qq','name']
    filter_horizontal = ['tags']
    readonly_fields = ['qq','consultant','tags']
    actions = ['delete_action',]

    def enroll(self):
        return "what"   # enroll字段显示的值
....

添加如上配置后,显示客户表时,会报错:

使用try捕获错误进行处理:

@register.simple_tag
def build_table_row(obj,admin_class,url_path):
    row_ele = ""
    for row_data in obj:
        row_ele = row_ele +'<tr><td colspan="6"><input  my_id="obj_checkbox" type="checkbox" value="%s"</td>'%(row_data.id)
        for index_ele,column in enumerate(admin_class.list_display):
            try:
                field_obj = row_data._meta.get_field(column)
                if field_obj.choices:
                    column_data = getattr(row_data,"get_%s_display"%column)()
                else:
                    column_data = getattr(row_data,column)
                field_obj1 = getattr(row_data,column)
                if hasattr(field_obj1,'values'):
                    s = ""
                    dic1 = field_obj1.values()
                    for i in range(dic1.count()):
                        for v in dic1[i].values():
                            s = s + str(v) + ';'
                        column_data = s
                if index_ele == 0:   # 若果是第一列,则加上a标签,可以跳转到修改页
                    row_ele += '<td colspan="6"><a href="%s%s/change/">%s</a></td>'%(url_path,row_data.id,column_data)
                else:
                    row_ele += "<td colspan='6'>%s</td>"%column_data
            except FieldDoesNotExist as e:
                if hasattr(admin_class,column):
                    column_func = getattr(admin_class,column)
                    admin_class.instance = obj
                    # 将obj传递给admin_class的instance,这样就能取到对应行的对象的id,这里obj是QuerySet对象

                    column_data = column_func()
                    row_ele += "<td colspan='6'>%s</td>" % column_data
        row_ele = row_ele + "</tr>"
    print(row_ele)
    return mark_safe(row_ele)

在admin_class中配置:

    def enroll(self):

        return "<a href='%s/enrollment/'>报名</a>"%self.instance[0].id
        # 因为instance是QuerySet对象,对于每一行,只有一个对象,取[0],这样,形成的连接就是id/enrollment/,在路由项中增加对应的路由,跳转到对应view函数处理

点击报名:

 

增加对应的路由项和视图及前端模板,完成报名的功能。 

 四、自定义用户登录验证

前面使用的是DjangoAdmin的登录界面:

 登陆后进入的是各种表的管理界面,现在要自定义登录界面,登陆后进入业务界面。

自己做一个登录界面:

 

{% extends 'base.html' %}
{% block mybody %}
    <div class="container" >
        <form class="form-signin col-sm-3">

          <h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
          <label for="inputEmail" class="sr-only">Email address</label>
          <input name="email" type="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus>
          <label for="inputPassword" class="sr-only">Password</label>
          <input name="password" type="password" id="inputPassword" class="form-control" placeholder="Password" required>
          <div class="checkbox mb-3">
            <label>
              <input type="checkbox" value="remember-me"> Remember me
            </label>
          </div>
          <button class="btn btn-lg btn-primary btn-block" type="submit">Login</button>

        </form>
    </div>
{% endblock %}

增加路由项:path('account/login/',views.acc_login),

编写视图函数acc_login:基本框架:

def acc_login(req):

    return render(req,'login.html')

此时,访问:http://127.0.0.1:8000/account/login/就可以访问到上面的自定义登录界面

修改完善:

前端

{% extends 'base.html' %}
{% block mybody %}
    <div class="container" >
        <form class="form-signin col-sm-3" method="post">{% csrf_token %}

          <h1 class="h3 mb-3 font-weight-normal">PlswCRM</h1>
          <label for="inputEmail" class="sr-only">Email address</label>
          <input name="email" type="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus>
          <label for="inputPassword" class="sr-only">Password</label>
          <input name="password" type="password" id="inputPassword" class="form-control" placeholder="Password" required>
          {% if errors %}
            <span style="color: red">{{ errors.error }}</span>
          {% endif %}
          <div class="checkbox mb-3">
            <label>
              <input type="checkbox" value="remember-me"> Remember me
            </label>
          </div>
          <button class="btn btn-lg btn-primary btn-block" type="submit">Login</button>

        </form>
    </div>
{% endblock %}

后端视图函数:

from django.shortcuts import render,redirect
from django.contrib.auth import authenticate,login
# 这里的authenticate和login是借助于django的认证和登录功能

def acc_login(req):

    errors={}
    if req.method == "POST":
        _email = req.POST.get('email')
        _password = req.POST.get('password')
        user = authenticate(username=_email,password=_password)
        print(user)
        # authenticate接受用户名和密码,如果验证通过,则user为用户对象,否则为空
        if user:
            # 如果用户存在,即验证通过,需要将用户写入session中做保存,再次访问网站其他页面时使用
            # 这个写session的动作,可以使用login()来实现
            login(req,user)  # 利用Django的login,实现用户写入session,即保存登录
            # 验证、登录成功,转到首页
            return redirect("/plcrm/")
        else:
            errors['error'] = "username or password is wrong"
    return render(req,'login.html',{"errors":errors,})

对需要登录验证的视图函数增加验证:

如前面的mytestapp的各个视图函数,访问前需要进行实现登录验证,这时还是借助Django的装饰器来实现:

from django.contrib.auth.decorators import login_required

# Create your views here.
@login_required   # 加上这个装饰器,就会在访问index函数时进行验证,如果没有登陆,则跳转到登录页面
def index(req):
    print(mytestapp_admin.enable_admins['plcrm']['customer'].model)
    return render(req,"mytestapp/index.html",{'table_list':mytestapp_admin.enable_admins})

在没有登陆的状态下访问mytestapp:

自动跳转到accounts/login/路径,这个是Django默认的登录路径,而我们自定义的是account/login/,这个选项在settings.py中进行配置:

 LOGIN_URL = '/account/login/'

这时,就会自动跳转到自定义的/account/login/这个登录界面。

将其他的视图函数都加上@login_required,这样就实现了所有页面都需要登录认证的功能。

五、登录退出

在用户名称上增加下列框,

实现登录退出:<a class="dropdown-item" href="{% url 'acc_logout' %}">login out</a>

在路由项中增加:path('account/logout/',views.acc_logout,name='acc_logout'),

视图函数:

def acc_logout(req):
    logout(req)
    return redirect('/account/login/')

logout也是借助如django的功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/168534.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux 环境安装 jdk 或 openjdk

一、linux 环境安装JDK的tar.gz包&#xff0c;通用命令&#xff1a; 1、查看已安装的JDK版本rpm -qa | grep jdk2、删除不需要的JDK版本&#xff1a;rpm -e --nodeps java-1.8.0-openjdk3、解压新JDK至/usr/lib/jvm目录下tar -zxvf openjdk-1044_linux-x64_bin_ri.tar.gz -C /…

AOSP刷机笔记

下载官方镜像&#xff0c;下载对应AOSP&#xff0c;编译出的*.img替换到官方镜像对应的文件, 刷入 把证书放到aosp源码的system/ca-certificates/files文件夹里&#xff0c;lunch aosp_sailfish-user编译可以实现无root抓包 mkdir ~/bin PATH~/bin:$PATH curl -sSL https://ger…

什么是集中采购 集中采购管理软件介绍

什么是集中采购&#xff1f; 集中采购是指企业总部某特定部门对企业所有采购进行管控&#xff0c;他们负责获取整个组织需要的物资。这个部门负责与供应商联络、供应商寻源、合同管理、风险分析&#xff0c;以及从供应商那里获得所需物资的每项工作。 企业采用集中采购管理模…

什么叫joinquant量化策略?

joinquant量化主要是在数据挖掘上有特别的意义&#xff0c;不像平时我们在执行各个量化选股策略时&#xff0c;还要一个一个去输入去查询。而joinquant量化策略在开发方面就简便了很多&#xff0c;joinquant量化策略是运用到个股量化交易中能够针对各个股票数据都能快速挖掘出来…

mongodb安装和部署,并整合到Springboot

mongodb安装和部署,并整合到Springboot 1.linux上docker安装mongodb docker pull mongo:4.4.18使用docker命令启动&#xff1a; docker run -p 27017:27017 --name mongo \ -v /mydata/mongo/db:/data/db \ -d mongo:4.4.18运行容器 docker exec -it mongo /bin/bash# 进入…

C进阶_字符串查找库函数

strstr 查找strstr的文档&#xff0c;可知它的原型为&#xff1a; char *strstr( const char *string, const char *strCharSet ); 它的返回值&#xff0c;根据文档是这样的&#xff1a; Return Value Each of these functions returns a pointer to the first occurrence …

使用 YonBuilder 进行报表分析 - 扩展篇

使用 YonBuilder 进行报表分析 - 扩展篇 在上一篇文章中&#xff0c;我们讲解了如何构建简单的报表以及交叉表的基础配置。本篇文章通过对主子表、树型表以及数据穿透的创建来对 YonBuilder 的报表配置进行扩展介绍。 创建报表 首先&#xff0c;要先创建一个员工信息实体&…

CSS选择器整理学习(中)

书接上回&#xff0c;在前端项目开发中&#xff0c;有时候需要对特殊的元素进行特殊的处理&#xff0c;但有时候元素的位置不确定、层级不确定、数量不确定等问题&#xff0c;导致我们没办法进行元素的选择&#xff0c;这个时候我们就需要用到元素选择器了。 一、CSS选择器 1…

加油站视频监控智能分析盒基于yolov5

加油站视频监控智能分析盒基于yolov5人工智能视觉技术&#xff0c;对现场画面中明火和烟雾以及人员抽烟、打电话等违规行为进行识别。除此之外&#xff0c;还可以对现场画面中卸油时灭火器未按要求正确摆放以及静电释放时间不足和人员离岗等不规范行为进行自动预警。YOLOv5在YO…

【云原生】k8s图形化管理攻击之rancher

内容预知 前言 1. Rancher的相关知识 1.1 Rancher的简介 1.2 Rancher与k8s的关系及区别 1.3 Rancher具有的优势 2. Rancher的安装部署 2.1 实验环境与部署图分配 2.2 具体的部署操作 &#xff08;1&#xff09;在 rancher 节点下载 rancher 镜像 &#xff08;2&#xff…

程序员同事每天准点下班,原来是用了这6个开发工具

工欲善其事必先利其器&#xff0c;要想更加高效的做事情&#xff0c;就得先将工具变得锋利。那么对于程序员来说同样也是如此&#xff0c;如果要想每天早点下班&#xff0c;就必须借助于一些开发工具来提高自己的工作效率&#xff0c;今天就给大家总结一些工作中常用到的工具。…

【算法题解】11. 判断链表是否有环,并返回入环节点

文章目录题目解法一&#xff1a;循环标记Java代码实现Go 代码实现复杂度分析解法二&#xff1a;快慢指针Java 代码实现Go 代码实现复杂度分析这是一道 中等难度 的题&#xff0c;是 判断链表是否有环 的扩展&#xff0c;在有环的情况下返回入环节点&#xff0c; 依然是两种解法…

Disney 流媒体广告 Flink 的应用实践

摘要&#xff1a;本文整理自 Disney 广告智能执行总监郝又超、Disney 广告智能实时计算负责人李丁哲&#xff0c;在 FFA 主会场的分享。本篇内容主要分为四个部分&#xff1a;Disney 流媒体广告与实时应用业务场景实现实时平台构建未来展望Tips&#xff1a;点击「阅读原文」查看…

kafka.2 集群搭建

文章目录1.启动kakfa自带的zk2.启动kafka集群3.查看zookeeper的kafka节点信息启停kafka集群脚本创建主题增加分区模拟生产消费模拟消费组消费主题&#xff0c;查看offset1.启动kakfa自带的zk 参考&#xff1a;https://blog.csdn.net/justlpf/article/details/127261664?utm_m…

通俗易懂的java设计模式(7)-原型模式

1.什么是原型模式&#xff1f; 原型模式提供了一种创建对象的模式&#xff0c;它是指用原型实例创建对象的种类&#xff0c;并且通过拷贝这些原型&#xff0c;创建新的对象。用一个很生动形象的例子&#xff1a;孙悟空拔出一根猴毛&#xff0c;变出其他和自己一模一样的小孙悟…

Linux三剑客之Sed

目录 一、认识sed 二、使用sed 命令格式 常用选项options 地址定界 编辑命令command sed用法 常用选项&#xff1a; 地址界定演示 编辑命令command演示 sed高级编辑命令 一、认识sed sed 是一种流编辑器&#xff0c;它一次处理一行内容。处理时&#xff0c;把当前处理的行…

《Linux Shell脚本攻略》学习笔记-第九章

9.1 简介 计算机系统是由一组硬件及控制这些硬件的软件组成的。 Linux既提供了能够检查这些系统当前性能的交互式程序&#xff0c;也提供了用于记录一段时间内系统性能表现的模块。 9.2 监视磁盘使用情况 磁盘空间是一种有限的资源。 du和df命令可以报告磁盘使用情况&#xff0…

消息中间件如何选型 图解 Kafka vs RabbitMQ vs RocketMQ 的差异

综述 Kafka 采用拉取 ( Pull) 方式消费消息&#xff0c;吞吐量相对更高&#xff0c;适合海量数据收集与传递场景&#xff0c;例如日志采集和集中分析缺点 Kafka 单机超过 64 个队列/分区&#xff0c;Load 会发生明显的飙高现象&#xff0c;队列越多&#xff0c;load 越高&#…

linux基本功系列之chage命令实战

文章目录前言一. chage命令的介绍二. 常用案例示范1. 查看用户密码的有效期2. 设置密码的过期时间3. 设置账号的失效时间总结前言 前言&#x1f680;&#x1f680;&#x1f680; 想要学好Linux&#xff0c;命令是基本功&#xff0c;企业中常用的命令大约200多个&#xff0c;不管…

2023牛客寒假算法基础集训营1

题解 | #2023牛客寒假算法基础集训营1#_牛客博客 (nowcoder.net) //本人能力有限&#xff0c;以下只附上本人get到的题&#xff0c;其他参考以上链接或其他 A World Final? World Cup! (I) 链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 …