您现在的位置是: 网站首页 >Django >Django2.0.8+xadmin2实现在线学习网站 Django

【Django在线教育平台】04.模板配置,完成用户登录相关页面和逻辑

admin2019年6月4日 13:49 Django | Html | JQuery 1765人已围观

Django2.0.8+xadmin2实现在线学习网站简介 Django2.0.8+xadmin2实现在线学习网站,课程、讲师、机构、用户收藏功能。GitHub地址:https://github.com/xyliurui/OnlineLearningPlatform ;Django版本:2.0.8

# 模板和资源位置 在项目中创建templates目录,用于放置模板文件 在项目中创建static目录,用来存放css, js等静态文件 ## 配置templates目录路径 在项目下新建templates目录用于存放模板文件,在settings.py中添加templates的目录,让它能被搜索到。 修改settings.py配置,添加模板文件的目录 ```python TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates'), ], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] ``` ## 配置static目录路径 用于放置静态文件。修改settings.py配置 ```python STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static') ] ``` # 创建临时的首页index.html 在templates目录下,创建index.html文件 ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> 暂无内容 </body> </html> ``` 然后配置首页url,在项目主url中,使用Django提供的`TemplateView`用于处理静态文件 ```python from django.views.generic import TemplateView urlpatterns = [ path('admin/', admin.site.urls), path('xadmin/', xadmin.site.urls), path('', TemplateView.as_view(template_name='index.html'), name='index'), ] ``` 访问 http://127.0.0.1:8000/ 即可看到首页的内容 # 创建登录 ## 登录login.html 创建登录模板文件 ## url配置跳转登录页面 ```python urlpatterns = [ path('admin/', admin.site.urls), path('xadmin/', xadmin.site.urls), path('', TemplateView.as_view(template_name='index.html'), name='index'), path('login/', TemplateView.as_view(template_name='login.html'), name='login'), ] ``` 访问 http://127.0.0.1:8000/login/ 即可访问登录页面 ## 使用函数实现用户登录user_login(request) 配置url之前我们要书写好对应处理的view Django的view实际就是一个函数,接收request请求对象,处理后返回response对象。 ### 用户登录视图 **users/views.py** ```python from django.shortcuts import render # 当我们配置url被这个view处理时,自动传入request对象 def user_login(request): if request.method == 'POST': pass elif request.method == 'GET': return render(request, 'login.html', {}) ``` ### 用户登录url 在项目的主url中添加 ```python from users.views import user_login urlpatterns = [ path('admin/', admin.site.urls), path('xadmin/', xadmin.site.urls), path('', TemplateView.as_view(template_name='index.html'), name='index'), # path('login/', TemplateView.as_view(template_name='login.html'), name='login'), path('login/', user_login, name='login'), ] ``` 现在访问 http://127.0.0.1:8000/login/ 仍会跳转到同一个页面 ### 用户登录表单 **templates/login.html** 可以看到form表单中有input。点击提交会把值提交到后台。我们需要修改action让它指向我们的后台相应地址。input中的name值会被传递到后台。回组成键值对形式。 ```html <h3 class="no-margins">登录</h3> <p class="m-t-md">登录到学习平台</p> <form method="post" action="/login/"> <input name='username' type="text" class="form-control uname" placeholder="用户名" /> <input name='password' type="password" class="form-control pword m-b" placeholder="密码" /> {% csrf_token %} <a href="">忘记密码了?</a> <button type="submit" class="btn btn-success btn-block">登录</button> </form> ``` ![BLOG_20190604_135101_16](/media/blog/images/2019/06/BLOG_20190604_135101_16.png "博客图集BLOG_20190604_135101_16.png") html页面内必须加上`crsf token` 才能传值到后台。 系统会随机的给前端发一串符号,必须把这串符号带回来,才允许post ### 用户登录post逻辑 ```python from django.shortcuts import render from django.contrib.auth import login, authenticate # 当我们配置url被这个view处理时,自动传入request对象 def user_login(request): if request.method == 'POST': user_name = request.POST.get('username', '') pass_word = request.POST.get('password', '') user = authenticate(username=user_name, password=pass_word) # 认证成功返回user对象,失败返回null if user: login(request, user) return render(request, 'index.html') else: return render(request, 'login.html', {}) elif request.method == 'GET': return render(request, 'login.html', {}) ``` ### 支持邮箱登录 #### 自定义authenticate方法 **users/views/py** ```python from django.contrib.auth.backends import ModelBackend from django.db.models import Q from .models import UserProfile # 自定义登录,可使用邮箱和账号 class CustomBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): try: # 不希望用户存在两个,get只能有一个。两个是get失败的一种原因 Q为使用并集查询 user = UserProfile.objects.get(Q(username=username) | Q(email=username)) # django的后台中密码加密:所以不能password==password # UserProfile继承的AbstractUser中有def check_password(self, raw_password) if user.check_password(password): return user except Exception as e: return None ``` #### 添加登录后台设置 修改settings.py,添加 ```python # 设置邮箱和用户名均可登录 AUTHENTICATION_BACKENDS = ( 'users.views.CustomBackend', ) ``` ### 添加登录错误提示 #### 模板添加错误信息提示 ```html <form method="post" action="/login/"> <input name='username' type="text" class="form-control uname" placeholder="用户名" /> <input name='password' type="password" class="form-control pword m-b" placeholder="密码" /> {% if msg %} <div class="alert alert-danger" style="padding: 5px;"> {{ msg }} </div> {% endif %} {% csrf_token %} <a href="">忘记密码了?</a> <button type="submit" class="btn btn-success btn-block">登录</button> </form> ``` #### 视图添加错误信息返回 ```python def user_login(request): if request.method == 'POST': user_name = request.POST.get('username', '') pass_word = request.POST.get('password', '') user = authenticate(username=user_name, password=pass_word) # 认证成功返回user对象,失败返回null if user: login(request, user) return render(request, 'index.html') else: return render(request, 'login.html', { 'msg': '用户名或密码错误!' }) elif request.method == 'GET': return render(request, 'login.html', {}) ``` ## 基于类的视图实现用户登录LoginView(View) 基础教程中基本上都是基于函数来做的,其实更推荐基于类来做。基于类可以带来不少好处 ### 基于类的登录视图LoginView(View) ```python from django.views.generic import View # 基于类的视图实现登录 class LoginView(View): def get(self, request): return render(request, 'login.html', {}) def post(self, request): user_name = request.POST.get('username', '') pass_word = request.POST.get('password', '') user = authenticate(username=user_name, password=pass_word) # 认证成功返回user对象,失败返回null if user: login(request, user) return render(request, 'index.html') else: return render(request, 'login.html', { 'msg': '用户名或密码错误!' }) ``` ### 基于类的登录url ```python from users.views import user_login, LoginView urlpatterns = [ path('admin/', admin.site.urls), path('xadmin/', xadmin.site.urls), path('', TemplateView.as_view(template_name='index.html'), name='index'), # path('login/', TemplateView.as_view(template_name='login.html'), name='login'), # path('login/', user_login, name='login'), path('login/', LoginView.as_view(), name='login'), # 基于类方法实现登录,这里是调用它的方法 ] ``` ### form字段验证 验证最大长度,是否为空等一系列。 users下新建forms文件。编辑 ```python from django import forms class LoginForm(forms.Form): # 用户名和密码不能为空 username = forms.CharField(required=True) password = forms.CharField(required=True, min_length=5) ``` ### form加入到登录逻辑LoginView(View) 定义好forms之后我们来使用它做验证。 ```python from .forms import LoginForm # 基于类的视图实现登录 class LoginView(View): def get(self, request): return render(request, 'login.html', {}) def post(self, request): login_form = LoginForm(request.POST) if login_form.is_valid(): user_name = request.POST.get('username', '') pass_word = request.POST.get('password', '') user = authenticate(username=user_name, password=pass_word) # 认证成功返回user对象,失败返回null if user: login(request, user) return render(request, 'index.html') else: return render(request, 'login.html', { 'msg': '用户名或密码错误!', 'login_form': login_form, }) else: return render(request, 'login.html', { 'login_form': login_form, }) ``` ### 完善错误提示login.html ```html <h3 class="no-margins">登录</h3> <p class="m-t-md">登录到学习平台</p> <form method="post" action="/login/"> <input name='username' value="{% if login_form.username.value %}{{ login_form.username.value }}{% endif %}" type="text" class="form-control uname" placeholder="用户名" /> {% if login_form.errors.username %} <span id="cname-error" class="help-block m-b-none"> {{ login_form.errors.username.as_text }}</span> {% endif %} <input name='password' type="password" class="form-control pword m-b" placeholder="密码" /> {% if login_form.errors.password %} <span id="cname-error" class="help-block m-b-none"> {{ login_form.errors.password.as_text }}</span> {% endif %} {% if msg %} <div class="alert alert-danger" style="padding: 5px;"> {{ msg }} </div> {% endif %} {% csrf_token %} <a href="">忘记密码了?</a> <button type="submit" class="btn btn-success btn-block">登录</button> </form> ``` * 写了一个类继承Django的view,然后写了`get` `post`方法(get/post的if是Django替我们完成的) * 在url中调用`Loginview`的`as_view`方法需要加上括号,进行调用。 * Django的form进行表单验证并把`error`值传到前台。 * `is_valid`方法,验证表单 ## session和cookie自动登录机制 ### cookie的存储 cookie是浏览器支持的一种本地存储方式。以dict,键值对方式存储。 ```python {"sessionkey": "123"} ``` 浏览器会自动对于它进行解析。 ### http请求是一种无状态的请求 用户向服务器发起的两次请求之间是没有状态的。也就是服务器并不知道这是同一个用户发的。 > a浏览一个新闻,b浏览一个新闻,服务器只需要把新闻返回给客户端就可以,但在没有登录的情况下浏览某些网站,例如淘宝,也是给我们记住的,a浏览了哪些商品,b浏览了哪些商品。 ### 有状态请求 做到记住用户: > 浏览器a在向服务器发起请求,服务器会自动给浏览器a回复一个id,浏览器a把id放到cookie当中,在下一次请求时带上这个cookie里的id值向浏览器请求,服务器就知道你是哪个浏览器发过来的了。 服务器a发回来的id会放到服务器a的域之下。不能跨域访问cookie。 使用浏览器随便打开一个网页,然后f12打开。会找到存储在浏览器本地的cookie值。点击clear all清空所有的cookie f5刷新页面,会发现又把这些cookie值进来。 如果将用户名和密码直接保存在cookie,可以实现最垃圾最简略版本的自动登录。 ### 解决cookie放在本地不安全的问题(session) > 用户在第一次请求后,浏览器回复的id既可以是用户的user id, 也可以一段任意的字符串,我们把它叫做session id 根据用户名和密码,服务器会采用自己的规则生成session id。这个session id保存在本地cookie。浏览器请求服务器会携带。 * 输入用户名 & 密码 * 调用 `login()`, 后端程序会根据用户名密码生成session id。保存在数据库中。 * 用户登录之后,需要通过这个session id取出这些基本信息。 Django的默认表中的session表就记录了用户登录时,后端我们Django为用户生成的sessionid。 可以看到session key value 和过期时间。 我们可以清空这张表的数据。运行项目进行登录。 可以看到我们刚刚生成的session id。 此时通过f12查看浏览器在本地存储的session id。可以看到如下图和我们数据库中的一致。 session_key 发到浏览器叫做session id 通过session id 用户访问任何一个页面都会携带,服务器就会认识。 settings.py中, ```python 'django.contrib.sessions', ``` 这个app会拦截我们每次的request请求,在request中找到session id,然后去数据表中进行查询。 然后通过session key 去找到session data。此时直接为我们取出了user。 在服务器返回浏览器的response中也会直接加上session id > cookie是浏览器本地存储机制,存在域名之下,存储不安全。 > 服务器在返回id时通过规则生成一串字符,并设置了过期时间。存储在服务器端(数据库) 参考 http://projectsedu.com/2016/10/17/django%E4%BB%8E%E8%AF%B7%E6%B1%82%E5%88%B0%E8%BF%94%E5%9B%9E%E9%83%BD%E7%BB%8F%E5%8E%86%E4%BA%86%E4%BB%80%E4%B9%88/

很赞哦! (0)

文章交流

  • emoji
0人参与,0条评论

当前用户

未登录,点击   登录

站点信息

  • 建站时间:网站已运行2285天
  • 系统信息:Linux
  • 后台程序:Python: 3.8.10
  • 网站框架:Django: 3.2.6
  • 文章统计:257 篇
  • 文章评论:63 条
  • 腾讯分析网站概况-腾讯分析
  • 百度统计网站概况-百度统计
  • 公众号:微信扫描二维码,关注我们
  • QQ群:QQ加群,下载网站的学习源码
返回
顶部
标题 换行 登录
网站