文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

类视图 中间件和模板

2023-01-31 00:44

关注

模板和类视图

1. 在工程中创建模板目录templates。

然后修改settings.py配置文件中修改TEMPLATES配置项的DIRS值, 如下:

image_thumb

2. 定义模板

在templates新建一个index.html文件

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

 

3. 类视图的引入

在Django中也可以使用类来定义一个视图,称为类视图

 def register(request):
    """处理注册"""

    # 获取请求方法,判断是GET/POST请求
    if request.method == 'GET':
        # 处理GET请求,返回注册页面
        return render(request, 'index.html')
    else:
        # 处理POST请求,实现注册逻辑
        return HttpResponse('这里实现注册逻辑')

使用类视图可以将视图对应的不同请求方式以类中的不同方法来区别定义。如下所示

from django.views.generic import View

class RegisterView(View):
    """类视图:处理注册"""

    def get(self, request):
        """处理GET请求,返回注册页面"""
        return render(request, 'register.html')

    def post(self, request):
        """处理POST请求,实现注册逻辑"""
        return HttpResponse('这里实现注册逻辑')

 

类视图的好处:

  • 代码可读性好
  • 类视图相对于函数视图有更高的复用性, 如果其他地方需要用到某个类视图的某个特定逻辑,直接继承该类视图即可

 

4. 类视图的使用

定义类视图需要继承自Django提供的父类View,可使用from django.views.generic import View或者from django.views.generic.base import View 导入,定义方式如上所示。

from django.views.generic import View
class RegisterView(View):
    """类视图:处理注册"""
    def get(self, request):
        """处理GET请求,返回注册页面"""
        return render(request, 'register.html')

    def post(self, request):
        return render(request, 'index.html')

配置路由时,使用类视图的as_view()方法来添加

urlpatterns = [
    # 视图函数:注册
    # url(r'^register/$', views.register, name='register'),
    # 类视图:注册
    url(r'^register/$', views.RegisterView.as_view(), name='register'),
]

 

5. 类视图原理

 @classonlymethod
    def as_view(cls, **initkwargs):
        """
        Main entry point for a request-response process.
        """
        ...省略代码...

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            # 调用dispatch方法,按照不同请求方式调用不同请求方法
            return self.dispatch(request, *args, **kwargs)

        ...省略代码...

        # 返回真正的函数视图
        return view


    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)

 

总结:

URL里面调用as_view,调用dispatch方法,按照不同请求方式调用不同请求方法。最后返回真正的函数视图View

6. 定义模板,模板渲染

1. 在templates目录中新建一个模板文件,如test.html

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

2. 调用模板分为两步骤

1) 找到模板 loader.get_template(模板文件在模板目录中的相对路径) -> 返回模板对象

2) 渲染模板 模板对象.render(context=None, request=None) -> 返回渲染后的html文本字符串 context 为模板变量字典,默认值为None request 为请求对象,默认值为None

定义一个视图如下:

from django.http import HttpResponse
from django.template import loader
def test(request):
    # 1.获取模板
    template = loader.get_template('test.html')
    context = {'city': '北京'}
    # 2.渲染模板
    return HttpResponse(template.render(context))

 

返回:

image_thumb[1]

上面代码可以简化,djangi提供了render函数

render(request对象, 模板文件路径, 模板数据字典)

from django.http import HttpResponse
from django.template import loader
# def test(request):
#     # 1.获取模板
#     template = loader.get_template('test.html')
#     context = {'city': '北京'}
#     # 2.渲染模板
#     return HttpResponse(template.render(context))
from django.shortcuts import render
def test(request):
    context = {'city': '广州'}
    return render(request, 'index.html', context)

 

7.定义模板,模板渲染

1. 模板变量

变量名必须由字母、数字、下划线(不能以下划线开头)和点组成。

语法如下:

{{变量}}

模板变量可以使python的内建类型,也可以是对象。

def index(request):
    context = {
        'city': '北京',
        'adict': {
            'name': '西游记',
            'author': '吴承恩'
        },
        'alist': [1, 2, 3, 4, 5]
    }
    return render(request, 'index.html', context)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>{{ city }}</h1>
    <h1>{{ adict }}</h1>
    <h1>{{ adict.name }}</h1>  注意字典的取值方法
    <h1>{{ alist }}</h1>
    <h1>{{ alist.0 }}</h1>  注意列表的取值方法
</body>
</html>

返回:

image_thumb[2]

 

2. 模板的语言

For循环

{% for item in 列表 %}

循环逻辑
{{forloop.counter}}表示当前是第几次循环,从1开始
{%empty%} 列表为空或不存在时执行此逻辑

{% endfor %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {% for foo in alist %}
        <h1>{{ foo }}</h1>
        {{forloop.counter}}
    {% endfor %}

</body>
</html>

 

IF条件

{% if ... %}
逻辑1
{% elif ... %}
逻辑2
{% else %}
逻辑3
{% endif %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
   {% if city == "北京" %}
       <h1>北京</h1>
   {% elif city == "北2" %}
       <h1>北2</h1>
   {% else %}
       <h1>else</h1>
   {% endif %}

</body>
</html>

 

比较运算符 和 布尔运算符

==
!=
<
>
<=
>=

and
or
not
{% if a == 1 %}  # 正确
{% if a==1 %}  # 错误

 

过滤器

语法如下:

  • 使用管道符号|来应用过滤器,用于进行计算、转换操作,可以使用在变量、标签中。
  • 如果过滤器需要参数,则使用冒号:传递参数。

变量|过滤器:参数

列举几个如下:

safe,禁用转义,告诉模板这个变量是安全的,可以解释执行

length,长度,返回字符串包含字符的个数,或列表、元组、字典的元素个数。

default,默认值,如果变量不存在时则返回默认值。

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
   {{ now_date|date:"Y-m-j H:i:s" }}<br/>
</body>
</html>

 

注释

1)单行注释语法如下:

{#...#}

2)多行注释使用comment标签,语法如下:

{% comment %}
...
{% endcomment %}

 

模板继承

父模板

如果发现在多个模板中某些内容相同,那就应该把这段内容定义到父模板中。

标签block:用于在父模板中预留区域,留给子模板填充差异性的内容,名字不能相同。 为了更好的可读性,建议给endblock标签写上名字,这个名字与对应的block名字相同。父模板中也可以使用上下文中传递过来的数据。

{% block 名称 %}
预留区域,可以编写默认内容,也可以没有默认内容
{% endblock  名称 %}

子模板

标签extends:继承,写在子模板文件的第一行。

{% extends "父模板路径"%}

子模版不用填充父模版中的所有预留区域,如果子模版没有填充,则使用父模版定义的默认值。

填充父模板中指定名称的预留区域。

{% block 名称 %}
实际填充内容
{{ block.super }}用于获取父模板中block的内容
{% endblock 名称 %}

 

例:

父模板block 名称

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

{% block index%}
    <h1>父模板</h1>
    {{ now_date|date:"Y-m-j H:i:s" }}<br/>
{% endblock index %}

</body>
</html>

子模板继承父模板

{% extends "index.html" %}  {# 继承父模板 #}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {% block index %}
        <h1>子模板</h1>  {# 子模板实际填充内容 #}
        {{ block.super }} {# 父模板,block里的内容 #}
    {% endblock index %}
</body>
</html>

 

返回:

1558507824(1)_thumb

 

8.中间件

1. 中间件定义

定义一个中间件工厂函数,然后返回一个可以别调用的中间件。

中间件工厂函数需要接收一个可以调用的get_response对象。

返回的中间件也是一个可以被调用的对象,并且像视图一样需要接收一个request对象参数,返回一个response对象。

def simple_middleware(get_response):
    # 此处编写的代码仅在Django第一次配置和初始化的时候执行一次。

    def middleware(request):
        # 此处编写的代码会在每个请求处理视图前被调用。

        response = get_response(request)

        # 此处编写的代码会在每个请求处理视图之后被调用。

        return response

    return middleware

例如:

我们在users应用中新建一个middleware.py文件

image

 

def my_middleware(get_response):
    print('init 被调用')
    def middleware(request):
        print('before request 被调用')
        response = get_response(request)
        print('after response 被调用')
        return response
    return middleware

2 . 我们需要在setting.py中注册中间件,如下:

image

3. 定义一个视图

def demo_view(request):
    print('view 视图被调用')
    return HttpResponse('OK')

 

返回:

image

init被调用了两次

原因:

Django运行在调试模式下,中间件init部分有可能被调用两次。

4. 执行流程

image

 

5. 多个中间件执行顺序

  • 在请求视图被处理,中间件由上至下依次执行
  • 在请求视图被处理,中间件由下至上依次执行

image

def my_middleware(get_response):
    print('init 被调用')
    def middleware(request):
        print('before request 被调用......1')
        response = get_response(request)
        print('after response 被调用.....1')
        return response
    return middleware


def my_middleware2(get_response):
    print('init2 被调用')
    def middleware(request):
        print('before request 被调用.......2')
        response = get_response(request)
        print('after response 被调用......2')
        return response
    return middleware

注册两个中间件

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',
    'users.middleware.my_middleware',  # 添加
    'users.middleware.my_middleware2',  # 添加
]

 

 

返回

image

 

 

总结:

中间件在请求视图被处理,中间件由上至下依次执行

在请求视图被处理,中间件由下至上依次执行

 

注意:如果在manage同级下创建了middleware那么每个APP都会调用这个中间件,意思就是全局的。大笑

 

扩展类方法写中间件:

导入from django.utils.deprecation import MiddlewareMixin, 继承MiddlewareMixin这个类

from django.utils.deprecation import MiddlewareMixin

class my_middleware(MiddlewareMixin):
    def process_request(self, request):
        print("middle_ware1.process_request......111")
    def process_response(self, request, response):
        print("middle_ware1.process_response.......2222")
        return response

返回

image

添加两个中间件试试

返回

image

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯