五:django CBV部分源码,模板语言

CBV源码解析

# 突破口在 urls.py
url(r'^login/',views.MyLogin.as_view())
# url(r'^login/',views.view) CBV本质上与FBV是一致的


@classonlymethod   # 类方法
    def as_view(cls, **initkwargs):
        ...
        # cls就是我们自己定义的类MyLogin

        def view(request, *args, **kwargs):  # 闭包函数
            self = cls(**initkwargs)
            # self = MyLogin(**initkwargs) 类实例化产生一个对象
            ...
            self.request = request
            self.args = args
            self.kwargs = kwargs
            return self.dispatch(request, *args, **kwargs) # 调用分发函数
        ...
        return view
    
    
# 看一下调用的分发函数
 def dispatch(self, request, *args, **kwargs):
        """
        http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] 一共有8种请求方式
        """
        # 获取请求方式的小写,然后与http_method_names里面的请求方式匹配匹配,如果请求方式不存在则logger.warning,若存在,则判断对象是否有该方法,比如self是MyLogin对象,有get和post方式,当请求方式为“POST”或“GET”时,能够匹配到get或post,handler=get 或者 handler=post 则返回get(request,*args, **kwargs)或post(request,*args, **kwargs)
        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)
    
# 看一下http_method_not_allowed
    def http_method_not_allowed(self, request, *args, **kwargs):
        logger.warning(
            'Method Not Allowed (%s): %s', request.method, request.path,
            extra={'status_code': 405, 'request': request}
        )
        return http.HttpResponseNotAllowed(self._allowed_methods())

image-20201107230505367

image-20201107231102405

image-20201107232329700

模板语法的传值

"""
{{}}:变量相关
{% %}:逻辑相关
"""

慢板语法可以传递给前端的数据类型

def index(request):
    buf_size = 1024
    pi = 3.1415926
    str_1 = 'jason实锤海王渣男'
    is_admin = True
    beast = ['egon','jason','alex','tank']
    t = (1,23,45)
    user_info = {'name':'egon','age':18,'gender':'female'}
    s = {'python','go','linux'}
    return render(request,'index.html',locals())

index.html

<body>
<p>{{ buf_size }}</p>
<p>{{ pi }}</p>
<p>{{ str_1 }}</p>
<p>{{ is_admin }}</p>
<p>{{ beast }}</p>
<p>{{ t }}</p>
<p>{{ user_info }}</p>
<p>{{ s }}</p>
</body>

img

"""
由上图可知,模板语法支持python的基本数据类型,那么,是否支持函数与类了
"""

    def func():
        x = 1
        y = 4
        return x if x > y else y

    class Beast(object):
        @staticmethod
        def get_name():
            return 'egon'

        def get_age(self):
            return self

        @classmethod
        def class_name(cls):
            return 'cls'

        def __str__(self):
            return '渣男jason'
    p = Beast()

    return render(request, 'index.html', locals())

"""
4         调用func()

渣男jason  p 触发__str__方法

渣男jason  执行get_age(),返回对象,触发__str__方法

cls       执行class_name()

egon      执行get_name()

渣男jason  实例化对象Beast(),触发__str__方法
"""

img

小节:

"""
模板语法:
(1)支持python的所有基本数据类型;
(2)支持函数,类,对象
(3)传递函数名会自动加括号调用(但是模版语法不支持给函数传额外的参数)
(4)传类名的时候也会自动加括号调用(实例化)
(5)内部能够自动判断出当前的变量名是否可以加括号调用 如果可以就会自动执行  针对的是函数名和类名
"""

django模板语法的取值是才用“句点符”的方式
可以点键,也可以点索引,也可以两者混合使用
exp:
    {{ beast.name }}
    {{t.1}}
    {{b.0.hobby.2 }}

过滤器(过滤器最多只能有两个参数)

"""
过滤器:就相当于模板语法的内置函数
"""

基本语法格式:
{{数据|过滤器:参数}}

注意:
"""
过滤器最多接收两个参数:管道符号前一个,管道符号后面一个
比如 {{current_time|date:'Y-m-d H:i:s'}}
"""

过滤器safe起到保护作用可以起到页面的保护作用

后端来实现:
from django.utils.safestring import mark_safe


def index(request):
    res = mark_safe('<h3>egon一米五</h3>')
    return render(request, 'index.html', locals())

<p>转义:{{ res }}</p>
    
    
前端来实现:
def index(request):
    res = '<h3>egon一米五</h3>'
    return render(request, 'index.html', locals())

<p>转义:{{ res|safe }}</p>

常用的几种过滤器

<p>统计长度:{{ beast|length }}</p>
<p>默认值(第一个参数是布尔值是True就展示第一个参数的值,否则就展示default的值):{{ user_info.is_female|default:"你说的都对"}}</p>
<p>文件大小:{{ file_size|filesizeformat }}</p>
<p>日期格式化:{{ now_str|date:'Y-m-d H:i:s' }}</p>
<p>切片操作(支持步长):{{ beast|slice:'0:3:2' }}</p>
<p>切取字符(包含三个点):{{ message|truncatechars:18 }}</p>
<p>切取单词(不包含三个点,按空格切):{{ content|truncatewords:3 }}</p>     """三个点不参与单词的切取"""
<p>移除指定的字符串:{{ content|cut:' ' }}</p>
<p>拼接操作:{{ beast|join:'$' }}</p>
<p>拼接操作(加法):{{ file_size|add:1024}}</p>
<p>拼接操作(加法):{{ content|add:'heh' }}</p>
<p>转义:{{ str_1|safe }}</p>
<p>转义:{{ str_2|safe }}</p>
<p>转义:{{ str_3 }}</p>
    
"""
import datetime
from django.utils.safestring import mark_safe

def index(request):
    file_size = 10240000
    now_str = datetime.datetime.now()
    beast = ['egon', 'jason', 'alex', 'tank']
    message = "2013年2月,正式推出百度翻译手机客户端。"
    content = "呵呵 你好呀 我来了 怎么样 还好吗"
    user_info = {'name': 'egon', 'age': 18, 'is_female': True}
    str_1 = 'Hello world!'
    str_2 = '<h3>咪咪</h3>'
    str_3 = mark_safe('<h2>敏敏</h2>')
    return render(request, 'index.html', locals())

"""

img

常用的几个标签

  • for循环
{% for item in machine %}
    <p>{{ forloop }}</p>
    <p>{{ item }}</p>
{% endfor %}

img

  • if判断
{% if b %}
    <p>baby</p>
{% elif s%}
    <p>都来把</p>
{% else %}
    <p>老baby</p>
{% endif %}


# if和for混合使用

{% for foo in lll %}
    {% if forloop.first %}
        <p>这是我的第一次</p>
    {% elif forloop.last %}
        <p>这是最后一次啊</p>
    {% else %}
        <p>{{ foo }}</p>
    {% endif %}
    {% empty %}
        <p>for循环的可迭代对象内部没有元素 根本没法循环</p>
{% endfor %}

# 处理字典的方法

{% for foo in d.keys %}
    <p>{{ foo }}</p>
{% endfor %}
{% for foo in d.values %}
    <p>{{ foo }}</p>
{% endfor %}
{% for foo in d.items %}
    <p>{{ foo }}</p>
{% endfor %}

empty表示,for循环的可迭代对象内部没有元素时,执行的分支。

  • with起别名

with语法内就可以通过as后面的别名快速的使用到前面非常复杂获取数据的方式

{% with d.hobby.3.info as nb  %}
    <p>{{ nb }}</p>
    在with语法内就可以通过as后面的别名快速的使用到前面非常复杂获取数据的方式
    <p>{{ d.hobby.3.info }}</p>
{% endwith %}

自定义过滤器&标签&inclusion_tag

创建并使用自定义过滤器filter、标签simple_taginclusion_tag的流程完全一致。

主要分为以下三个步骤:

  1. 在应用app01创建一个名为templatetags 的文件夹
  2. templatetags文件夹下创建任意名字的py文件,如mytag.py
  3. mytag.py文件中做如下设置:
from django import template

register = template.Library()

自定义过滤器

@register.filter(name='mydate')   # 过滤器的名字mydate
def my_date(time_str):       # 传参 time_str = now_str
    import time
    return time.strftime('%Y-%m-%d %H:%M:%S')

使用index.html
{% load mytag %}    # 先导入模块的名字,这里是mytag
<p>自定义过滤器:{{ now_str|mydate }}</p>

注意:自定义过滤器内置过滤器一样,最多只能接收2个参数;

自定义标签simple_tag

功能:simple_tag自定义过滤器的功能一致,都是接收视图层传递过来的数据进行进一步的处理。

不同的是simple_tag可以接收多个参数

@register.simple_tag(name='connect')
def connect(x, y, z, h):
    process_list = [x, y, z, h]
    return '$'.join(process_list)

{% load mytag %}
<p>{% connect 'jason' 'is' '海王' '渣男' %}</p>

自定义inclusion_tag

功能:将数据和html页面绑在一起,传给模版文件。数据一般是视图层从数据库里面取出的;html页面一般是模版文件的局部页面。

内部实现原理:

先定义一个方法 
	在页面上调用该方法 并且可以传值
	该方法会生成一些数据然后传递给一个html页面
	之后将渲染好的结果放到调用的位置

left_menu.html

<ul>
    {% for foo in data %}
        <li>{{ foo }}</li>
    {% endfor %}

</ul>

mytag.py

@register.inclusion_tag('left_menu.html')
def left(n):
    data = ['第{}项'.format(i) for i in range(n)]
    return locals()

index.html

{% left 8 %}

小节:

局部left_menu.html页面,仅仅是书写局部的html语句,在这里面接收left方法的返回值,形成了一个绑定数据的html页面。

模版文件中使用标签left的位置处,渲染这个绑定了数据的left_menu.html页面。

总结:当html页面某一个地方的页面需要传参数才能够动态的渲染出来,并且在多个页面上都需要使用到该局部 那么就考虑将该局部页面做成inclusion_tag形式

模板的继承

目的:减少模板文件代码的冗余量。相同的部分继承使用,不同的部分自己定制。

具体的实现:

  • 提前在父模板中规划好子模板需要自定制的区域,该操作不会影响父模板的内容。
{% block content %}
	模版内容
{% endblock %}
  • 在子模版中,继承父模版,此时会子模版会完全继承父模版,两者的页面内容完全一样。
{% extends 'home.html' %}
  • 子页面就可以声明想要修改哪块划定了的区域。
{% block content %}		         # 自定制名字为'content'的区域
	子页面内容	
{% endblock %}

一般情况下,模版页面上应该至少有三块可以被修改的区域

"""
1.css区域
2.html区域
3.js区域
"""

{% block css %}

{% endblock %}
  
{% block content %}

{% endblock %}
  
{% block js %}

{% endblock %}

# 每一个子页面就都可以有自己独有的css代码 html代码 js代码
#一般情况下 模版的页面上划定的区域越多 那么该模版的扩展性就越高

模板的导入

功能:将页面的某一个局部当成模块的形式,哪个地方需要就可以直接导入使用即可。

{% include 'side_bar.html' %}
posted @ 2020-11-08 16:31  为了等  阅读(69)  评论(0编辑  收藏  举报