通过django中间件和python魔法方法实现自定义session(通过文件存储session)

Posted 耗油炒白菜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通过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
MysessionDict.py

操作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")
encrypt.py

中间件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
mysession.py

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),
]
urls.py

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")
views.py

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="年龄")
models.py

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
register_forms.py

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>
login.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>
register.html

 

  

以上是关于通过django中间件和python魔法方法实现自定义session(通过文件存储session)的主要内容,如果未能解决你的问题,请参考以下文章

魔法方法之自定义序列

Django --魔法方法:def __str__()

魔法方法

Python之路68-Django中间件

Python 魔法方法连载五,实现算术运算

Django中间件