通过django中间件和python魔法方法实现自定义session(通过文件存储session)
思路:
# 首先设置一个继承dict的类MysessionDict(用来设置session,例如request.mysession)
# 请求来的时候
# 1、生成一个空的MysessionDict对象;request.mysession = MysessionDict()
# 2、过滤url,如果请求是"/login/","/register/"就直接通过,不用获取cookie
# 3、获取请求的cookie,如果有随机字符串,则拿着这个随机字符串到存放session的文件中去匹配是否存在这个cookie,如果存着取出对应的值并赋值给request.mysession.data
# 请求走的时候
# 首先判断请求的url如果是"/login/"并且mysession操作方式是修改,如果是"/login/"(不是则不做处理):
# 生成随机字符串,
# 获取request.POST中的用户名和密码信息存放在data变量中
# 将随机字符串和data通过方法将信息存放到文件中
# 将随机字符串赋值给cookie,键为"mysession_id";
# response.set_cookie('mysession_id', random_str)
# 如果是删除操作
# 删除文件中session,并删除cookie
代码:
- 设置字典的MysessionDict.py
class MysessionDict(dict):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.modified = False
self.deleted = False
@staticmethod
def check_type_of_key(key):
return isinstance(key, str) or False
def __setattr__(self, key, value):
if not self.check_type_of_key(key):
raise TypeError(
"The type of key must be 'str' "
)
if key not in ['modified', 'deleted']:
self['modified'] = True
super().__setattr__(key, value)
def __getattr__(self, item):
return self.__dict__.get(item)
def __setitem__(self, key, value):
if not self.check_type_of_key(key):
raise TypeError(
"The type of key must be 'str' "
)
if key not in ['modified', 'deleted']:
self.modified = True
setattr(self, key, value)
def __getitem__(self, item):
return getattr(self, item, None)
def flush(self):
self.deleted = True
- 操作session文件的方法encrypt.py
import json
import os
# 保存session到文件中
def dump(data, random_str):
with open("static/session.txt", "a") as f:
json_data = json.dumps(data)
all_data = "%s|%s" % (random_str, json_data)
f.write("{}\n".format(all_data))
# 从文件中取出session_id对应的session值
def load(random_str):
with open("static/session.txt", "r") as f:
for line in f:
if random_str in line:
line = line.strip("\n")
line_list = line.split("|")[1]
data = json.loads(line_list)
return data
# 删除cookie
def delete(random_str):
with open("static/session.txt", "r") as f, \
open("static/session.txt.swap", "w", encoding="utf-8") as fw:
for line in f:
if random_str in line:
line = ""
fw.write("{}".format(line))
os.remove("static/session.txt")
os.rename("static/session.txt.swap", "static/session.txt")
- 中间件mysession.py
from django.utils.deprecation import MiddlewareMixin
from app01.mymiddleware.utils.MysessionDict import MysessionDict
from app01.mymiddleware.utils.encrypt import dump, load, delete
from django.shortcuts import redirect
import uuid
IgnoreUrl = ['/login/', '/register/']
class MyMiddleware(MiddlewareMixin):
def process_request(self, request):
request.mysession = MysessionDict()
target_url = request.get_full_path()
if target_url not in IgnoreUrl:
random_str = request.COOKIES.get("mysession_id")
if not random_str:
return redirect("login")
data = load(random_str)
request.mysession.data = data
def process_response(self, request, response):
if request.mysession.modified and request.get_full_path() == "/login/":
random_str = str(uuid.uuid1())
data = {
"username": request.POST.get('username'),
"password": request.POST.get('password')
}
dump(data,random_str)
response.set_cookie('mysession_id', random_str)
request.mysession["modified"] = False
if request.mysession.deleted:
random_str = request.COOKIES.get("mysession_id")
delete(random_str)
response.delete_cookie("mysession_id")
return response
- urls.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 注册
url(r'^register/', views.register),
# 登录
url(r'^login/', views.login,name="login"),
url(r'^logout/', views.logout),
url(r'^index/', views.index),
]
- views.py
from django.shortcuts import render, HttpResponse, redirect
from django.http import JsonResponse
from app01.register_forms import RegisterForms
from app01 import models
import json
# Create your views here.
def register(request):
form_obj = RegisterForms()
if request.method == "POST":
back_code = {"code": 200, "msg": ""}
data = json.loads(request.body)
form_obj = RegisterForms(data)
if form_obj.is_valid():
clean_data = form_obj.cleaned_data
clean_data.pop("re_password")
models.Userinfo.objects.create(**clean_data)
back_code["msg"] = "注册成功"
back_code["url"] = "/login/"
else:
back_code["code"] = 300
back_code["msg"] = form_obj.errors
return JsonResponse(back_code)
return render(request, "register.html", locals())
def login(request):
if request.method == "POST":
username = request.POST.get("username")
password = request.POST.get("password")
user_obj = models.Userinfo.objects.filter(username=username,password=password).first()
if user_obj:
request.mysession["modified"] = True
return HttpResponse("ok")
return render(request, "login.html")
def logout(request):
request.mysession.flush()
return redirect("login")
def index(request):
print(request.mysession.data)
if request.mysession.data:
return JsonResponse(request.mysession.data)
return HttpResponse("index")
- models.py
from django.db import models
# Create your models here.
class Userinfo(models.Model):
username = models.CharField(max_length=16, verbose_name="用户名")
password = models.CharField(max_length=16, verbose_name="密码")
age = models.IntegerField(verbose_name="年龄")
- register_forms.py
from django import forms
from app01 import models
class RegisterForms(forms.Form):
username = forms.CharField(max_length=16, min_length=4, label="用户名",
error_messages={
'min_length': '用户名最少4位',
'max_length': '用户名最大16位',
'required': "用户名不能为空"
},
widget=forms.widgets.TextInput(attrs={'class': 'form-control'})
)
password = forms.CharField(max_length=16, min_length=4, label="密码",
error_messages={
'min_length': '密码最少4位',
'max_length': '密码最大16位',
'required': "密码不能为空"
},
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
)
re_password = forms.CharField(max_length=16, min_length=4, label="确认密码",
error_messages={
'min_length': '确认密码最少4位',
'max_length': '确认密码最大16位',
'required': "确认密码不能为空"
},
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
)
age = forms.CharField(label="年龄",
error_messages={
'required': "年龄不能为空"
},
widget=forms.widgets.TextInput(attrs={'class': 'form-control'})
)
def clean_username(self):
username = self.cleaned_data.get("username")
user_obj = models.Userinfo.objects.filter(username=username).first()
if user_obj:
self.add_error("username", "用户已存在")
if username.endswith("sb"):
self.add_error("username", "用户名不能以sb结尾")
return username
def clean_age(self):
age = self.cleaned_data.get("age")
age = int(age)
if not (age < 150 and age >18):
self.add_error("age", "年龄必须小于150,大于18")
age = str(age)
return age
def clean(self):
password = self.cleaned_data.get("password")
re_password = self.cleaned_data.get("re_password")
if not password == re_password:
self.add_error("re_password", "两次密码不一致")
return self.cleaned_data
- login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- Bootstrap3 核心 CSS 文件 -->
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<!-- Bootstrap3 核心 JavaScript 文件 -->
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- font-awesome.min.css图标库4.7版本 -->
<link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
{% load static %}
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1 class="text-center">登录界面</h1>
<form action="" method="post">
{% csrf_token %}
用户名:<input type="text" name="username" class="form-control">
密 码:<input type="password" name="password" class="form-control">
<br>
<input type="submit" class="btn btn-info btn-block" id="btn" value="提交">
</form>
</div>
</div>
</div>
</body>
</html>
- register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- Bootstrap3 核心 CSS 文件 -->
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<!-- Bootstrap3 核心 JavaScript 文件 -->
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- font-awesome.min.css图标库4.7版本 -->
<link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
{% load static %}
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1 class="text-center">注册页面</h1>
<form action="" method="post" novalidate>
{% for form in form_obj %}
<p>
{{ form.label }}:{{ form }}
<span style="color: red" class="input_span"></span>
</p>
{% endfor %}
<input type="button" class="btn btn-info btn-block" id="btn" value="提交">
</form>
</div>
</div>
</div>
<script src="{% static 'js/mysteup.js' %}"></script>
<script>
$("p span").each(function () {
if ($(this).text()) {
$(this).prev().css("border", "solid red")
}
});
$("#btn").click(function () {
$.ajax({
url: '',
type: 'post',
contentType:"application/json",
dataType: 'json',
data: JSON.stringify({
"username": $("#id_username").val(),
"password": $("#id_password").val(),
"re_password": $("#id_re_password").val(),
"age": $("#id_age").val(),
}),
success: function (args) {
if (args.code == 200) {
window.location.href = args.url
} else {
$.each(args.msg, function (index, obj) {
{#console.log(index,obj) // username ["用户名不能为空"]#}
let targetId = '#id_' + index; // input标签
$(targetId).next().text(obj[0]).prev().css("border", "solid red")
})
}
}
})
})
$('input').focus(function () {
// 将input下面的span标签和input外面的div标签修改内容及属性
$(this).next().text('').prev().removeAttr("style","");
})
</script>
</body>
</html>
- settings
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'app01.mymiddleware.mysession.MyMiddleware',
]
文档更新时间: 2022-03-28 15:54 作者:李延召