zoukankan      html  css  js  c++  java
  • 1126 视图层与模板层

    昨日内容回顾

    昨日内容回顾
    	表关系的建立方式
    		表与表之间的关系就三种
    			一对一     OneToOne(to='')  # to后面可以跟字符串的表名 也可以直接跟变量名表名(该表名必须在上面提前定义出来)
    			一对多     ForeignKey(to='')
    			多对多     ManyToMany(to='')
    			自己一定要会三种关系的推导步骤 以及建表的注意事项
    			
    			一对一和多对多外键字段 建在哪一方都可以 但是推荐你建在查询频率较高的一方 以便后续的orm查询
    			一对多外键字段 建在多的那一方
    			
    			一对一和一对多外键字段 在创建表的时候回自动加_id后缀 无论你有没有加
    			
    			多对多字段不会在表中创建出来 只是用来告诉orm自动帮你创建第三张表
    			能够方便后续orm查询操作	
    	
    	django请求生命周期流程图
    		
    
    	路由层
    		url方法第一个参数是一个正则表达式
    		匹配的特点:只要正则表达式能够匹配到内容 那么会立刻结束匹配 直接执行后面所对应的视图函数
    		正是由于该特点会出现,当你的项目特别庞大的时候 可能会出现url被顶替的现象(test testadd)
    		如果出现上述情况
    			1.修改正则表达式
    			2.将下面的放到上面去
    		
    		django在路由匹配的时候默认有一个补救机制
    		当你的url没有正常匹配到 django会让浏览器自动加斜杠再来匹配一次(重定向)
    		配置文件中有一个参数用来控制该机制是否允许
    		APPEND_SLASH = True/False
    			
    		网站首页可以使用的匹配方式
    		# 网站首页
    		url(r'^$',home),
    		# 网站404页面的设计(了解)
    		url(r'',error)
    		
    		
    		
    	路由匹配
    	
    	无名分组
    		给正则表达式加括号分组 在路由匹配成功之后调用视图函数的时候
    		会将括号内正则表达式匹配到的内容当做位置参数传递给视图函数
    		url(r'^index/(d+)/',index)   # index(request,d+内容)
    	
    	有名分组
    		给正则表达式加括号分组并起别名 在路由匹配成功之后调用视图函数的时候
    		会将括号内正则表达式匹配到的内容当做关键字传递给视图函数
    		url(r'^index/(?P<year>d+)/',index)   # index(request,year=d+内容)
    	
    		注意事项 无名有名不能混合
    		但是单个情况下 可以使用多次
    		
    	反向解析
    		本质:根据别名 动态解析出一个结果 该结果可以直接访问到别名所对应的url
    		没有正则表达式符号
    			url(r'^index/',views.index,name='xxx')
    			
    			前端
    				{% url 'xxx' %}  # index/
    			后端
    				from django.shortcuts import reverse
    				reverse('xxx')  # index/
    		出现正则表达式符号
    			# 无名分组
    			url(r'^index/(d+)/',views.login,name='yyy')
    			# index/数字/
    			前端
    				{% url 'yyy' 数字 %}  # index/数字/
    			后端
    				reverse('xxx',args=(数字,))
    				# 只要是容器类型 内部就算只有一个元素 你也给我习惯性的把分隔符逗号加上
    				
    			# 有名分组
    				# 你可以直接使用无名分组的方式即可
    				前端
    				{% url 'yyy' 名字=数字 %}  # index/数字/
    			后端
    				reverse('xxx',keargs={'名字':数字})
    	
    	路由分发
    		前提
    			所有的app都可以有自己独立的urls.py templates模板文件夹 static静态文件夹
    			正是由于该特点 使得基于django实现多人开发 非常的方便
    			每个人只需要开发自己的app即可 
    		
    		路由分发
    			总路由不再直接做路由与视图函数对应关系了
    			而是仅仅做一个转发的功能
    			好处:更加的解耦合 更加好维护
    			from django.conf.urls import url,include
    			
    			url(r'^应用名1/',include('应用名1.urls'))
    			url(r'^应用名2/',include('应用名2.urls'))	
    	
    	名称空间
    		当不同的应用中给路由与视图对应关系起了相同的别名
    		在反向解析的时候 并不能直接识别到是哪个应用下的
    		url(r'^应用名1/',include('应用名1.urls',namespace='应用名'))
    		
    		{% url '应用名1:相同的别名' %}
    		{% url '应用名2:相同的别名' %}
    		
    		reverse('应用名1:相同的别名')
    		reverse('应用名2:相同的别名')
    		
    		# 其实你完全可以不适用名称空间
    		# 你只需要保证在起别名的时候不要出现冲突即可 建议做法就是加	应用前缀_别名
    	
    	虚拟环境
    		给每一个项目提供一个专门属于该项目自己的所需模块
    		避免浪费 节省资源
    		requirement.txt
    			django==1.11.11
    			Flask==1.4
    		建议不要频繁的开设虚拟环境
    		
    	django版本区别
    		path与url
    		path第一个参数不支持正则 如果你还想使用正则 你可以re_path跟你的url一模一样
    		
    		path虽然不支持正则 但是提供了五个默认的转换器 能够自动帮你转换数据类型
    		
    		还支持用户自定义转换器(不要记忆 直接拷贝即可)
    	
    	request方法获取文件数据
    		request.FILES  获取form表单上传的文件数据
    		
    		file_obj = request.FILES.get('myfile')
    		file_obj.name  文件名
    		
    		f = open(file.obj.name,'wb')
    		for chunk in file_obj.chunks():  # for line in file_obj:
    			f.write(chunk)
    		f.close()
    

    一. 视图层

    路由配置主页与404

    路由层:
    from django.urls import path, re_path
    urlpatterns = [
        # 主页最上方配置
        re_path('^$', root, name="root"),
        re_path('^index/$', index),
        re_path('^home/$', home),
    
        # 其他路由...
    
        # 404配在最下方
        re_path('/$', error)
    ]
    视图层:
    from django.shortcuts import render, redirect, reverse  # 需要导入
    # 主页
    def root(request):
        return render(request, 'root.html')
    def index(request):
        return redirect(reverse('root'))   # reverse括弧中跟的参数为路由的别名
    def home(request):
        return redirect(reverse('root'))
    # 404
    def error(request):
        return render(request, 'error.html')
    
    # redirect: 返回的参数可以可以是:
    # 一个模型: 将调用模型的get_absolute_url()函数;
    # 一个视图, 可以带有函数: 可以使用urlresolvers.reverse来反向解析名称;
    # 一个绝对的或相对的URL, 将原封不动的作为重定向的位置.
    # redirect("/index/") | redirect("http:127.0.0.1:8000/index/")
    

    1. 三大板斧

    HTTPresponse

    返回字符串

    render

    返回HTTP文件,及字典形式的变量

    原理实现
    def login(request):
    	res = Template('<h1> {{user}} <h1>')
        con = Context({'user':{'username':'Jason','password':'123'}})
        return HttpResponse(res.render(con))
    

    redirect

    标签重定向

    视图函数必须有一个返回值 并且返回值的数据类型必须是HttpResponse对象
    

    2. JsonResponse对象

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

    from django.http import JsonResponse
    
    response = JsonResponse({'foo': 'bar'})
    print(response.content)
    
    b'{"foo": "bar"}'
    

    默认只能传递字典类型,如果要传递非字典类型需要设置一下safe关键字参数。

    response = JsonResponse([1, 2, 3], safe=False)
    

    基础

    前后端数据交互 该如何进行?

    前后端分离         
    通常情况下前后端数据交互采用的都是json的字符串(字典)   
    后端只需要写好相应的url接口 前端访问你这个接口    
    你只需要返回一个大字典即可 + 开发文档   
    用来告诉前端工程师 你这个接口能够返回哪些数据 
    

    前后端序列化反序列化使用哪些方法

        python后端             	js
    				
        json.dumps             JSON.stringify
    
    
        json.loads             JSON.parse
    

    视图函数返回json格式的字符串

    def index(request):
        user_dic = {'name':'jason好帅哦 我好喜欢~','password':'123'}	
    
    

    直接传至前端会乱码 'u',#

    json转码

    如何让json不自动帮你对中文进行转码ensure_ascii=False

        json_str = json.dumps(user_dic,ensure_ascii=False)
        return HttpResponse(json_str)
    
    

    使用JsonResponse直接return

    return JsonResponse(user_dic,json_dumps_params={'ensure_ascii':False})
    
    
    

    safe序列化字典之外

    默认序列化字典

    l = [1,2,3,4,5,6,7,]
    # JsonResponse默认是序列化字典用的 如果你想序列化其他数据类型(json模块能够序列化的) 你需要加一个safe参数
    return JsonResponse(l,safe=False)	
    
    

    3. FBV与CBV

    定义

    FBV:function base views 函数方式完成视图响应
    CBV:class base views 类方式完成视图响应

    CBV

    导入

    视图层中
    from django.views import View
    
    

    使用

    定义一个类

    CBV能够根据请求方式的不同执行不同的函数(get,post)

    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())
    
    

    CBV源码分析

    思考:为什么CBV能够根据请求方式的不同 自动执行不同的方法???

    1.url(r'^login/',views.MyLogin.as_view())

    这是个类方法,直接加括号调用,项目启动自动执行
    
    # 访问属性和方法
    # 方法就是函数(函数名加括号执行优先级最高)
    # 项目一启动 会自动执行as_view方法
    
    

    2.点进去as_view()方法中

    发现返回的是内部函数的函数名 
    也就是 url(r'^login/',views.view())
    说明CBV本质上也就是FBV
    
    

    img

    3.as_view()执行时

    • 也就是执行自己内部的view方法,
    • 给self赋值了cls是我们自己写的类 MyLogin self是我们自己定义的类的对象
    • view方法return了dispatch()方法
    @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
    
    

    img

    4.找到dispatch()方法

    • 方法获得当前的请求方式,然后判断请求方式在不在8大请求方式中
    • 在 的话通过反射将get反射查找自己类的属性方法并赋值给handler
      • return 出去 handler()
    • 不在 调用报错函数:http_method_not_allowed请求方式不合法!
    def dispatch(self, request, *args, **kwargs):
    
        # 判断当前请求方式在不在默认的八个方法内
        # 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方法
    
    

    img

    装饰器

    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")
    
    

    CBVmethod_decorator

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

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

    # CBV版添加装饰器
    from django.views import View
    from django.utils.decorators import method_decorator
    
    class AddClass(View):
    
        @method_decorator(wrapper)
        def get(self, request):
            return render(request, "add_class.html")
    
        def post(self, request):
            class_name = request.POST.get("class_name")
            models.Classes.objects.create(name=class_name)
            return redirect("/class_list/")
    
    

    方式一:

    在方法上直接写装饰器
    
    

    方式二:

    导入,给类直接加装饰器
    from django.utils.decorators import method_decorator
    
    1.函数上
    @method_decorator(装饰器名)
    def 函数():
    	pass
    	
    2.类上指定
    @method_decorator(装饰器名,name='函数名')
    class 类名:
    	pass
    
    

    方式三:

    一次性给类一起装,给dispatch()方法装

    • 如果你想在视图函数执行之前 做一些操作 你可以在你的CBV中定义dispatch方法来拦截
    @method_decorator(装饰器名,name:dispatch)
    class Mylogin(view):
        def dispatch(self, request, *args, **kwargs):  
            return super().dispatch(request,*args,**kwargs)
    
    

    补充知识点

    django settings源码
    
    基于settings源码 应用到我们自己的项目中去
    
    

    4. request对象

    1. method: 请求方式  #request.method
    2. GET: get请求的参数  #request.GET.get("k")
    3. POST: post请求的参数(本质是从bdoy中取出来)  #request.POST.get("k")
    4. body: post提交的数据(不能直接查看)
    5. path: 请求的路径,不带参数
    6. request.get_full_path(): 请求路径,带参数
    7. FILES: 文件数据
    8. encoding: 编码格式
    9. META: 数据大汇总的字典
    
    

    二. 模板层

    官方文档

    1. 常用语法

    只需要记两种特殊符号:

    • 变量相关 {{ }}
    • 逻辑相关 {% %}

    2. 变量

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

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

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

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

    注意事项:

    1. 如果计算结果的值是可调用的,它将被无参数的调用。 调用的结果将成为模版的值。
    2. 如果使用的变量不存在, 模版系统将插入 string_if_invalid 选项的值, 它被默认设置为'' (空字符串) 。

    几个例子:

    def template_test(request):
        l = [11, 22, 33]
        d = {"name": "alex"}
    
        class Person(object):
            def __init__(self, name, age):
                self.name = name
                self.age = age
    
            def dream(self):
                return "{} is dream...".format(self.name)
    
        Alex = Person(name="Alex", age=34)
        Egon = Person(name="Egon", age=9000)
        Eva_J = Person(name="Eva_J", age=18)
    
        person_list = [Alex, Egon, Eva_J]
        return render(request, "template_test.html", {"l": l, "d": d, "person_list": person_list})
    
    

    模板中支持的写法:

    {# 取l中的第一个参数 #}
    {{ l.0 }}
    {# 取字典中key的值 #}
    {{ d.name }}
    {# 取对象的name属性 #}
    {{ person_list.0.name }}
    {# .操作只能调用不带参数的方法 #}
    {{ person_list.0.dream }}
    
    

    3. 模板传值

    方法locals()

    第一种:

    • 直接传值,指名道姓,使用字典,变量多的时候会很麻烦
    • return render(request,'text.html',{'n':n})

    第二种:

    • 使用locals()方法
    • return render(request,'text.html',locals())

    类型

    python基本数据类型全部支持传值
    
    

    函数

    • 自动加括号调用函数
    • 返回值做前端展示
    • 不支持传参
    <p>传函数名:{{ index1 }}
    
    给HTML页面传递函数名的时候 
    模板语法会自动加括号调用该函数 
    并且将函数的返回值当做展示依据
    
    模板语法不支持函数传参 也就意味着 
    你传给html页面的只能是不需要传参调用的函数
    </p>
    
    

    • 传类名自动加括号实例化对象
    • 传对象,可以调用.方法
    • 只要能加括号调用的,传到html,都会自动加括号调用
    <p>传类名:{{ MyClass }}
    			自动加括号实例化产生对象</p>
    			
    <p>传对象:{{ obj }}</p>
    <p>{{ obj.get_self }}</p>
    <p>{{ obj.get_cls }}</p>
    <p>{{ obj.get_func }}</p>
    
    <p>总结:只要是能够加括号调用的 传递到html页面上都会自动加括号调用</p>
    
    

    4. 过滤器|

    模板语法也给你提供了一些内置的方法 帮你快速的处理数据
    最多只能有两个参数
    
    会自动将:
        '|'左边的数据当做过滤器的第一个参数传入 
        ':'右边的当做第二个参数
    
    

    定义

    在Django的模板语言中,通过使用 过滤器 来改变变量的显示。

    • 过滤器的语法: {{ value|filter_name:参数 }}
    • 使用管道符"|"来应用过滤器。

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

    注意事项:

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

    语法

    -- {{ 变量|过滤器1[[:参数]|...|过滤器n[:参数]] }}
    -- 注:过滤器可以串联操作,可以拥有0个或1个参数
    

    常见内置filter

    -- 增加   add:num
    -- 字符串长度   length
    -- 默认值   default:'默认值'  # 变量不存在或为空
    -- 全大写   upper
    -- 全小写   lower
    -- 切片   slice:'0:-1'
    -- 将数字转换为文件大小   filesizeformat
    -- 字符串隐藏   truncatechars:13   # 只显示10个字符,后置字符都用...来替代
    -- 时间   date:'Y-m-d'
    -- 转换原意   safe
    

    使用

    1. 统计长度 length

      {{s|length}}

    2. 加法运算 add

      {{n|add:666}} 加法运算(内部异常捕获 支持数字相加 字符串拼接 都不符合返回空)

    3. 切片操作 slice

      {{list|slice:'0:5:2'}} 顾头不顾尾 也支持步长

    4. 判断是否有值 default

      {{is_value|default:'is_value变量名指向为空时展示'}} 判断是否有值(有值展示值本身 没值展示默认值)

    5. 转换文件 filesizeformat

      {{ file_size|filesizeformat }} 自动转成文件大小格式

    6. 截取文本内容 truncatechars:num

      {{ s|truncatechars:8 }} 截取文本内容(字符) 截取8个字符 三个点也算

    7. 按空格截取文本 truncatewords:num

      {{ s1|truncatewords:5 }} 截取文本内容(按照空格计算) 截取五个单词 三个点不算

    8. 默认是不会自动转换html标签的,防止恶意攻击 safe

      1. 前端使用

        safe 展示带有标签的文本:{{ sss|safe }}

      2. 后端使用

        mark_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标签 防止恶意攻击</p>#}
    {#<p>展示带有标签的文本:{{ sss|safe }}</p>#}
    {#<p>展示带有标签的文本:{{ sss1|safe }}</p>#}
    
    {{ 123|add:"5" }} 给value加上一个数值
    {{ "AB'CD"|addslashes }} 单引号加上转义号,一般用于输出到javascript中
    {{ "abcd"|capfirst }} 第一个字母大写
    {{ "abcd"|center:"50" }} 输出指定长度的字符串,并把值对中
    {{ "123spam456spam789"|cut:"spam" }} 查找删除指定字符串
    {{ value|date:"F j, Y" }} 格式化日期
    {{ value|default:"(N/A)" }} 值不存在,使用指定值
    {{ value|default_if_none:"(N/A)" }} 值是None,使用指定值
    {{ 列表变量|dictsort:"数字" }} 排序从小到大
    {{ 列表变量|dictsortreversed:"数字" }} 排序从大到小
    {{ string|escape }} 转换为html实体
    {{ 21984124|filesizeformat }} 以1024为基数,计算最大值,保留1位小数,增加可读性
    {{ list|first }} 返回列表第一个元素
    {{ "ik23hr&jqwh"|fix_ampersands }} &转为&
    {{ 13.414121241|floatformat }} 保留1位小数,可为负数,几种形式
    {{ 13.414121241|floatformat:"2" }} 保留2位小数
    {{ 23456 |get_digit:"1" }} 从个位数开始截取指定位置的1个数字
    {{ list|join:", " }} 用指定分隔符连接列表
    {{ list|length }} 返回列表个数
    {% if 列表|length_is:"3" %} 列表个数是否指定数值
    {{ "ABCD"|linebreaks }} 用新行用
    {{ "ABCD"|linebreaksbr }} 用新行用 标记包裹
    {{ 变量|linenumbers }} 为变量中每一行加上行号
    {{ "abcd"|ljust:"50" }} 把字符串在指定宽度中对左,其它用空格填充
    {{ "ABCD"|lower }} 小写
    {{ "abcdefghijklmnopqrstuvwxyz"|phone2numeric }} 把字符转为可以对应的数字??
    {{ 列表或数字|pluralize }} 单词的复数形式,如列表字符串个数大于1,返回s,否则返回空串
    {{ 列表或数字|pluralize:"es" }} 指定es
    {{ 列表或数字|pluralize:"y,ies" }} 指定ies替换为y
    {{ object|pprint }} 显示一个对象的值
    {{ 列表|random }} 返回列表的随机一项
    {{ string|removetags:"br p div" }} 删除字符串中指定html标记
    {{ string|rjust:"50" }} 把字符串在指定宽度中对右,其它用空格填充
    {{ 列表|slice:":2" }} 切片
    {{ string|slugify }} 字符串中留下减号和下划线,其它符号删除,空格用减号替换
    {{ 3|stringformat:"02i" }} 字符串格式,使用Python的字符串格式语法
    {{ "EABCD"|striptags }} 剥去[X]HTML语法标记
    {{ 时间变量|time:"P" }} 日期的时间部分格式
    {{ datetime|timesince }} 给定日期到现在过去了多少时间
    {{ datetime|timesince:"other_datetime" }} 两日期间过去了多少时间
    {{ datetime|timeuntil }} 给定日期到现在过去了多少时间,与上面的区别在于2日期的前后位置。
    {{ datetime|timeuntil:"other_datetime" }} 两日期间过去了多少时间
    {{ "abdsadf"|title }} 首字母大写
    {{ "A B C D E F"|truncatewords:"3" }} 截取指定个数的单词
    {{ "111221"|truncatewords_html:"2" }} 截取指定个数的html标记,并补完整
    {{ list|unordered_list }} 多重嵌套列表展现为html的无序列表
    {{ string|upper }} 全部大写
    {{ string|urlize }} 将URLs由纯文本变为可点击的链接。(没有实验成功)
    {{ string|urlizetrunc:"30" }} 同上,多个截取字符数。(同样没有实验成功)
    {{ "B C D E F"|wordcount }} 单词数
    {{ "a b c d e f g h i j k"|wordwrap:"5" }} 每指定数量的字符就插入回车符
    {{ boolean|yesno:"Yes,No,Perhaps" }} 对三种值的返回字符串,对应是 非空,空,None
    

    前后端的取消转义

    前端   
    
    |safe
    
    后端   
    
    from django.utils.safestring import mark_safe   
    sss2 = "<h2>我的h2标签</h2>"   
    res = mark_safe(sss2)  
    
    

    5.逻辑相关

    标签

    1.语法:
        -- {% 关键词 arg1 ... argn %}  eg: {% url 'test' 1 2 3 %} => /test/1/2/3/
    ​
    2.常用:
        -- 反向解析url   {% url 'namespace:url_name' arg1 arg2 %}
        -- 当前时间now   {% now 'Y-m-d' %}
        -- 起别名with   {% with '后面的别名flag就代表我' as flag %} {{ flag }} {% endwith %}
        -- Django CSRF认证   {% csrf_token %}
    
    

    for循环

    普通for循环

    <ul>
    {% for user in user_list %}
        <li>{{ user.name }}</li>
    {% endfor %}
    </ul>
    
    

    forloop

    img

    Variable Description
    forloop.counter 当前循环的索引值(从1开始)
    forloop.counter0 当前循环的索引值(从0开始)
    forloop.revcounter 当前循环的倒序索引值(从1开始)
    forloop.revcounter0 当前循环的倒序索引值(从0开始)
    forloop.first 当前循环是不是第一次循环(布尔值)
    forloop.last 当前循环是不是最后一次循环(布尔值)
    forloop.parentloop 本层循环的外层循环
    {% for foo in l %}
        {% if forloop.first %}
                <p>这是我的第一次</p>
            {% elif forloop.last %}
                <p>这是最后一次了啊</p>
            {% else %}
                <p>{{ foo }}</p>
        {% endif %}
        {% empty %}
        	<p>当for循环的对象是空的时候会走</p>
    {% endfor %}
    
    

    for ... empty

    <ul>
    {% for user in user_list %}
        <li>{{ user.name }}</li>
    {% empty %}
        <li>空空如也</li>
    {% endfor %}
    </ul>
    
    

    if判断

    {% if user_list %}
      用户人数:{{ user_list|length }}
    {% elif black_list %}
      黑名单数:{{ black_list|length }}
    {% else %}
      没有用户
    {% endif %}
    
    

    当然也可以只有if和else

    {% if user_list|length > 5 %}
      七座豪华SUV
    {% else %}
        黄包车
    {% endif %}
    
    

    if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。

    with

    定义一个中间变量,多用于给一个复杂的变量起别名。

    注意等号左右不要加空格。

    {% with total=business.employees.count %}
        {{ total }} employee{{ total|pluralize }}
    {% endwith %}
    
    

    {% with business.employees.count as total %}
        {{ total }} employee{{ total|pluralize }}
    {% endwith %}
    
    

    模板语法的取值

    只有一种方式  统一采用句点符  (.)
    <p>{{ comp_dic.hobby.2.2.age }}</p>
    
    

    6.自定义过滤器和标签

    步骤

    1. 在应用名下新建一个名字必须叫templatetags的文件夹

    2. 在给文件夹内,新建一个任意名称的py文件

    3. 在该py文件中 必须写以下两句代码

      from django.template import Library
      register = Library()
      
      
    4. 然后就可以利用register来自定义过滤器和标签了

    使用

    自定义过滤器需要加载

    {% load 过滤器名 %}
    
    

    自定义过滤器

    和默认的过滤器一样,最多只能接受两个参数
    
    @register.filter(name='bady')
    def index(a,d):
    	return a+b
    
    

    自定义标签

    可以接受任意多个参数
    
    @register.simple_tag(name='mytag')
    def mytag(a,b,c,d):
    	return '%s?%s?%s?%s'%(a,b,c,d)
    
    

    特点

    自定义的过滤器可以在逻辑语句中使用,而自定义的标签不可以

    {% if mytag '1' '2' '3' '4' %}
        <p>有值</p>
        {% else %}
        <p>无值</p>
    {% endif %}
    
    

    自定义inclusion_tag

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

    使用

    • 当你需要使用一些页面组件的时候
    • 并且该页面组件需要参数才能够正常渲染
    • 你可以考虑使用inclusion_tag
    {% load mytag %}
    {% xxx 5 %}
    
    

    代码

    @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页面
    
    

    7. 模板的继承

    • 事先在想要继承的页面上通过block划定可能要改的区域
    • 继承的时候,在子页面上先继承extends
    • 利用block自动提示 选择你想要修改的内容区域

    划定区域

    {% block content %}
    {% endblock %}
    
    先在页面上利用block划定你以后可能想改的区域
    
    

    继承

    继承之后,就可以通过名字找到对应的区域进行修改

    {% extends 'home.html' %}
    
    {% block content %}
    修改模板中content区域内容
    {% endblock %}
    
    

    特点

    模板上的block区域越多 页面的扩展性越强
    建议你一个模板页面至少有三块区域
    
    1. css区域		
    2. html代码区域  可以设置多个block
    3. js区域
    
    有了这三块区域 就能够实现每一个页面都有自己独立的css和js代码
    
    

    8.模板的导入

    将html页面当做模块直接导入使用

    {% include 'bform.html' %}
    
    

    一、include标签 -- 模板导入

    使用前提:多个页面有一个相同的页面版块时(多个有样式标签的集合体)

    如何运用:可以将多个样式标签的集合进行封装,对外提供板块的名字(接口),在有该板块的页面中直接导入即可

    语法:{% include '板块页面的路径' %}

    • 公共的页面板块
    <!-- templates/public.html -->
    <!-- 该页面位公共的页面代码块,所以不需要完整的html页面结构 -->
    <div class="public">
        <!-- 公用页面板块的详细html代码 -->
    </div>
    
    
    • 公告页面板块的样式
    /* static/css/public.css */
    /* 该样式文件是为公告页面代码块提供页面布局的css样式 */
    .public {
        /* 具体的css样式块 */
    }
    
    
    • 使用公告板块的页面们
    <!-- 拥有公共页面板块的 templates/first.html -->
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>first</title>
        <link rel="stylesheet" href="/static/css/public.css">
    </head>
    <body>
    <!-- 该页面的其他html代码块 -->
        
    <!-- 加载相同的页面板块 -->
    {% include 'public.html' %}
        
    <!-- 该页面的其他html代码块 -->
    </body>
    </html>
    
    <!-- 拥有公共页面板块的 templates/second.html -->
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>second</title>
        <link rel="stylesheet" href="/static/css/public.css">
    </head>
    <body>
    <!-- 该页面的其他html代码块 -->
        
    <!-- 加载相同的页面板块 -->
    {% include 'public.html' %}
        
    <!-- 该页面的其他html代码块 -->
    </body>
    </html>
    
    

    二、inclusion_tag自定义标签

    使用前提:与include标签出现的页面需求很类似,但是这些不是完全相同的板块,因为板块内的细节不是完全一致

    如何使用:

    1. 先封装相似的页面标签结果,为数据不同而页面标签个数不同的地方采用Django模板语言写活(数据决定了最终标签个数);
    2. 自定义inclusion_tag,将封装的页面文件都给inclusion_tag装饰器,自定义的函数的参数为不同的数据,函数的返回值就是用关键词形式将参数返回;
    3. 在拥有该相似板块的页面中导入自定义tag,并使用自定义tag传入具体实参即可。

    • 自定义inclusion_tag
    # app/templatetags/owen_tags.py
    
    from django.template import Library
    register = Library()
    
    @register.inclusion_tag('public_tag.html')
    def header_list(list):
        return {'list': list}
    
    
    • 公共类似的页面板块
    <!-- templates/public_tag.html -->
    <!-- 该页面位公共的页面代码块,所以不需要完整的html页面结构 -->
    <ul class="public_tag">
        <!-- 公用页面板块的详细html代码 -->
        {% for foo in list %}
        <li>{{ foo }}</li>
        {% endfor %}
    </ul>
    <!-- 注:拥有该公共页面代码块的页面会为其提供存放不同数据的 list变量  -->
    
    
    • 使用公告板块的页面们
    <!-- 拥有公共页面板块的 templates/first_tag.html -->
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>first_tag</title>
    </head>
    <body>
    <!-- 该页面的其他html代码块 -->
        
    <!-- 加载共同类似的页面板块 -->
    {% load owen_tags %}
    {% with [1, 2, 3, 4, 5] as list %}
        {% header_list list %}
    {% endwith %}
        
    <!-- 该页面的其他html代码块 -->
    </body>
    </html>
    
    <!-- 拥有公共页面板块的 templates/second_tag.html -->
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>second_tag</title>
    </head>
    <body>
    <!-- 该页面的其他html代码块 -->
        
    <!-- 加载共同类似的页面板块 -->
    {% load owen_tags %}
    {% with [10, 30, 50] as list %}
        {% header_list list %}
    {% endwith %}
        
    <!-- 该页面的其他html代码块 -->
    </body>
    </html>
    
    

    三、母版

    前提:多个页面的多个板块相同或相似,只有少部分板块是自己独有的,将共有的部分全部提出封装,包含了页面大部分版块结构,所以我们称呼其为 母版。
    如何运用:
    1. 先封装母版:大部分版块相同或相似的base.html,在特点的位置留出响应的block接口;
    2. 每个需要运用母版页面的页面来继承母版 {% extends '母版页面的路径' %};
    3. 在自己页面中的任意位置书写block中自身独有的页面内容 {{% block block名 %} ... {% endblock %}};
    4. 如果需要继承母版block中原有的内容,使用 {{ block.super }} 来获取。

    • 公共的母版页面
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>{{ title }}</title>
        <link rel="stylesheet" href="/static/css/base.css">
        {% block style %}
            {# 为继承该母版的页面引入自身样式文件通过的block #}
        {% endblock %}
    </head>
    <body>
    <!-- 母版有有大量的共同板块 -->
    <!-- 母版有有大量的共同板块 -->
        
    <!-- 母版有有大量的共同板块 -->
    {% block own %}
        {# 为继承该母版的页面提供书写自己页面独有内容的block #}
    {% endblock %}
        
    <!-- 母版有有大量的共同板块 -->
    <!-- 母版有有大量的共同板块 -->
    </body>
    </html>
    
    
    • 页面样式文件均放在static/css中,每个html文件按需导入自己的css文件
    /* static/css/base.css */
    /* static/css/login.css */
    /* static/css/register.css */
    
    
    • 继承母版的login页面
    {% extends 'base.html' %}
    
    {% block style %}
    <link rel="stylesheet" href="/static/css/login.css">
    {% endblock %}
    
    {% block own %}
    <div class="login">登录页面独有的登录板块</div>
    {% endblock %}
    
    
    • 继承母版的register页面
    {% extends 'base.html' %}
    
    {% block own %}
    <div class="register">注册页面独有的注册板块</div>
    {% endblock %}
    
    {% block style %}
    <link rel="stylesheet" href="/static/css/register.css">
    {% endblock %}
    
    <!-- 继承母版的页面通过替换母版留出的block块,来实现自己页面独有的板块 -->
    <!-- 替换block块的顺序随意 -->
    
  • 相关阅读:
    MD5加密Java实现
    一直以来有个问题我没有解决,现在知道了
    从最近一次Struts 2 的漏洞看Web安全
    Android与Struts2、Hibernate打造社交平台
    Android与服务器端交互
    大二生活总结
    throttle_classes 60秒访问10次限制
    restframework流程
    django-admin有用的设置
    django-ckeditor设置
  • 原文地址:https://www.cnblogs.com/fwzzz/p/11939157.html
Copyright © 2011-2022 走看看