加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

day77:luffy:导航栏的实现&DjangoRestFramework JWT&多

发布时间:2020-12-20 09:58:10 所属栏目:Python 来源:网络整理
导读:目录 1.导航栏的实现 2.登录前戏:用户表初始化 3.DjangoRestFramework JWT 4.多条件登录 5.登录状态的判断和退出登录 1.导航栏的实现 1.设计导航栏的model模型类 apps/home/models.py class Nav(BaseModel): """ 导航菜单模型 """ POSITION_OPTION = ( ( 1,

目录

1.导航栏的实现

2.登录前戏:用户表初始化

3.DjangoRestFramework JWT

4.多条件登录

5.登录状态的判断和退出登录

1.导航栏的实现

1.设计导航栏的model模型类

apps/home/models.py

class Nav(BaseModel):
    """导航菜单模型"""
    POSITION_OPTION = (
        (1,"顶部导航"),(2,1)">脚部导航导航标题)
    link = models.CharField(max_length=500,1)">导航链接)
    position = models.IntegerField(choices=POSITION_OPTION,default=1,1)">导航位置)
    is_site = models.BooleanField(default=False,1)">是否是站外地址)

     Meta:
        db_table = 'ly_nav'
        verbose_name = 导航菜单
        verbose_name_plural = verbose_name

    # 自定义方法[自定义字段或者自定义工具方法]
    def __str__(self):
        return self.title

2.在Xadmin中注册导航栏模型类

apps/home/adminx.py

 导航菜单
 NavModelAdmin(object):
    list_display=[title",1)">linkis_showis_siteposition]
xadmin.site.register(models.Nav,NavModelAdmin)

执行数据库迁移同步指令

python manage.py makemigrations
python manage.py migrate

3.在Xadmin中添加一些导航栏数据

?4.注册导航栏的URL

from django.urls import path,re_path
from .  views
urlpatterns = [
    ......
    path(nav/header/,views.HeaderNavListAPIView.as_view()),]

5.新建导航栏的视图类

from .models  Nav
from .serializers  NavModelSerializer
 HeaderNavListAPIView(ListAPIView):
    顶部导航菜单视图
    queryset = Nav.objects.filter(is_show=True,is_deleted=False,position=1).order_by(-orders-id)[:constants.HEADER_NAV_LENGTH]
    serializer_class = NavModelSerializer

'''
position=1代表是顶部导航,position=2代表是底部导航
'''

6.新建导航栏的序列化器

 NavModelSerializer(serializers.ModelSerializer):
    导航菜单序列化器"""
     Meta:
        model = Nav
        fields = [id"]

7.调试一下看是否能获取到数据

8.编写导航栏vue组件的代码

1.Vheader组件加载时,通过axios的get请求去请求后端的数据

<script>
    export default {
      name: "Header"return {
         ......
          nav_data_list:[],}
      },methods:{
        ......
        get_nav_data(){
          this.$axios.get(`${this.$settings.Host}/home/nav/header/`,).then((res)=>{
            this.nav_data_list = res.data;
          })
          .catch((error)=>{
            console.log(error);
          })
        }
      },// 注意:一定要写created方法来触发函数
      created() {
        this.get_nav_data();
      }

    }
    
</script>

2.后端数据已经拿到,接下来要在前端展示出来

思路:for循环取出导航栏所有的数据,判断导航栏的标题是站内跳转还是站外跳转

如果是站内跳转就用router-link,如果是站外跳转就用a href

value就是你从后端获取到的数据 value.link value.is_site value.title就可以取到相应的值

 <el-col ="nav" :span="10">
            el-row>
                :span="3" v-for="(value,index) in nav_data_list" :key="index">

                 a :href="value.link" class="active" v-if="value.is_site">{{value.title}}</a>

                  router-link :to v-elserouter-link>

                el-col>

              >

          >

2.登录前戏:用户表初始化

1.Login.vue

template>
    div ="login box">
        img src="../../static/img/Loginbg.3377d0c.jpg" alt=""="login"="login-title"="../../static/img/Logotitle.1ba5466.png"p>帮助有志向的年轻人通过努力学习获得体面的工作和生活!div="login_box"="title">
                    span @click="login_type=0">密码登录span="login_type=1">短信登录="inp"="login_type==0"input v-model = "username" type="text" placeholder="用户名 / 手机号码"="user"= "password"="password" name=""="pwd"="密码"id="geetest1"></="rember">
                        >
                            type="checkbox"="no"="a" v-model="remember"/>
                            >记住密码>忘记密码button ="login_btn" @click="loginHandle">登录buttonp ="go_login" >没有账号 >立即注册 v-show="login_type==1"="手机号码"  type="短信验证码">
          ="get_code">获取验证码="login_btn">
>

script>
export default {
  name: 'Loginreturn {
        login_type: 0""falsethis.$axios.post(`${.$settings.Host}/userslogin`,{
        username:.username,1)">.password,}).then((res)=>{
        console.log(res);
        // console.log(this.remember);
        if (.remember){
          localStorage.token = res.data.token;
          localStorage.username  res.data.username;
          localStorage.id  res.data.id;
          sessionStorage.removeItem(token);
          sessionStorage.removeItem(usernameid);

        }else {
          sessionStorage.token  res.data.token;
          sessionStorage.username  res.data.username;
          sessionStorage.id  res.data.id;
          localStorage.removeItem();
          localStorage.removeItem();
        }
        .$router.push();

      }).catch((error){
        .$alert(用户名password errorerror msg确定style scoped
.box{
    width: 100%;
  height
    position relative
  overflow hidden;
}
.box img
  min-height
.box .login  absolute 500px
    height 400px
    top 0
    left
  margin auto
  right
  bottom
  top -338px
.login .login-title
     width
    text-align center
.login-title img 190px
.login-title p
    font-family PingFangSC-Regular
    font-size 18px
    color #fff
    letter-spacing .29px
    padding-top 10px
    padding-bottom 50px
.login_box
    background
    box-shadow 0 2px 4px 0 rgba(0,.5)
    border-radius 4px
    margin 0 auto 40px
.login_box .title 20px #9b9b9b .32px
    border-bottom 1px solid #e6e6e6
     display flex
        justify-content space-around
        padding 50px 60px 0 60px
        margin-bottom
        cursor pointer
.login_box .title span:nth-of-type(1) #4a4a4a
        border-bottom 2px solid #84cc39

.inp 350px
.inp input
    border
    outline 45px 1px solid #d9d9d9
    text-indent 14px #fff !important
.inp input.user
    margin-bottom 16px
.inp .rember
    justify-content space-between
    align-items
    margin-top
.inp .rember p:first-of-type 12px .19px
    margin-left 22px
    display -ms-flexbox
    -ms-flex-align;
    /*position: relative;*/

.inp .rember p:nth-of-type(2)
    cursor

.inp .rember input 30px

.inp .rember p span inline-block
  font-size
  width 100px;
  position: absolute;left: 20px;*/


#geetest
.login_btn #84cc39 5px .26px
.inp .go_login
.inp .go_login span}
style>

2.在index.js中添加Login组件的路由

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import Login from '@/components/Login'

Vue.use(Router)

export default new Router({
  mode:'history'

3.将导航栏Vheader组件的登录按钮设置一个跳转连接

<!-- 点击登录按钮 跳转到登录的页面:/user/login -->
to="user/login"><="signin">

4.将导航栏Vheader组件中的登录状态token改为false

将token值改为false,让首页是未登录状态,这样才能显示登录注册的按钮

<script> {
          
          token:false
python manage.py startapp users

2.在dev.py配置文件的INSTALL_APPS加上users

3.为user应用配置总路由

  path(users/',include(users.urls")),

6.创建user模型类

在django的auth模块是自带一个用户表的,我们写用户表时可以继承django自带的用户表.

from django.db  models
from django.contrib.auth.models import AbstractUser  AbstractUser是django自带的一个用户表


 User(AbstractUser):
    phone = models.CharField(max_length=16,null=True,blank=True)
    wechat = models.CharField(max_length=16,1)">True)

    ly_user用户表
        verbose_name_plural = verbose_name

7.关于用户表要做的两件事

我们想做的两件事:

  1.使用django自带的Abstractuser表加自己的扩展字段作为项目的用户表【已经完成】

  2.后台登录Xadmin的后台管理系统的那些用户不再使用原来django自带的用户表,而是使用自己创建的用户表

Xadmin使用自己创建的用户表.

需要在setting中配置一下,让django别再使用自带的那个user表,而是使用我们自己编写的user表

dev.py

AUTH_USER_MODEL = users.User'

注意:如果现在执行数据库迁移指令会报错。

上面的操作应该建立在第一次数据库迁移之前。

但是我们之前已经进行过几次数据库迁移了。所以需要做以下几步操作:

 0. 先把现有的数据库导出备份,然后清掉数据库中所有的数据表。

 1. 把开发者创建的所有子应用下面的migrations目录下除了__init__.py以外的所有迁移文件,只要涉及到用户的,一律删除,并将django-migrations表中的数据全部删除。

 2. 把django.contrib.admin.migrations目录下除了__init__.py以外的所有迁移文件,全部删除。

 3. 把django.contrib.auth.migrations目录下除了__init__.py以外的所有迁移文件,全部删除。

 4. 把reversion.migrations目录下除了__init__.py以外的所有迁移文件,全部删除。这个不在django目录里面,在site-packages里面,是xadmin安装的时候带的,它会记录用户信息,也需要删除

 5. 把xadmin.migrations目录下除了__init__.py以外的所有迁移文件,全部删除。

 6. 删除我们当前数据库中的所有表

 7. 接下来,执行数据迁移(makemigrations和migrate),回顾第0步中的数据,将数据导入就可以了,以后如果要修改用户相关数据,不需要重复本次操作,直接数据迁移即可。// 

这些完成之后,创建一个超级用户

python3 manage.py createsuperuser

会发现xadmin超级用户的用户名和密码存到了自己的ly_user表中。我们达到了目的。

3.DjangoRestFramework JWT

1.jwt的安装

pip install djangorestframework-jwt -i https://mirrors.aliyun.com/pypi/simple/

2.jwt的配置

dev.py

REST_FRAMEWORK = {
    DEFAULT_AUTHENTICATION_CLASSES: (
        rest_framework_jwt.authentication.JSONWebTokenAuthenticationrest_framework.authentication.SessionAuthenticationrest_framework.authentication.BasicAuthentication datetime
JWT_AUTH =JWT_EXPIRATION_DELTA': datetime.timedelta(days=1apps/users/urls.py

为jwt设置路由 ,用来前端访问url 获取jwt token值

from rest_framework_jwt.views  obtain_jwt_token
 path

urlpatterns = [
    path(rlogin/

4.前端通过axios请求获取后端传过来的token

用户在登录界面输入用户名和密码,点击登录 往后台发送post请求

后端返回给前端一个token值,前端接收token值并存储起来

1.获取用户在前端输入的用户名和密码

methods:{
    loginHandle(){
      this.$axios.post(`${this.$settings.Host}/users/login/`,{
        username:this.password,

2.为login.vue的登录按钮绑定一个LoginHandle事件

>

这个时候我们访问www.lycity.com/user/login 输入用户名和密码

查看console 可以看到data中已经存放着token值 ==>这个时候前端已经拿到token值

那么接下来的问题是前端如何将token值保存起来呢?

3.引入session storage 和 local storage===>实现前端对token的存储

session storage和local storage的区别

session storage 是临时存储 关闭浏览器就没有了

local storage 是永久存储

5.前端存储token值

登录页面有一个记住密码的选项,我们就可以使用session storage 和 loca storage 来做一些事情

1.将记住密码checkbox设置为v-model

当用户勾选/没有勾选 记住密码 这个选项时,remember的值发生改变

Login.vue

/>
    >

2.我们先让remember的值默认为false

export  {
  name: 'Login' {
         ...
        remember:当用户勾选记住密码 remember的值为true 反之为false

所以根据 remember的值 就可以做if判断了

6.扩展默认的返回值

默认的返回值仅有token值 ,但是我们还需在返回值中增加username和id,方便在客户端页面中显示当前登录用户。

所以需要扩展一下

通过修改该视图的返回值可以完成我们的需求

user/utils.py

def jwt_response_payload_handler(token,user=None,request=None):
    
    自定义jwt认证成功返回数据
     {
        token: token,1)">: user.id,1)">username: user.username
    }

除了扩展一下这个,还要修改一下下面的配置

settings/dev.py

 JWT
JWT_AUTH =JWT_RESPONSE_PAYLOAD_HANDLER': users.utils.jwt_response_payload_handler
  methods:{
    loginHandle(){
      {
        console.log(res);
        if (.remember){
          localStorage.token = res.data.token;
          localStorage.username = res.data.username;
          localStorage.id = res.data.id;
           ...

        }else {
          sessionStorage.token = res.data.token;
          sessionStorage.username = res.data.username;
          sessionStorage.id = res.data.id;
            ...
        }

final

'''
实现思路:
如果用户标选了记住密码 就将token值存储在local storage中
如果用户没有标记 记住密码 就将token值存储在session storage中 
'''

  methods:{
    loginHandle(){
       console.log(this.remember);
         res.data.id;
          sessionStorage.removeItem('token');
          sessionStorage.removeItem('username');
          sessionStorage.removeItem('id');

        } res.data.id;
          localStorage.removeItem('token');
          localStorage.removeItem('username');
          localStorage.removeItem('id');
        }
        this.$router.push('/');

Tip:关于session storage和local storage的使用方法

sessionStorage.变量名 = 变量值    保存数据
sessionStorage.setItem("变量名","变量值")  保存数据
sessionStorage.变量名   读取数据
sessionStorage.getItem("变量名")  读取数据
sessionStorage.removeItem("变量名")  清除单个数据
sessionStorage.clear()   清除所有sessionStorage保存的数据

localStorage.变量名 = 变量值    保存数据
localStorage.setItem("变量名",1)"> 保存数据
localStorage.变量名   读取数据
localStorage.getItem("变量名")  读取数据
localStorage.removeItem("变量名")  清除单个数据
localStorage.clear()   清除所有sessionStorage保存的数据

4.多条件登录

扩展的登录视图,在收到用户名与密码时,也是调用Django的认证系统中提供的authenticate()来检查用户名与密码是否正确。

我们可以通过修改Django认证系统的认证后端(主要是authenticate方法)来支持登录账号既可以是用户名也可以是手机号。

官方说:修改Django认证系统的认证后端需要继承django.contrib.auth.backends.ModelBackend,并重写authenticate方法。

authenticate(self,request,username=None,password=None,**kwargs)方法的参数说明:

  • request 本次认证的请求对象

  • username 本次认证提供的用户账号

  • password 本次认证提供的密码

我们想要让用户既可以以用户名登录,也可以以手机号登录,那么对于authenticate方法而言,username参数即表示用户名或者手机号。

重写authenticate方法的思路:

  1. 根据username参数查找用户User对象,username参数可能是用户名,也可能是手机号

  2. 若查找到User对象,调用User对象的check_password方法检查密码是否正确

users/utils.py

def get_user_by_account(account):
    
    根据帐号获取user对象
    :param account: 账号,可以是用户名,也可以是手机号
    :return: User对象 或者 None
    try:
        
         查询用户名是否存在
        user = models.User.objects.filter(Q(username=account)|Q(mobile=account)).first()
    except models.User.DoesNotExist:
         None 
    :
        return user  存在返回用户名

from django.db.models  Q
from django.contrib.auth.backends  ModelBackend
 UsernameMobileAuthBackend(ModelBackend):
    
    自定义用户名或手机号认证
    """

    def authenticate(self,**kwargs):
        user = get_user_by_account(username)
        if user is not None and user.check_password(password) :
        if user is not None and user.check_password(password) and user.is_authenticated:
            user.is_authenticated是看他有没有权限的,这里可以不加上它
            return user

在配置文件settings/dev.py中告知Django使用我们自定义的认证后端

AUTHENTICATION_BACKENDS = [
    users.utils.UsernameMobileAuthBackend
<script>
export  {
  name: "Header" {
        .....
      token: true 二者只要其中之一有值就是true 代表用户已经登录
      this.token = localStorage.token || sessionStorage.token;
    },logout() {
       用户注销时,无论是临时存储还是永久存储都应该清除掉
      sessionStorage.removeItem('token');
      sessionStorage.removeItem('username');
      sessionStorage.removeItem('id');
      localStorage.removeItem('token');
      localStorage.removeItem('username');
      localStorage.removeItem('id');
      .check_login();
    }
  },created() {
    .get_nav_data();
  }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读