零基础使用Django2.0.1打造在线教育网站(十一):登录页面实现

关于博主

努力与运动兼备~~~有任何问题可以加我好友或者关注微信公众号,欢迎交流,我们一起进步!

                 微信公众号:  啃饼思录
                 QQ: 2810706745(啃饼小白)

写在前面

从本篇笔记开始,我们就正式进入到前端页面的配置了,里面包含的信息很多,主要解决网站首页显示,发送接收验证码,用户注册,登录,密码找回,修改密码等问题。鉴于篇幅可能有点长,所以这里分3篇进行介绍,分别是第十一,十二,十三篇笔记。本篇笔记主要解决网站首页显示和登录页面的配置以及登录方式的自定义这3个问题。

本篇笔记对应于第十一篇代码,对应于github的位置是https://github.com/licheetools/eduline

网站首页显示和登录页面的配置

放置前端网站首页index.html

正如大家平时所看到的那样,一般网站首页都是直接在根目录下显示的,所以我们就要在我们的初始前端资料里面,把我们的index.html文件放在templates目录里面,就是这个样子:

新建静态文件夹static

在主项目树里面新建静态文件夹static,再在里面新建5个文件夹,用于放置css,img,images,js,media等文件。就是这样:

前面说过Django的web开发是采用MTV模式的,现在如果我们想在浏览器中显示前端页面,我们只需要配置一下url就可以了。

前端静态页面的URL的配置

打开我们的eduline/urls.py文件,修改为如下代码:

from django.urls import path
from django.views.generic import TemplateView
import xadmin


urlpatterns = [
    path('xadmin/', xadmin.site.urls),
    # 用''指代根目录,TemplateView.as_view可以将template转换为view
    path('', TemplateView.as_view(template_name='index.html'), name='index'),
]

接下来我们运行一下我们的项目:runserver,直接在浏览器地址栏中输入:

http://127.0.0.1:8000/

或者

http://127.0.0.1

回车一下,出现:

我们的index页面已经成功加载出来了,但是很丑,因为样式还没有加载出来,我们需要配置一下路径。

配置静态static文件的路径

打开我们的eduline/settings.py文件,拉到最底下,添加修改为如下:

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),  
# 说明静态文件放在哪个目录,记住这里只能用列表或者元组,单一一个元组需要用,结尾
]

静态文件路径修改了,所以我们需要在前端页面代码里面对其引用路径都作修改:

将所有的../,全部替换为/static/,你可以使用ctrl+f,先查找出所有再替换也可以的:

变成了这个样子:

接着,把我们前端资料里的文件都放在指定的文件夹里面(资料里都有文件夹名,而且都是和你刚才创建的名字一样)

偷懒的话可以直接复制粘贴相关文件。

现在,我们刷新一下我们的页面(如果你停止了项目的运行就运行一下),出现:

说明我们的前端网站页面已经成功显示了。(如果出现页面残缺问题,可以使用本篇笔记上传的旧版前端资料。)

登录页面的配置

放置前端登录页面login.html

在前端资料里面把我们的login.html文件放在templates目录里面,就是这个样子:

替换路径

同样将所有的../,全部替换为/static/,你可以使用ctrl+f,先查找出所有再替换也可以的,这里就不细说了。

登录页面的URL的配置

打开我们的eduline/urls.py文件,添加如下代码:

# 登录url
path('login/', TemplateView.as_view(template_name="login.html"), name="login"

取消注释并修改登录路径

打开我们的index.html页面,找到第27,28行,取消注释(删除注释符号),再将里面的href="login.html"修改为:href="/login/",再找到第30行代码,将一对<div class="personal"> </div>给收起来,并注释掉,因为我们目前还用不到它。就是下面的一段代码:

	<!--	<div class="personal">
                            <dl class="user fr">
                                <dd>bobby<img class="down fr" src="/static/images/top_down.png"/></dd>
                                <dt><img width="20" height="20" src="/static/media/image/2016/12/default_big_14.png"/></dt>
                            </dl>
                            <div class="userdetail">
                            	<dl>
	                                <dt><img width="80" height="80" src="/static/media/image/2016/12/default_big_14.png"/></dt>
	                                <dd>
	                                    <h2>django</h2>
	                                    <p>bobby</p>
	                                </dd>
                                </dl>
                                <div class="btn">
	                                <a class="personcenter fl" href="usercenter-info.html">进入个人中心</a>
	                                <a class="fr" href="/logout/">退出</a>
                                </div>
                            </div>
                        </div>
   -->

现在,我们刷新一下我们的页面(如果你停止了项目的运行就运行一下),出现:

然后点击登录按钮,跳转到如下地址:http://127.0.0.1:8000/login/,页面成了这个样子:

恭喜你,我们登录页面也已经正常显示出来了,下面是如何实现登录的交互功能。

登录页面的交互实现

Django的MTV模式你还差一个V,也就是view你还没用到过,这里就到了它大显身手的时候了。尽管前面我们已经把网站首页和登录页面在浏览器中显示了,但是那些信息都是固定的,也就是说当初前端人员在设计网页的时候就确定了,我们现在所要做的就是更改它们的信息,使满足自己的信息得到显示。

接下来我们就通过编写视图函数,来实现这个,不过前提是需要挖坑与填坑操作,这里先不介绍,后面会具体说明。

视图函数View的创建

我们打开,apps/users/views.py文件,在里面添加如下代码:

# 当我们配置的url被这个view处理时,将会自动传入request对象.
def user_login(request):
    # 前端向后端发送的请求方式有两种: get和post

    # 登录提交表单时为post
    if request.method == "POST":
        pass
    # 获取登录页面时为get
    elif request.method == "GET":
        # render的作用是渲染html并返回给用户
        # render三要素: request ,模板名称 ,一个字典用于传给前端并在页面显示
        return render(request, "login.html", {})

然后打开eduline/urls.py文件,将login的登录路径修改为如下:

from users.views import login

 # 登录url
    # path('login/', TemplateView.as_view(template_name="login.html"), name="login")
    path('login/', login, name="login")

现在我们准备测试一下,我们获取登录页面时的method是不是为get,在两行返回语句的位置打上断点:

然后开启debug模式,待网站首页显示出来以后点击登录按钮,可以看到蓝色行跳到render那一行了,并发现Method就是GET:

页面表单的提交

在登录页面,我们发现它其实是一个表单:

我们打开login.html文件,找到第70行代码:

这就是我们刚才的登录时的表单提交页面,把第70行的action指向修改一下:action="login.html"变成:action="/login/",还有这里面input中的name值都会随着表单的提交被传递到后台,并以键值对的形式进行存储。

我们现在再来测试一下,看看获取登录提交表单时的method是不是为post,只保留第一行位置上的断点:

然后开启debug模式,待网站首页显示出来以后点击登录按钮,并在表单中输入之前的信息,点击提交,出现了403禁止访问错误:

这其实是Django自带的防止csrf攻击的一个安全机制,目前你不用管这个机制的作用原理是什么(后面会讲到),只需要记住所有html页面内包含<form>表单的地方,都必须在<form>标签内加上{% csrf_token %}才能被验证通过,并传值到后台。

不知道你注意到上方有个input:

 <input type='hidden' name='csrfmiddlewaretoken' value='5I2SlleZJOMUX9QbwYLUIAOshdrdpRcy' />

它的意思就是我们刚才加入的{% csrf_token %}不会在页面中显示。

我们重新开启Debug模式,待网站首页显示出来以后点击登录按钮,并在表单中输入之前的信息,点击提交,页面跳到Pycharm中的pass位置:

并发现Method就是POST,而且POST对象是一个QueryDict!看下面:

从上图可以看到request中的POST其实是一个QueryDict对象,所以我们可以把它当成一个字典(其实它就是一个字典,你看到没有都是以键值对的形式进行返回的),用来获取前端返回的数据:

    if request.method == "POST":
        # username,password为前端页面name的返回值,取到用户名和密码我们就开始进行登录验证;取不到时为空。
        user_name = request.POST.get('username', '')
        pass_word = request.POST.get('password', '')

用户登录验证

目前,我们采用Django自带的auth方法来进行用户登录验证,后面会介绍另一种简单的验证方式。在users/views.py文件添加如下代码:

from django.contrib.auth import authenticate, login

# 当我们配置的url被这个view处理时,将会自动传入request对象.
def login(request):
    # 前端向后端发送的请求方式有两种: get和post

    # 登录提交表单时为post
    if request.method == "POST":
        # username,password为前端页面name的返回值,取到用户名和密码我们就开始进行登录验证;取不到时为空。
        user_name = request.POST.get('username', '')
        pass_word = request.POST.get('password', '')
        # 取值成功返回user对象,失败返回null
        user = authenticate(username=user_name, password=pass_word)
        if user is not None:
            # login 有两个参数:request和user。我们在请求的时候,request实际上是写进了一部分信息,
            # 然后在render的时候,这些信息也被返回前端页面从而完成用户登录。
            login(request, user)
            # 页面跳转至网站首页 user request也会被带回到首页,显示登录状态
            return render(request, 'index.html')
        else:
            # 说明里面的值是None,再次跳转回主页面并报错
            return render(request, "login.html", {})
    # 获取登录页面时为get
    elif request.method == "GET":
        # render的作用是渲染html并返回给用户
        # render三要素: request ,模板名称 ,一个字典用于传给前端并在页面显示
        return render(request, "login.html", {})

注意: authenticate的调用只需要传入用户名和密码即可,如果成功则会返回user对象,失败就返回null

html页面登录验证配置

我们采用下面

{% if request.user.is_authenticated %} 

{% else %}   

 {% endif %}

的方式来进行判断:

{% if request.user.is_authenticated %}   
                <div class="top">
				<div class="wp">
					<div class="fl"><p>服务电话:<b>33333333</b></p></div>
                    <!--登录后跳转-->

						<div class="personal">
                            <dl class="user fr">
                                <dd>admin@admin.com<img class="down fr" src="/static/images/top_down.png"/></dd>
                                <dt><img width="20" height="20" src="/static/media/image/2016/12/default_big_14.png"/></dt>
                            </dl>
                            <div class="userdetail">
                            	<dl>
	                                <dt><img width="80" height="80" src="/static/media/image/2016/12/default_big_14.png"/></dt>
	                                <dd>
	                                    <h2>管理员</h2>
	                                    <p>admin@admin.com</p>
	                                </dd>
                                </dl>
                                <div class="btn">
	                                <a class="personcenter fl" href="usercenter-info.html">进入个人中心</a>
	                                <a class="fr" href="/logout/">退出</a>
                                </div>
                            </div>
                        </div>

				</div>
			</div>    <!--如果用户登录成功,显示个人中心-->
            {% else %}             
                <div class="top">
				<div class="wp">
					<div class="fl"><p>服务电话:<b>33333333</b></p></div>
                        <a style="color:white" class="fr registerbtn" href="register.html">注册</a>
                        <a style="color:white" class="fr loginbtn" href="/login/">登录</a>

                </div>
            </div>    <!--如果用户登录失败,显示用户登录按钮-->
            {% endif %}
就是这个样子:

我们现在先运行一下我们的项目,然后在后台注销我们刚才的登录状态(记住目前注销用户只能在xadmin后台,以后配置好可以在网站首页注销)

我们打开users/views.py文件,在这行代码处打上一个断点:user = authenticate(username=user_name, password=pass_word),就是这个样子:

然后开启debug模式,待网站首页显示出来以后点击登录按钮,并在表单中输入之前的信息,点击提交,页面跳到Pycharm中的user=authenticate这个位置:

我们成功的获取到了前端页面提交的信息,但不一定是可以登录(之前注册过)的用户,所以我们需要验证:

成功了,NewBee用户登录成功了!

如果你继续往下执行的话,会报出下面的错误:

login() takes exactly 1 argument (but 2 given)

这是因为我们在处理登录时调用了我们自定义名为login的函数:

而不是调用了Django提供的login函数:

所以就会出错。因此我们一定不能把自定义的函数名和Django自带的函数名取同一个名字,那样会造成系统错误。

所将自定义的函数命名为user_login,就不会出问题了!

还有eduline/urls.py文件里面对应的部分也要修改:

from users.views import user_login

path('login/', user_login, name="login")

重新运行一下我们的项目,你会发现个人中心出现了:

采用邮箱登录页面

打开eduline/settings.py文件,在第34行添加如下代码:

AUTHENTICATION_BACKENDS = (
    'users.views.CustomBackend',
)

然后打开users/views.py文件,在后面添加如下代码:

from django.contrib.auth.backends import ModelBackend
from .models import UserProfile
# Q是并集运算
from django.db.models import Q

# 实现用户名邮箱均可登录的函数,必须继承ModelBackend类,因为它有方法authenticate
class CustomBackend(ModelBackend):
    def authenticate(self, username=None, password=None, **kwargs):
        try:
 # 我们不希望用户存在两个,也就是说通过某个用户名和某个邮箱登录的都是指向同一用户,所以采用Q来进行并集查询
            user = UserProfile.objects.get(Q(username=username)|Q(email=username))

            # 记住不能使用password==password,因为密码都被django的后台给加密了

            # UserProfile继承的AbstractUser中有check_password这个函数
            if user.check_password(password):
                return user
        except Exception as e:
            return None

现在我们在xadmin的后台中,注销一下,再来测试一下,看是不是可以用邮箱登录了。

我们之前的用户名和账号登录,现在我们尝试使用邮箱和密码来登录,在try和user所在的两行打上断点开启Debug模式:

开启debug模式,待网站首页显示出来以后点击登录按钮,并在表单中输入之前的信息,点击提交,页面跳到Pycharm中来:

可以看到我们已经成功登录了!接下来做一下错误信息的提示!

用户错误信息提示

打开users/views.py文件,修改第28行代码为如下:

    return render(request, "login.html", {'msg': '用户名或者密码错误!'})
也就是这样:

但是错误信息如何在前端页面显示呢?我们需要配置一下,打开login.html文件,找到第80行代码:

<div class="error btns login-form-tips" id="jsLoginTips"></div>

这个字段就是用来提示错误信息的,我们修改一下:

<div class="error btns login-form-tips" id="jsLoginTips">{{ msg }}</div>

我们来测试一下,不过先在xamin里注销一下,然后填入错的信息再提交,就出现:

恭喜你,测试成功了!

至此,我们本篇关于网站首页显示和登录页面的配置以及登录方式的自定义这3个问题的介绍,就到此结束了,感谢你的赏阅。

本篇笔记对应于第十一篇代码,对应于github的位置是https://github.com/licheetools/eduline

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏pangguoming

使用sshfs挂载远程服务器目录

服务器日志查看,是开发人员和服务器运维人员在工作中经常会遇到的一件事情,只有一台服务器时,比较好办,直接登录服务器使用tail -f file-path 命令就...

22640
来自专栏前端vue

Node中间件multer文件上传实践

单文件上传,接收一个以fieldname命名的文件,文件信息保存在req.file

12220
来自专栏杂烩

Mongodb linux下安装 原

#对mongo实例来说,每个host允许链接的最大链接数,这些链接空闲时会放入池中,如果链接被耗尽,任何请求链接的操作会被阻塞等待链接可用,推荐配置10

24540
来自专栏浪淘沙

Linux学习

一、基础指令     1.ls指令         ../    上级目录         ./    当前目录         ls -al     ...

72040
来自专栏浪淘沙

Shell学习总结

一、基础指令     1.ls指令         ../    上级目录         ./    当前目录         ls -al     ...

18330
来自专栏令仔很忙

令仔学Redis(一)----浅析Redis存储数据时格式的设计

之前接触的一个业务,数据量的话现在在数据库中存了有将近400W的数据,在搜索的时候得到的这些数据会放入达到异步队列中,然后单独开一个线程来进行双写,写缓存,然...

14410
来自专栏pangguoming

linux如何修改文件或目录的权限(chmod)

chmod命令是linux上用于改变权限的命令,-R 是递归遍历子目录,因为你要操作的文件使用的*通配符。777,第一个7代表文件所属者的权限,第二个7代表文件...

394100
来自专栏咸鱼不闲

常用的dos命令

前言: 95、98、2000、2003、XP、Vista、Windows7、Window8、Window10是图形界面,在这之前是dos界面,现在仍然保持着这个...

13930
来自专栏蓝天

通用的进程监控重拉起bash脚本process_monitor.sh

9510
来自专栏书山有路勤为径

linux操作系统

<1>查看文件信息:ls ls是英文单词list的简写,其功能为列出目录的内容,是用户最常用的命令之一,它类似于DOS下的dir命令 参数 含义 -a ...

36220

扫码关注云+社区

领取腾讯云代金券