美文网首页好文有约
Python(五十六)中间件和上下文处理器

Python(五十六)中间件和上下文处理器

作者: Lonelyroots | 来源:发表于2022-02-12 19:00 被阅读0次

从2021年9月2日发文至今,Python系列(包括代码在内)共计109493个字、五十六篇!

1. 中间件

1.1. 中间件的引入

Django中间件(Middleware)是一个轻量级、底层的“插件”系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出。

1.2. django中的中间件

django中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。
在django项目的settings模块中,有一个MIDDLEWARE_CLASSES变量,其中的每一个元素就是一个中间件。

1.3. 中间的执行顺序

请求以自上而下的顺序通过所有的层,view函数处理之后,响应以自下而上的顺序通过所有的层,期间经过的每个中间件都会对请求或者响应进行处理。

1.4. 中间件的结构

中间件中可以定义五个方法:

1.process_request(self,request) :执行视图之前被调用(是在产生request对象,进行url匹配之前),在每个请求上调用,返回None或HttpResponse对象。
2.process_view(self,request,callback,callback_args,callback_kwargs):调用视图之前被调用(是在url匹配之后,调用视图函数之前),在每个请求上调用,返回None或HttpResponse对象。
3.process_template_response(self,request,response):在视图刚好执行完毕之后被调用,在每个请求上调用,返回实现了render方法的响应对象。
4.process_exception(self, request, exception):当视图抛出异常时调用,在每个请求上调用,返回一个HttpResponse对象。
5.process_response(self, request, response):所有响应返回浏览器之前被调用,在每个请求上调用,返回HttpResponse对象。

1.5. 自定义中间件第一种方式例子

Myblog15_16/mymiddleware.py:

from django.utils.deprecation import MiddlewareMixin
from django.http import HttpResponse

class MyException(MiddlewareMixin):
    # 用户发送请求到达视图之前就会调用
    def process_request(self,request):
        print('中间件被调用')
        request.name = 'chenhong'
        # return HttpResponse('我返回了!')        # 不会进行后续操作
        return None     # 没有任何东西返回,会正常进行后续操作

Myblog15_16/settings.py:在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',
    'Myblog15_16.mymiddleware.MyException',     # (十二、中间件和上下文处理器)
    # 'Myblog15_16.mymiddleware.UserMiddleware',   # (十二、中间件和上下文处理器)
]

form_session/views.py:

from django.shortcuts import render
from django.shortcuts import redirect,reverse

def home(request):
    # 从session里面去获取相关与username的值,通过username变量去接收,如果没有值,将”用户未登录“的字符串赋值给username
    username = request.session.get('username','用户未登录')
    print(request.name)     # (十二、中间件和上下文处理器)
    if username == '用户未登录':
        return redirect('login')        # 这里重定向可以不写reverse
    return render(request,'form_session/home.html',context={
        'username':username
    })

def logout(request):
    request.session.flush()     # 删除当前会话的数据并删除cookie
    return redirect('home')

templates/form_session/home.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

欢迎{{ username }}登录页面    {# 这里的username是views里context传的键 #}
<a href="{% url 'logout' %}">注销</a>

</body>
</html>

form_session/urls.py:

from django.urls import path
from . import views

urlpatterns = [
    path('home/',views.home,name='home'),
    path('logout/',views.logout,name='logout'),
]

1.6. 自定义中间件第二种方式例子

Myblog15_16/mymiddleware.py:

from django.utils.deprecation import MiddlewareMixin
from django.http import HttpResponse

class UserMiddleware(MiddlewareMixin):
    def __init__(self, get_response=None):
        self.get_response = get_response
        print(self.get_response)

    def __call__(self, request):
        """__call__()方法能够让类的实例对象,像函数一样被调用"""
        # 请求处理,request到达view之前执行的代码
        username = request.session.get('username','用户未登录')
        if username != '用户未登录':
            setattr(request,'myuser',username)
        else:
            setattr(request,'myuser','用户未登录')
        print('======request======')

        # 响应处理,视图层执行后才是执行响应的代码
        response = self.get_response(request)
        print('======response======')
        return response

Myblog15_16/settings.py:在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',
    # 'Myblog15_16.mymiddleware.MyException',     # (十二、中间件和上下文处理器)
    'Myblog15_16.mymiddleware.UserMiddleware',   # (十二、中间件和上下文处理器)
]

form_session/views.py:

from django.shortcuts import render
from django.shortcuts import redirect,reverse

def home(request):
    # 从session里面去获取相关与username的值,通过username变量去接收,如果没有值,将”用户未登录“的字符串赋值给username
    username = request.session.get('username','用户未登录')
    # print(request.name)     # (十二、中间件和上下文处理器)
    print(request.myuser)     # (十二、中间件和上下文处理器)
    if username == '用户未登录':
        return redirect('login')        # 这里重定向可以不写reverse
    return render(request,'form_session/home.html',context={
        'username':username
    })

def logout(request):
    request.session.flush()     # 删除当前会话的数据并删除cookie
    return redirect('home')

templates/form_session/home.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

欢迎{{ username }}登录页面    {# 这里的username是views里context传的键 #}
<a href="{% url 'logout' %}">注销</a>

</body>
</html>

form_session/urls.py:

from django.urls import path
from . import views

urlpatterns = [
    path('home/',views.home,name='home'),
    path('logout/',views.logout,name='logout'),
]
运行结果
运行结果

2. 上下文处理器

2.1. 上下文处理器的引入

在模板中想要使用的变量是从视图函数中的context这个上下文的参数中传递进来的,每个视图函数需要什么参数就传什么参数。
而上下文处理器就是创建模板变量,在settings.py中,包含了当前使用的上下文处理器,它的作用是可以给每一个模板(包括不同app下方的模板)提供相同的变量。

2.2. 自定义上下文处理器例子

在刚才的中间件的例子中,我们给request增加了一个myuser的属性,而如果每个模板中也就是每个页面上都需要用到登录用户名这个变量名的话,那么我们也可以把这个变量在上下文处理器中将变量传给模板。

上下文处理器的程序:Myblog15_16/mycontext.py:

# (十二、中间件和上下文处理器)

def my_user(request):
    user = request.session.get('username','用户未登录')
    if user != '用户未登录':
        return {'myuser1':user}
    else:
        return {'myuser1':'用户暂未登录,请您先登录!'}

Myblog15_16/settings.py:在settings文件里进行上下文处理器的注册。

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',
                'Myblog15_16.mycontext.my_user',        # (十二、中间件和上下文处理器)
            ],
        },
    },
]

form_session/views.py:

from django.shortcuts import render
from django.shortcuts import redirect,reverse

def home(request):
    # 从session里面去获取相关与username的值,通过username变量去接收,如果没有值,将”用户未登录“的字符串赋值给username
    username = request.session.get('username','用户未登录')
    # print(request.name)     # (十二、中间件和上下文处理器)
    print(request.myuser)     # (十二、中间件和上下文处理器)
    if username == '用户未登录':
        return redirect('login')        # 这里重定向可以不写reverse
    return render(request,'form_session/home.html',context={
        'username':username
    })

def logout(request):
    request.session.flush()     # 删除当前会话的数据并删除cookie
    return redirect('home')

templates/form_session/home.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

欢迎{{ username }}登录页面    {# 这里的username是views里context传的键 #}
<a href="{% url 'logout' %}">注销</a>

上下文处理器的用户名:{{ myuser1 }}     {#  (十二、中间件和上下文处理器)  #}

</body>
</html>

form_session/urls.py:

from django.urls import path
from . import views

urlpatterns = [
    path('home/',views.home,name='home'),
    path('logout/',views.logout,name='logout'),
]
运行结果

2.3. 中间件和上下文的总结

我们刚才分别用中间件和上下文完成了跟登录用户有关的例子, 最后的结果都是能在页面上显示用户的用户名了。
中间件是在用户请求到响应的过程中去加入一些额外的逻辑功能,例子中给request增加了一个myuser的属性。
上下文是给所有的模板增加变量,例子中给模板增加了一个myuser的变量。

3. admin后台

3.1. 介绍Django管理页面

为员工或客户生成一个用户添加,修改和删除内容的后台是一项缺乏创造性和乏味的工作。因此,Django全自动地根据模型创建后台界面。
Django产生于一个公众页面和内容发布者页面完全分离的新闻类站点的开发过程中。站点管理人员使用管理系统来添加新闻、事件和体育时讯等,这些添加的内容被显示在公众页面上。Django 通过为站点管理人员创建统一的内容编辑界面解决了这个问题。管理界面不是为了网站的访问者,而是为管理者准备的。

form_session/models.py:

from django.db import models

# Create your models here.

class UserModel(models.Model):
    username = models.CharField(max_length=30,unique=True)
    password = models.CharField(max_length=16)
    email = models.EmailField()



# (十二、中间件和上下文处理器)
from django.db import models

# Create your models here.
# 学院表
class Department(models.Model):

    d_id = models.AutoField(primary_key=True)
    d_name = models.CharField(max_length=30,unique=True)

    def __str__(self):
        return f'd_id={self.d_id},d_name={self.d_name}'

# 学生表
class Student(models.Model):

    s_id = models.AutoField(primary_key=True)
    s_name = models.CharField(max_length=30)
    # 一对多关系,当删除学院时,隶属于该学院的学生对应学院的id号为null。当related_name取别名stu,在视图函数反向访问时,student_set可以用stu来代替
    dept_id = models.ForeignKey('Department',on_delete=models.SET_NULL,null=True,related_name='stu')       # 外键在数据库中显示会自动添加_id

    def __str__(self):
        return f's_id={self.s_id},s_name={self.s_name},dept_id={self.dept_id}'

# 学生详情表
class StuDetail(models.Model):

    stu_id = models.AutoField(primary_key=True)
    stu_age = models.IntegerField()
    stu_sex = models.BooleanField(default=1)
    intro = models.TextField(null=True)
    # 一对一关系,在删除学生的同时,删除该学生的详情
    s_id = models.OneToOneField('Student',on_delete=models.CASCADE)

    def __str__(self):
        return f'stu_id={self.stu_id},stu_age={self.stu_age},stu_sex={self.stu_sex},intro={self.intro}'

# 课程表
class Course(models.Model):

    c_id = models.AutoField(primary_key=True)
    c_name = models.CharField(max_length=30,unique=True)
    # 多对多关系,关系创建成功,中间表自动生成。
    stu_course = models.ManyToManyField('Student')

    def __str__(self):
        return f'c_id={self.c_id},c_name={self.c_name}'

需要先在Run manage.py Task窗口下,createsuperuser创建超级管理员账户,然后完成一些有关信息的注册(然后才能登录,进到admin的后台),切记密码一定要记住!!!

form_session/admin.py:

# (十二、中间件和上下文处理器)
from django.contrib import admin
from .models import UserModel,Student,StuDetail,Department,Course

# Register your models here.

# 查找
class StudentAdmin(admin.ModelAdmin):
    list_display = ['s_id','s_name']        # 显示某些字段
    list_filter = ['s_id']      # 过滤字段
    search_fields = ['s_id','s_name']       # 可以通过设置的字段进行搜索
    list_per_page = 3       # 分页,一页显示3个,默认情况是以倒序进行排序

# 增加和修改
class StuDetailAdmin(admin.ModelAdmin):
    # fields = ['s_id','stu_age','intro']   # 字段显示的先后顺序,以及展示的字段个数
    fieldsets = [
        ('学生',{'fields':['s_id']}),
        ('个人信息',{'fields':['stu_age','intro']})
    ]       # 字段分组,也是按序排列

# 把这些模型类都注册进去
admin.site.register(UserModel)
admin.site.register(Student,StudentAdmin)
admin.site.register(StuDetail,StuDetailAdmin)
admin.site.register(Department)
admin.site.register(Course)

Myblog15_16/settings.py:修改admin后台语言、时区以及提交时间。

LANGUAGE_CODE = 'zh-hans'       # (十二、中间件和上下文处理器)

TIME_ZONE = 'Asia/Shanghai'     # (十二、中间件和上下文处理器)

USE_I18N = True

USE_L10N = True

USE_TZ = False      # 修改为False以后,这样提交到数据库的时间才是当前的时间 (十二、中间件和上下文处理器)
运行结果

相比于在视图文件中通过程序进行增删改查,图形化界面的增删改查操作更加地方便有效!

文章到这里就结束了!希望大家能多多支持Python(系列)!六个月带大家学会Python,私聊我,可以问关于本文章的问题!以后每天都会发布新的文章,喜欢的点点关注!一个陪伴你学习Python的新青年!不管多忙都会更新下去,一起加油!

Editor:Lonelyroots

相关文章

网友评论

    本文标题:Python(五十六)中间件和上下文处理器

    本文链接:https://www.haomeiwen.com/subject/tjcxlrtx.html