zoukankan      html  css  js  c++  java
  • Django 视图层和模板层

    一、网站首页和404页面的路由配置

    1. 网站首页路由

    总路由中:
    url(r'^$',视图函数)
    

    2. 404页面

    总路由中:
    
    url(r'',404的视图函数) # 把这一行放在总路由的最后一行即可
    

    二、Django视图层

    1. 小白必会三板斧

    (1)HttpResponse

    (2)render

    (3)redirect

    • 视图函数必须有一个返回值,并且返回值的数据类型必须是HttpResponse对象。(render 和 redirect 方法内部其实最后都是返回的HttpResponse对象)

    2. JsonResponse

    • 导入方法,不同于上面的三板斧:from django.http import JsonResponse

    • HttpResponse会直接返回字符串类型的数据到前端,JsonResponse会返回一个json数据格式的数据到前端。

    (1)前后端分离后数据的交互

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

    (2)前后端序列化和反序列化

    • python后端的序列化

      • json.dumps()
        
    • 前端的JS序列化

      • JSON.stringify()
        
    • python后端的反序列化

      • json.loads()
        
    • 前端的JS反序列化

      • JSON.parse()
        

    (3)python的json模块的特点

    • 在使用json序列化对象时,若对象中含有中文,则会把中文编码成二进制类型。

      • 解决方法:

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

    (4)JsonResponse的序列化特点

    • JsonResponse方法默认是序列化字典用的,如果你想序列化其他数据类型(json模块能够序列化,但是JsonResponse不行) ,你需要加一个safe参数;在使用JsonResponse方法时它内部也是使用json序列化,若对象中含有中文,则会把中文编码成二进制类型。

    • 后端传到前端的json格式数据,前端会直接自动反序列化成JS对象。

    # 阻止JsonResponse把中文自动转码(变量名必须是json_dumps_params) :json_dumps_params={'ensure_ascii':False}
    # 例如:
    return JsonResponse(user_dic,json_dumps_params={'ensure_ascii':False})
    
    # JsonResponse序列化除字典外的其他数据类型 : safe=False
    lis = [1,2,3]
    return JsonResponse(lis,safe=False)
    

    3. FBV与CBV

    (1)FBV(基于函数的视图)

    路由样式:
    
    url(r'^login/',view.login)
    
    视图样式:
    
    def login(request):
        return HttpResponse('登陆成功')
    

    (2)CBV (基于类的视图)

    • CBV能够根据请求方式的不同,自动执行不同的方法。

    • 在python中,函数加括号的执行优先级最高

    路由样式:
    
    url(r'^login/',views.MyLogin.as_view())
    
    ***********在python中,函数加括号的执行优先级最高***************
    在启动django项目时,就会调用as_view()。as_view()的返回值就是view函数,view函数时as_view源码中的方法。所以,上面的url等价于url(r'^login/',views.view)。views.view会在url前面的正则匹配到后调用view函数。
    
    视图样式:
    
    from django.views import View  ********************
    
    class MyLogin(View):  # 继承View类
    	def get(self,request):
    		print('我是MyLogin里面的get方法')
    		return render(request,'login.html')
    
    	def post(self,request):
    		print('我是MyLogin里面的post方法')
    		return HttpResponse('post')
    

    (3)CBV源码的功能流程

    1. 调用url(r'^login/',views.MyLogin.as_view())中的as_view方法,它是类的绑定方法。

    2. as_view方法中,包含一个view方法,形成一个闭包函数,最后把view函数返回出去。

    3. view方法中,实例化一个MyLogin类的对象,再用这个对象调用dispatch方法,最后把dispatch方法的返回值返回出去。

    4. dispatch方法中,判断当前请求方式在不在默认的八个请求方式中,

      若在,则通过对象的反射,得到对应的请求函数地址,最后调用请求函数,把其返回值返回出去。

      若不在,则通过对象调用http_method_not_allowed方法,把其返回值返回出去。

    各部分源码展示:

    #第1部分:
    
    url(r'^login/',views.MyLogin.as_view())
    
    
    # 第2,3部分:
    
    @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
    
    
    # 第4部分:
    
    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方法
    
    

    4. 给CBV加装饰器

    • 给CBV加装饰器,推荐使用内置模块

      1. 需要导入的模块
      from django.utils.decorators import method_decorator
      
      2.使用方式
      
      # (1)给类加  
      @method_decorator(自定义的装饰器名,name='类内部的方法名')
      如:
      @method_decorator(outter,name='post')
      class MyClass(View):
        def post(self,request):
            pass
      
      # (2)直接给类内部的方法装
      
      class MyClass(View):
        @method_decorator(outter)
        def post(self,request):
            pass 
      
      # (3)给类内部所以方法装
      
      要重写dispatch方法,再给dispatch方法装装饰器即可实现。如果你想在视图函数执行之前 做一些操作 你可以在你的CBV中定义dispatch方法来拦截
      
      class MyClass(View):
        @method_decorator(outter)
        def dispatch(self,request,*args, **kwargs):
            return super().dispatch(request,*args,**kwargs)
      
        def post(self,request):
            pass
        
        等价于:
      @method_decorator(outter,name='dispatch')
      class MyClass(View):
       
        def dispatch(self,request,*args, **kwargs):
            return super().dispatch(request,*args,**kwargs)
      
        def post(self,request):
            pass
            
      

    三、Django模板层(即templates的html文件)

    1. 模板语法

    • 只有两种书写格式

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

    2. 给模板传值

    (1)传值的数据类型

    1. python基本数据类型,(整型,浮点型,字符串,列表,元组,字典,集合,布尔值)

    2. 传函数名 {{ func }}

      • 给HTML页面传递函数名的时候,模板语法会自动加括号调用该函数,并且将函数的返回值当做展示的数据
      • 模板语法不支持函数传参,也就意味着,你传给html页面的只能是不需要传参调用的函数,即无参函数和有默认形数的函数
    3. 传类名 {{ MyClass }}

      • 在html文件中,会自动加括号产生对象
    4. 传对象 {{ obj }}

      • 传过来的对象,仍然可以使用对象点属性的方式取值或者调用方法。
    • 总结:只要是正常情况下能够加括号调用的(不包含在定义类是使用__call__),其实就是普通的函数和类,传递到html页面上都会自动加括号调用。

    (2)模板中的取值方式

    • 在django中,它的模板语法只能使用容器类型名 点 的方式来取值(点key值或者点索引值)。

    • 当通过点的方式长度太长,可以通过关键字with给其取一个别名

    • 实例:

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

    (3)给模板传值的方式

    • 给html页面传值的两种方式
    1. 指定道姓 当需要传递的变量名特别多的情况下 有点麻烦

      • render(request,'test.html',{'user_dic':{'user_name':'hsw'}})
        
    2. locals()方法传值

      • locals()会将当前所在名称空间中所有的名字全部传递给html页面

      • render(request,'test.html',locals())
        

    3. 过滤器

    (1)语法结构

    • 就是使用 " | " 
      
      会自动将|左边的数据当前过滤器的第一个参数传入 :右边的当做第二个参数
      
    • 最多只能有两个参数

    (2)各个过滤器

    <p>模板语法之过滤器   会自动将|左边的数据当前过滤器的第一个参数传入 :右边的当做第二个参数</p>
        
    #1.
    <p>统计长度(如果无法统计默认返回0):{{ s|length }}</p>
        
    #2.
    <p>加法运算(内部异常捕获 先强转成数字再相加 ,不行就都转字符串再拼接 都不行就返回空):{{ n|add:f }}</p>
        
    #3.
    <p>切片操作 顾头不顾尾 也支持步长,支持的负数切片:{{ l|slice:'0:5:2' }}</p>
        
    #4.
    <p>判断是否有值(有值展示值本身 没值展示默认值):{{ is_value|default:'is_value变量名指向的值为空' }}</p>
        
    #5.
    <p>自动转成文件大小格式:{{ 给定的文件大小|filesizeformat }}</p>
        
    #6.
    <p>截取文本内容(字符) 截取五个字符 三个点也算:{{ s|truncatechars:8 }}</p>
    
    <p>截取文本内容(按照空格计算) 截取五个单词 三个点不算 :{{ s1|truncatewords:5 }}</p>
        
    #7.
    <p>默认情况下 是不会自动帮你转换成前端html标签,传过来的只是当做字符串处理,为的就是防止恶意攻击</p>
    
    # 前端取消转义(即让传过来的标签能被当做标签处理)
    <p>展示带有标签的文本:{{ sss|safe }}</p>
    
        
    # 后端取消转义(即让传过来的标签能被当做标签处理)
    在后端视图函数中:
    from django.utils.safestring import mark_safe
    	sss2 = "<h2>我的h2标签</h2>"
    	res = mark_safe(sss2)	
        
    前端中:    
    <p>{{ res }}</p>
    
    

    4. 标签,逻辑相关

    (1)if/elif/else

    {% if s %}#}
        <p>s有值</p>
    {% else %}
        <p>s没有值</p>
    {% endif %}
    

    (2)for

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

    (3)for和if 联用

    {% for foo in l %}
        {% if forloop.first %}  # forloop.first第一次循环的时候为True,其他时候为False
            <p>这是我的第一次</p>
        {% elif forloop.last %}  # forloop.last最后一次循环的时候为True,其他时候为False
            <p>这是最后一次了啊</p>
        {% else %}
            <p>{{ foo }}</p>
        {% endif %}
        {% empty %}
             <p>当for循环的对象是空的时候会走</p>
    {% endfor %}
    

    5. 自定义过滤器和标签

    • django支持用户自定义
    • 注意:自定义的过滤器可以在逻辑语句使用,而自定义的标签不可以,会报错

    (1)步骤:

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

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

    3. 在该py文件中 必须先写下面两句代码,之后就可以利用register来自定义过滤器和标签

      from django.template import Library
      register = Library()
      

    (2)自定义过滤器实例:

    
    # 以下自定义的都是在templatetags文件夹中的mytag.py文件中
    
    from django.template import Library
    register = Library()
    
    @register.filter(name='baby')  # 过滤器名称为baby 
    def index(a,b):
    	return a + b
    
    # 自定义过滤器的使用
    {% load mytag %}  # mytag为templatetags文件夹中我们写的自定义过滤器所在的py文件的名字
    {{ 1|baby:1  }}
    {{ 1|baby:100  }}
    

    (3)自定义标签实例:

    • 可以接受任意多个参数
    
    # 以下自定义的都是在templatetags文件夹中的mytag.py文件中
    from django.template import Library
    register = Library()
    
    @register.simple_tag(name='aaa')
    def mytag(a,b,c,d):
    	return f'{a}{b}{c}{d}'
    
    
    # 自定义标签的使用 可以接受多个参数 参数与参数之间必须空格隔开
    {% load mytag %}  # mytag为templatetags文件夹中我们写的自定义过滤器所在的py文件的名字
    {% aaa 'a' 'b' 'c' 'd' %} 
    
    

    (4)自定义inclusion_tag

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

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

    • 实例:

      # 以下自定义的都是在templatetags文件夹中的mytag.py文件中
      # 自定义inclusion_tag
      
      # mytag.html为templates文件夹中的新建html文件 , xxx为该自定义inclusion_tag的别名 
      
      from django.template import Library
      register = Library()
      @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页面
          
      # 自定义inclusion_tag的使用   
      {% load mytag %}  # mytag为templatetags文件夹中我们写的自定义过滤器所在的py文件的名字
      {% xxx 5 %}    
      

    6. 模板的继承

    • 继承的作用:一个页面拥有另一个页面的内容,并在原来的内容上修改某一块区域的内容。

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

    (1)模板继承的步骤

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

    (2)划定的语法

    {% block 该划定区域的名称 %}
    	被划定的区域(标签)
    {% endblock %}
    

    (3)继承的语法

    # 在新页面上也都不需要写,只需下面这些内容即可
    {% extends 'home.html' %}  # 继承home.html页面
    				  
    {% block content %}  # 对home.html页面中划定的content区域做修改
    修改模板中content区域内容
    {% endblock %}
    

    (4)沿用父页面的内容

    
    # 在新页面上也都不需要写,只需下面这些内容即可
    {% extends 'home.html' %}  # 继承home.html页面
    				  
    {% block content %}  # 对home.html页面中划定的content区域做修改
    修改模板中content区域内容
    
    {{ block.super }}  # 继续使用父页面上被划定的content内容,可以使用多次
    
    修改模板中content区域内容
    {% endblock %}
    

    (5)注意

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

    7. 模板的导入

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

    • 语法:

      {% include 'html文件名(带后缀)' %} 
      
    • 模板导入实例:

      {#针对想要修改的区域 做内容的变更#}
      {% block content %}
          
      	<p>我改成reg页面内容</p>
          
          {{ block.super }}
        
           {% include 'bform.html' %}
          
      {% endblock %}
      
  • 相关阅读:
    _bzoj1061 [Noi2008]志愿者招募【最小费用最大流】
    _bzoj2243 [SDOI2011]染色【树链剖分】
    _bzoj1013 [JSOI2008]球形空间产生器sphere【高斯消元】
    _bzoj1002 [FJOI2007]轮状病毒【瞎搞】
    leetcode 273 Integer to English Words
    leetcode 12 Integer to Roman
    leetcode 1071 Greatest Common Divisor of Strings
    lc6 ZigZag Conversion
    lc13 Roman to Integer
    leetcode 171 Excel Sheet Column Number
  • 原文地址:https://www.cnblogs.com/Mcoming/p/11938317.html
Copyright © 2011-2022 走看看