• django 之视图层及模板层 04



    路由:视图函数的内存地址

    视图层

    render方法是Template和Contex两个对象的组合使用

    from django .template import Template,Context
    def func1(request):
        res = Template('<h1>{{user}}</h>')
        con=Context({'user':{'username':'zhang','password':123,}})
        return HttpResponse(res.render(con))
    

    JsonResponse对象

    JsonResponse是HttpResponse的子类,专门用来生成JSON编码的响应。

    # ensure_ascii=False 默认等于True,设置成False,遇到中文不再进行转码,仅仅只是进行序列化,转换成json形式的字符串
    import json
    def func(request):
        d={'a':1,'b':3,'c':3,'d':4,'e':'速度发货!!!!!!!'}
        return HttpResponse(json.dumps(d,ensure_ascii=False),)  # 
    
    
    from django.http import JsonResponse
    def func(request):
        d={'a':1,'b':3,'c':3,'d':4,'e':'速度发货!!!!!!!'}
        l=[1,2,3,4,5,]
       # return JsonResponse(d)  # 加括号是个对象,内部也是基于json.dumps进行的序列化,默认遇到中文也会转成ASCII编码,
    	# return JsonResponse(d,json_dumps_params={'ensure_ascii':False})  # 遇到中文不转码
    	return JsonResponse(l,safe=False)  # In order to allow non-dict objects to be serialized set the safe parameter to False.  根据报错信息,去源码找到JsonResponse不能序列化其他数据类型的原因,就是修改safe=True 为False,之后就能序列化其他数据类型(json模块能序列化的)了
    

    CBV及源码分析

    我们之前写过的都是基于函数的view,就叫FBV。还可以把view写成基于类的。
    FBV:基于函数的视图
    CBV:基于类的视图

    from django.views import View
    
    class MyLogin(View):
        def get(self,request):
            print('我是MyLogin里面的get方法')
            return render(request,'login.html')
    
        def post(self,request):
            print('我是MyLogin里面的post方法')
            return HttpResponse('post')
    
        # 路由的书写 与CBV有点不同
        # FBV写法     路由 >>> 视图函数内存地址
        url(r'^index/',views.index),
        # CBV写法
        url(r'^login/',views.MyLogin.as_view())  # views.view  本质也是FBV
    
    	 http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
        
         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())
        
        @classonlymethod
        def as_view(cls, **initkwargs):
            def view(request, *args, **kwargs):  # 闭包函数
                self = cls(**initkwargs)  # cls是我们自己写的类 MyLogin  self是我们自己定义的类的对象
                # 在看源码的时候 你一定要把握住一个顺序 对象在查找属性和方法的时候
                # 先从对象自身找 再去产生对象的类中找 再去类的父类中找
                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.
            # 判断当前请求方式在不在默认的八个方法内
            # 1.先以GET请求为例
            if request.method.lower() in self.http_method_names:
                # 利用反射去我们自己定义类的对象中查找get属性或者是方法  getattr(obj,'get')
                # handler = get方法
                handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
                else:
                    handler = self.http_method_not_allowed
                    return handler(request, *args, **kwargs)  # 调用get方法
    

    CBV 加装饰器的方式

    使用装饰器装饰FBV
    FBV本身就是一个函数,所以和给普通的函数加装饰器无差:

    def wrapper(func):
        def inner(*args, **kwargs):
            start_time = time.time()
            ret = func(*args, **kwargs)
            end_time = time.time()
            print("used:", end_time-start_time)
            return ret
        return inner
    
    
    # FBV版添加班级
    @wrapper
    def add_class(request):
        if request.method == "POST":
            class_name = request.POST.get("class_name")
            models.Classes.objects.create(name=class_name)
            return redirect("/class_list/")
        return render(request, "add_class.html")
    

    CBV 加装饰器的方式

    类中的方法与独立函数不完全相同,因此不能直接将函数装饰器应用于类中的方法 ,我们需要先将其转换为方法装饰器。

    Django中提供了method_decorator装饰器用于将函数装饰器转换为方法装饰器

    #使用CBV时要注意,请求过来后会先执行dispatch()这个方法,如果需要批量对具体的请求处理方法,如get,post等做一些操作的时候,这里我们可以手动改写dispatch方法,这个dispatch方法就和在FBV上加装饰器的效果一样。

    给CBV加装饰器 推荐你使用内置模块
    from django.utils.decorators import method_decorator
    
    # 2.可以指定给谁装
    # @method_decorator(wrapper,name='post')  # name=... 表示指定给谁装
    # @method_decorator(wrapper,name='dispatch')
    class MyLogin(View):
        @method_decorator(wrapper)
        def dispatch(self, request, *args, **kwargs):  # 如果你想在视图函数执行之前 做一些操作 你可以在你的CBV中定义dispatch方法来拦截
    
            return super().dispatch(request,*args,**kwargs)
        # @outter  # 1.直接写
        # @method_decorator(outter)  # 1.推荐写法
        def get(self,request):
            print('我是MyLogin里面的get方法')
            return render(request,'login.html')
        # @outter
        def post(self,request):
            print('我是MyLogin里面的post方法')
            time.sleep(1)
            return HttpResponse('post')
    
    

    模板层

    模板语法传值

    模板语法

    		只有两种书写格式:
    			{{}}  变量相关
    			{%%}  逻辑相关
    
    		模板传值:python基本数据类型全部支持传值
    

    变量

    在Django的模板语言中按此语法使用:{{ 变量名 }}。

    当模版引擎遇到一个变量,它将计算这个变量,然后用结果替换掉它本身。 变量的命名包括任何字母数字以及下划线 ("_")的组合。 变量名称中不能有空格或标点符号。

    点(.)在模板语言中有特殊的含义。当模版系统遇到点("."),它将以这样的顺序查询:

    字典查询(Dictionary lookup)
    属性或方法查询(Attribute or method lookup)
    数字索引查询(Numeric index lookup)

    注意事项:

    1. 如果计算结果的值是可调用的,它将被无参数的调用。 调用的结果将成为模版的值。
    2. 如果使用的变量不存在, 模版系统将插入 string_if_invalid 选项的值, 它被默认设置为'' (空字符串)
    # test.py文件
    def test(request):
        n=1
        f=1.11
        s='hello baby~'
        l=[1,2,3,4,]
        t=(1,2,3,44,55)
        d={'name':'zhangsan','hobby':'read'}
        se={12,13,14,15,}
        b=False
        def index1():  #给HTML页面传递函数名的时候 模板语法会自动加括号调用该函数 并且将函数的返回值当做展示依据,模板语法不支持函数传参 也就意味着 你传给html页面的只能是不需要传参调用的函数
            return '都是废话'
        class Test(object):
            def get_self(self):
                return 'get_self'
        obj = Test()
        return render(request,'test.html',locals())
    
    # 传类名像函数名一样,也是加括号调用,实例化一个对象;传对象,就是对象本身,是类的对象的内存地址;只要是能够加括号调用的 传递到html页面上都会自动加括号调用
    
    <!--test.html文件-->
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <link rel="stylesheet" href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    
    </head>
    <body>
    <p>{{ n }}</p>
    <p>{{ f }}</p>
    <p>{{ s }}</p>
    <p>{{ l }}</p>
    <p>{{ se }}</p>
    <p>{{ d }}</p>
    <p>{{ b }}</p>
    <p>传函数名:{{ index1 }}</p>
    <p>传函数名:{{ Test }}</p>   
    <p>传函数名:{{ obj }}</p>  
    </body>
    </html>
    

    过滤器(Filters)

    模板语法也给你提供了一些内置的方法 帮你快速的处理数据
    过滤器的语法: {{ value|filter_name:参数 }}

    例如:{{ name|lower }}会将name变量应用lower过滤器之后再显示它的值。lower在这里的作用是将文本全都变成小写。

    注意事项:

    1.过滤器支持“链式”操作。即一个过滤器的输出作为另一个过滤器的输入。
    2.过滤器可以接受参数,例如:{{ sss|truncatewords:30 }},这将显示sss的前30个词。
    3.过滤器参数包含空格的话,必须用引号包裹起来。比如使用逗号和空格去连接一个列表中的元素,如:{{ list|join:', ' }}
    4.'|'左右没有空格没有空格没有空格

    前后端取消转义(*)

    
    前端
    	|safe
    后端
    from django.utils.safestring import mark_safe
    sss2 = "<h2>我的h2标签</h2>"
    res = mark_safe(sss2)
    
    <p>统计长度(如果无法统计默认返回0):{{ s|length }}</p>
    <p>加法运算(内部异常捕获 支持数字相加 字符串拼接 都不符合返回空):{{ n|add:f }}</p>
    <p>切片操作 顾头不顾尾 也支持步长:{{ l|slice:'0:5:2' }}</p>
    <p>判断是否有值(有值展示值本身 没值展示默认值):{{ is_value|default:'is_value变量名指向的值为空' }}</p>
    <p>自动转成文件大小格式:{{ file_size|filesizeformat }}</p>
    <p>截取文本内容(字符) 截取五个字符 三个点也算:{{ s|truncatechars:8 }}</p>
    <p>截取文本内容(按照空格计算) 截取五个字符 三个点不算 :{{ s1|truncatewords:5 }}</p>
    <p>默认情况下,不会转换成前端html标签 :{{sss}}</p>  # 后端传来的字符串类型的标签
    <p>展示带有标签的文本:{{ sss|safe }}</p> 添加safe参数之后可以转换后端传来的字符串标签
    <p>展示带有标签的文本:{{ ss|safe }}</p>  后端: ss='<script>alert(123)</script>'
    
    

    标签

    标签 逻辑相关
    if
    for循环

    {% for foo in l %}
    	{{ forloop }}
    	{% if forloop.first %}
    		<p>{{ foo }}</p>
    	{% elif forloop.last %}
    	{% else %}
    		<p>{{ foo }}</p>
    	{% endif %}
    	{% empty %}
    		<p>档for循环的对象为空的时候走这个!</p>
    {% endfor %}
    

    模板语法的取值 只有一种方式 统一采用句点符 (.)

    {{ comp_dic.hobby.2.2.age }}

    <p>当你的数据是通过比较复杂的点点点获取到的后续又需要经常使用 你可以给该数据起别名 别名只能在with内部使用</p>
    {% with comp_dic.hobby.2.2.age as age  %}    
    	<p>{{ age }}</p>
    	<p>{{ comp_dic.hobby.2.2.age }}</p>
    {% endwith %}
    

    自定义过滤器和标签

    自定义过滤器

    django支持用户自定义
    必须要先有三部准备
    1.在应用名下新建一个名字必须叫templatetags的文件夹
    2.在该文件夹内 新建一个任意名称的py文件
    3.在该py文件中 必须先写下面两句代码
    from django.template import Library
    register = Library()

    			之后就可以利用register来自定义过滤器和标签
    
    # 应用名下templatetag文件夹 mytag.py文件
    from django.template import Library
    register = Library()
    # 自定义过滤器,跟默认的过滤器一样,最多只能接受两个参数
    @register.filter(name='xxx') # 给过滤器起名字
    def index(a,b):
        return a+b
    

    使用自定义的过滤器,需要先在html页面上 加载。

    <!--test.html文件-->
    {% load mytag %}
    {{ 1|xxx:99 }}
    

    自定义标签

    # 应用名下templatetag文件夹 mytag.py文件
    
    # 自定义标签   可以接受任意多个参数
    @register.simple_tag(name='zzz')
    def mytag(a,b,c,d):
        return '%s?%s?%s?%s'%(a,b,c,d)
    
    <!--test.html文件-->
    {% load mytag %}
    {% zzz 'a' 'b' 'c' 'd' %}
    
    <!--test.html文件-->
    <p>自定义的过滤器可以在逻辑语句使用 而自定义的标签不可以</p>
    {% if 1|xxx:99 %}
        <p>有值</p>
    {% else %}
        <p>无值</p>
    {% endif %}
    

    自定义inclusion_tag

    是一个函数 能够接受外界传入的参数, 然后传递给一个html页面,页面上获取数据 渲染完成之后,将渲染好的页面放到调用inclusion_tag的地方

    # 应用名下templatetag文件夹 mytag.py文件
    # 自定义inclusion_tag
    @register.inclusion_tag('mytag.html',name='xxx')
    def index666(n):
        l = []
        for i in range(n):
            l.append('第%s项'%i)
        return locals()  # 将l直接传递给mytag.html页面
    
    <!--mytag.html文件-->
    <!--只做临时渲染的页面,所以该页面的其他框架部分html代码就不需要了-->
    <ul>
        {% for foo in l %}
            <li>{{ foo }}</li>
        {% endfor %}
    </ul>
    
    <!--test.html文件-->
    <p>自定义inclusion_tag的使用  当你需要使用一些页面组件的时候 并且该页面组件需要参数才能够正常渲染 你可以考虑使用inclusion_tag</p>
    {% load mytag %}
    {% xxx 5 %}
    

    模板的继承

    你需要事先在你想要使用的页面上划定区域,之后在继承的时候 ,你就可以使用你划定的区域,也就意味着,如果你不划定任何区域,那么你将无法修改页面内容。

    <!--先在页面上利用block划定你以后可能想改的区域-->
    {% block content %}
    {% endblock %}
    
    <!--继承之后  就可以通过名字找到对应的区域进行修改-->
    {% extends 'home.html' %}
    
    {% block content %}
    <!--修改模板中content区域内容-->
    {% endblock %}
    			
    

    模板上的block区域越多 页面的扩展性越强
    建议你一个模板页面至少有三块区域:
    	css区域
        html代码区域  可以设置多个block
        js区域
    有了这三块区域 就能够实现每一个页面都有自己独立的css和js代码
    
    
    {% extends 'home.html' %}  子文件就可以通过这个方法继承猪文件的html代码的格式
    {% block css %}
    <style>
        p {
            color: green;
        }
    </style>
    {% endblock %}
    
    {% block content %}
    <p>login页面</p>
    {% endblock %}
    
    {% block js %}
    <script>
        alert('login')
    </script>
    {% endblock %}
    
    你还可以在子页面上继续沿用父页面的内容
    		{{ block.super }}
    

    模板的继承
    1.先在你想要继承的页面上通过block划定你将来可能要改的区域
    2.在子页面上先继承extends
    3.利用block自动提示 选择你想要修改的内容区域

    模板的导入

    将html页面当做模块的直接导入使用
    	{% include 'bform.html' %}
    

    下一篇:django之模型层

  • 相关阅读:
    第十八章 文件传输协议
    第十七章 DNS原理
    第三十六章 Linux常用性能检测的指令
    学习日报
    连接数据库综合实例
    异常处理动手动脑
    Css实例之信息提交
    JDBC编程
    将文本文件写入数据库并使用数据库读取
    Java学习
  • 原文地址:https://www.cnblogs.com/zhangchaocoming/p/11939438.html
Copyright © 2020-2023  润新知