12 案例:登录_哔哩哔哩_bilibili 参考大佬的B站视频教程笔记
目录
登录接口的实现会话机制成功后的信息保存:
中间件的使用,解决登录保护使未登录过的用户进行登录
Form组件 - 主要作用:
Form组件信息的配置
ModelForm组件 - 特点:
验证码的保存在session会话中并设置过期时间
缓存的使用
python 快速定位问题小技巧:(traceback的使用)
登录接口的实现会话机制成功后的信息保存:
- 生成随机字符串
- 返回到用户的浏览器的cookie中
- 存储到网站的session中 随机字符串+用户标识
中间件的使用,解决登录保护使未登录过的用户进行登录
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse, redirectclass AuthMiddleware(MiddlewareMixin):# 项目运行前的操作请求,钩子函数def process_request(self, request):# 0.排除那些不需要登录就能访问的页面# request.path_info 获取当前用户请求的URL /login/if request.path_info in ["/login/", "/image/code/"]:return# 1.读取当前访问的用户的session信息,如果能读到,说明已登陆过,就可以继续向后走。info_dict = request.session.get("info")# print(info_dict)if info_dict:return# 2.没有登录过,重新回到登录页面return redirect('/login/')
# 注册app中间件
'myapp.middleware.auth.AuthMiddleware'
Form组件 - 主要作用:
1.生成html表单标签、数据校验
2.form = LoginForm(initial={'user':'xxx','password':'xxx'}) # Web页面默认值,字典类型
Form组件信息的配置
# form 组件配置
class LoginForm(BootStrapForm):username = forms.CharField(label="用户名",widget=forms.TextInput,required=True)password = forms.CharField(label="密码",widget=forms.PasswordInput(render_value=True), # 展示数据(加密点显示)required=True)code = forms.CharField(label="验证码",widget=forms.TextInput,required=True)def clean_password(self): # 密码采用md5加密pwd = self.cleaned_data.get("password")return md5(pwd)
数据校验视图
def login(request):""" 登录 """if request.method == "GET":form = LoginForm()return render(request, 'login.html', {'form': form})form = LoginForm(data=request.POST)# form = LoginForm(initial={'user':'xxx','password':'xxx','code':'xxxx'}) # Web页面初始值if form.is_valid():# 验证成功,获取到的用户名和密码# {'username': 'wupeiqi', 'password': '123',"code":123}# 验证码的校验user_input_code = form.cleaned_data.pop('code')code = request.session.get('image_code', "")if code.upper() != user_input_code.upper():form.add_error("code", "验证码错误")return render(request, 'login.html', {'form': form})# 去数据库校验用户名和密码是否正确,获取用户对象、None# admin_object = models.Admin.objects.filter(username=xxx, password=xxx).first()admin_object = models.Admin.objects.filter(**form.cleaned_data).first()if not admin_object:form.add_error("password", "用户名或密码错误")# form.add_error("username", "用户名或密码错误")return render(request, 'login.html', {'form': form})# 用户名和密码正确# 网站生成随机字符串; 写到用户浏览器的cookie中;在写入到session中;request.session["info"] = {'id': admin_object.id, 'name': admin_object.username}# session可以保存7天request.session.set_expiry(60 * 60 * 24 * 7)return redirect("/admin/list/")return render(request, 'login.html', {'form': form})
登录页面login.html
<div class="account"><h2>用户登录</h2><form method="post" novalidate>{% csrf_token %}<div class="form-group"><label>用户名</label>{{ form.username }}<span style="color: red;">{{ form.username.errors.0 }}</span></div><div class="form-group"><label>密码</label>{{ form.password }}<span style="color: red;">{{ form.password.errors.0 }}</span></div><div class="form-group"><label>图片验证码</label><div class="row"><div class="col-xs-7">{{ form.code }}<span style="color: red;">{{ form.code.errors.0 }}</span></div><div class="col-xs-5"><img id="image_code" src="/image/code/" style="width: 125px;"></div></div></div><input type="submit" value="登 录" class="btn btn-primary"></form>
</div>
ModelForm组件 - 特点:
- 校验数据,生成表单标签
- 使用obj直接保存数据到数据库,免去复杂的xxx.objects.create(xxx)
- 默认显示数据,对象类型
obj=xxx.objects.filter(id=1).first()
obj=xxxModelForm(instance=obj)
- 依赖于数据库的model,减少字段的定义
class Meta:model = xxxfields = ['username']# fields = "__all__"
ModelForm组件
class UserModelForm(BootStrapModelForm):name = forms.CharField(min_length=3,label="用户名",widget=forms.TextInput(attrs={"class": "form-control"}))class Meta:model = models.UserInfofields = ["name", "password", "age", 'account', 'create_time', "gender", "depart"]# fields = '__all__'
数据检验与保存
def user_model_form_add(request):""" 添加用户(ModelForm版本)"""if request.method == "GET":form = UserModelForm()return render(request, 'user_model_form_add.html', {"form": form})# 用户POST提交数据,数据校验。form = UserModelForm(data=request.POST)if form.is_valid():# 如果数据合法,保存到数据库# {'name': '123','account': Decimal('0'),'gender': 1, 'depart': <Department: IT运维部门>}# print(form.cleaned_data)form.save() # 同 models.UserInfo.objects.create(..)return redirect('/user/list/')# 校验失败(在页面上显示错误信息)return render(request, 'user_model_form_add.html', {"form": form})
用户web页面user_add.html
<div class="container"><div class="panel panel-default"><div class="panel-heading"><h3 class="panel-title"> 新建用户 </h3></div><div class="panel-body"><form method="post" novalidate>{% csrf_token %}{% for field in form %}<div class="form-group"><label>{{ field.label }}</label>{{ field }}<span style="color: red;">{{ field.errors.0 }}</span></div>{% endfor %}<button type="submit" class="btn btn-primary">提 交</button></form></div></div>
</div>
验证码的保存在session会话中并设置过期时间
# 写入到自己的session中(以便于后续获取验证码再进行校验)
request.session['image_code'] = code_string
# 给Session设置60s超时
request.session.set_expiry(60)
# 校验
# 验证码的校验
user_input_code = form.cleaned_data.pop('code')
code = request.session.get('image_code', "")
if code.upper() != user_input_code.upper():form.add_error("code", "验证码错误")return render(request, 'login.html', {'form': form})
保存用户登录的信息到session并设置过期时间
# 网站生成随机字符串; 写到用户浏览器的cookie中;在写入到session中;
request.session["info"] = {'id': admin_object.id, 'name': admin_object.username}
# session可以保存7天
request.session.set_expiry(60 * 60 * 24 * 7)
用户密码的加密形式(即用户输入的密码是密钥加密和MD5加密后来进行和数据库中比对)
def md5(data_string): # SECRET_KEY + MD5 加密obj = hashlib.md5(settings.SECRET_KEY.encode('utf-8'))obj.update(data_string.encode('utf-8'))return obj.hexdigest()
用户注销功能的实现
def logout(request):""" 注销 """request.session.clear() # 清除session会话信息return redirect('/login/')
model中的choices字段的获取
# 在django中做的约束
gender_choices = ((1, "男"),(2, "女"),)
gender = models.SmallIntegerField(verbose_name="性别", choices=gender_choices)
获取方法:get_字段名_display()
queryset = models.UserInfo.objects.all()
for row in queryset:print(row.get_gender_display()) # 输出男或女# [注意:row.get_gender_display在前端页面时不要加括号,django自动实现]
缓存的使用
- 响应头 Expires 缓存过期时间,用来指定资源到期的时间
- 响应头 Chche Control,用于控制网页的缓存,创建后的时间缓存失效,单位s
- get_or_set 若未获取到数据则执行set操作
- add(key,value) 存储缓存
- get(key) 获取缓存数据
- set_many(dict,timeout) 批量存储缓存
- delete(key) 删除缓存数据
- get_many(key_list) 批量获取数据
# setting config
CACHES = {'default':{'BACKEND':'django.core.cache.backends.locmem.LocMemCache', # 内存缓存'LOCATION':'unique-snowflake','TIMEOUT':300,'OPTIONS':{'MAX_ENTRIES':300, # 缓存最大数据条数'CULL_FREQUENCY':2, # 当缓存条数达到最大值时,删除1/x的缓存数据}}
}
# view
import time
from django.views.decorators.cache import cache_page
@cache_page(15) # 缓存时间,多长时间缓存一次,单位s
def test_cache(request):t = time.time()return HttpResponse('time is %s'%(t))
python 快速定位问题小技巧:(traceback的使用)
import traceback
try:a
except:print(traceback.format_exc())
"""
输出
Traceback (most recent call last):File "E:/desktop/my_dj/web/app/tests.py", line 6, in <module>a
NameError: name 'a' is not defined
"""