首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >类视图 中间件和模板

类视图 中间件和模板

作者头像
py3study
发布2020-01-15 20:15:12
8230
发布2020-01-15 20:15:12
举报
文章被收录于专栏:python3python3

模板和类视图

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

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

image_thumb
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]
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]
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
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
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
image

3. 定义一个视图

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

返回:

image
image

init被调用了两次

原因:

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

4. 执行流程

image
image

5. 多个中间件执行顺序

  • 在请求视图被处理,中间件由上至下依次执行
  • 在请求视图被处理,中间件由下至上依次执行
image
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
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

添加两个中间件试试

返回

image
image
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-06-07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档