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.新建导航栏的序列化器
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> > >
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组件的登录按钮设置一个跳转连接
4.将导航栏Vheader组件中的登录状态token改为false
将token值改为false,让首页是未登录状态,这样才能显示登录注册的按钮
<script> { token:falsepython 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
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表中。我们达到了目的。
@H_403_0@ 3.DjangoRestFramework JWT1.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/添加用户名和密码字段 post提交后可得token值,如图所示
4.前端通过axios请求获取后端传过来的token
后端返回给前端一个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值
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的值 就可以做if判断了
6.扩展默认的返回值
所以需要扩展一下
通过修改该视图的返回值可以完成我们的需求
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方法来返回jwt 认证成功返回了三个字段 token id username 响应给前端
前端也应该接収这几个字段
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的使用方法
@H_403_0@ 4.多条件登录sessionStorage.变量名 = 变量值 保存数据 sessionStorage.setItem("变量名","变量值") 保存数据 sessionStorage.变量名 读取数据 sessionStorage.getItem("变量名") 读取数据 sessionStorage.removeItem("变量名") 清除单个数据 sessionStorage.clear() 清除所有sessionStorage保存的数据 localStorage.变量名 = 变量值 保存数据 localStorage.setItem("变量名",1)"> 保存数据 localStorage.变量名 读取数据 localStorage.getItem("变量名") 读取数据 localStorage.removeItem("变量名") 清除单个数据 localStorage.clear() 清除所有sessionStorage保存的数据
我们可以通过修改Django认证系统的认证后端(主要是authenticate方法)来支持登录账号既可以是用户名也可以是手机号。
官方说:修改Django认证系统的认证后端需要继承django.contrib.auth.backends.ModelBackend,并重写authenticate方法。
authenticate(self,request,username=None,password=None,**kwargs)
方法的参数说明:
request 本次认证的请求对象
username 本次认证提供的用户账号
password 本次认证提供的密码
我们想要让用户既可以以用户名登录,也可以以手机号登录,那么对于authenticate方法而言,username参数即表示用户名或者手机号。
重写authenticate方法的思路:
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用户名或者手机号的一个多条件登录。 @H_403_0@ 5.登录状态的判断和退出登录<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(); }猜你在找的Python相关文章