51、request几个方法、CBV 与FBA、CBV源码剖析、模版层

124 阅读7分钟

request对象的几个方法

1.request.path:获取url地址的路径部分,只包含路径部分
2.request.path_info
3.request.get_full_path()  获取url地址的完整path,既包含路径又包含参数部分
4.request.body   浏览器发过来的二进制数据
def index(request,a):
    print('hello')
    print(request.path)  # /index/
    print(request.path_info) # /index/
    print(request.get_full_path()) # /index/   /index/?username=kevin
    print(request.body) # b''
    return render(request,'index.html')

CBV和FBV

1.CBV:class based views:在视图中写类
2.FBV:function based views:在视图中写函数
3.怎样在视图中写类:
		1.urls.py:url(r'正则',类名.as_view())
        urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^MyLogin/', views.MyLogin.as_view())]
    
    2.views.py:导模块--类必须继承View---有get、post函数(分别代表get请求,post请求)
        from django.views import View
        class MyLogin(View):
            def get(self,request): # 通过get请求方式会访问到这个方法
                return HttpResponse('get请求')
            def post(self,request):  # 通过post请求方式会访问到这个方法 
                return HttpResponse('post请求')
             
4.第三方工具:postman(在官网下载)、apizz(网页版,不需要下载,注册登陆即可)            

CBV源码剖析

1.看源码:首先先找入口---CBV入口:路由  as_view()
2.views.MyLogin.as_view()---分析:类调用方法
	  1.类来调用方法:
        1. 被@classmethod装饰器修饰的方法
        2. 被@staticmethod装饰器修饰的方法
    我们在MyLogin类中并没有写as_view(), 可能会在父类中
3.鼠标+contrl点进去:
    @classonlymethod
    def as_view(cls, **initkwargs):
        for key in initkwargs:
						pass
        def view(request, *args, **kwargs):
          	self = cls(**initkwargs) # self = MyLogin()
          	return self.dispatch(request, *args, **kwargs)
        return view
4.推论:
		1.
		views.MyLogin.as_view()--->View类里面的as_view方法中得view方法的内存地址
		views.MyLogin.as_view()--->本质也是函数的内存地址
    2.当请求来了,会自定触发view函数的执行---->会触发view()函数    

分析view返回值--self.dispatch(request, *args, **kwargs)

    def dispatch(self, request, *args, **kwargs):
        if request.method.lower() in self.http_method_names:
        # self.http_method_names-->对象自己查找-类里查找--父类里查找(http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'])
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)

分析返回值:handler(request, *args, **kwargs)

    def dispatch(self, request, *args, **kwargs):
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)  # getattr():获取对象字符串对应得属性(handler =getattr(self, 'get'))----->get函数的内存地址
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)

需求:我写的这个类只允许get请求,怎么做?

class MyLogin(View):
    http_method_names = ['get', 'post']
    def get(self, request):
        return HttpResponse('get')
    def post(self, request):
        return HttpResponse('post')

模版层

简单来说,模版层就是html文件,在html文件里面django给你提供了一些模版语法,是html自身不自带的

模版的变量分配

1.模版里面的取值一律使用点语法(eg:列表取值)
2.{{ }}   变量相关 
  {% %}  逻辑相关 
3.在模版语法里,函数的使用不需要加括号,直接使用函数名,会自动调用 ps:不能传参

例子

1.
def foo(request):
    dic1 = {'name':'123','gender':'female'}
    a = {'b':1}
    # return render(request,'foo.html',context={'userdic':dic1,'aa':a})
    return render(request,'foo.html',locals())
  
2.
    # foo.html
    {{ a }}
    {{ b }}
    {{ c }}
    {{ d }}
    {{ d.0 }}
    {{ e }}
    {{ e.name }}
    {{ f }}
    {{ g }}
    {{ h }}

    # views.py
    def foo(request):
        a = 1
        b = 1.2
        c = True
        d = [1,2,3,4]
        e = {'name':'123','gender':'female'}
        f ={1,2,3,4}
        g = 'hello world'
        h = (1,2,3,4)
        return render(request,'foo.html',locals())

    # 浏览器
    1 1.2 True [1, 2, 3, 4] 1 {'name': '123', 'gender': 'female'} 123 {1, 2, 3, 4} hello world (1, 2, 3, 4)
    
    
3.函数:函数的时候,不需要加括号,直接使用函数名,它会自动给你加括号调用--不可传参
    # foo.html
    {{ func }}
    
    # views.py
    def func():
      return 'func'
    return render(request,'foo.html',locals())
  
    # 浏览器
      func

模版之过滤器

1.django提供的过滤器:filter__name
2.语法:
		{{obj|filter__name:param}}  变量名字|过滤器名称:变量

常用过滤器

1.default:默认值
		作用:如果一个变量值是False或者为空、None,使用default后指定的默认值,否则,使用变量本身的值,如果value=’‘则输出“nothing”
		{{ value|default:"nothing" }}

2.default_if_none
		作用:如果只针对value是None这一种情况来设置默认值,需要使用default_if_none
				只有在value=None的情况下,才会输出“None...”,
		{{ value|default_if_none:"None..." }}

3.length:长度
		作用:返回值的长度。它对字符串、列表、字典等容器类型都起作用,如果value是 ['a', 'b', 'c', 'd'],那么输出是4
		{{ value|length }}

4.filesizeformat:转换人类可读的文件大小
		作用:将值的格式化为一个"人类可读的"文件尺寸(如13KB、4.1 MB、102bytes等等),如果 value 是 12312312321,输出将会是 11.5 GB
		{{ value|filesizeformat }}

5.date:格式化日期(时间戳不可)
		作用:将日期按照指定的格式输出,如果value=datetime.datetime.now(),按照格式Y-m-d则输出2019-02-02
		{{ value|date:"Y-m-d" }}  

7.slice:切字符串
		作用:对输出的字符串进行切片操作,顾头不顾尾,如果value=“egon“,则输出"eg"
{{ value|slice:"0:2" }} 

8.truncatechars:截取
		作用:如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾,如果value=”hello world egon 嘎嘎“,则输出"hello...",注意8个字符也包含末尾的3个点
		{{ value|truncatechars:8 }}

9.truncatewords
		作用:同truncatechars,但truncatewords是按照单词截断,注意末尾的3个点不算作单词,如果value=”hello world egon 嘎嘎“,则输出"hello world ..."
{{ value|truncatewords:2 }}
                            
10.safe:渲染标签--xss攻击、sql注入 csrf 密码加盐(安全相关)
    1.                       
    s1 = '<h1>hello</h1>'                       
    {{ s1|safe }}                        
    2.
			后端:导模块 from django.utils.safestring import mark_safe
      from django.utils.safestring import mark_safe
      s1 = mark_safe('<h1>hello</h1>')

模版之标签

for循环

1.快捷键:for+tab--自动不全
  {% for foo in l1 %}

  {% endfor %}
  
2.基本使用
  {% for foo in l1 %}
  <p>{{ foo }}</p>
  {% endfor %}
forloop
1.
  {% for foo in l1 %}
  <p>{{ forloop }}</p>
  {% endfor %}
  
  >>>{'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 7, 'revcounter0': 6, 'first': True, 'last': False}
  
2.counter0:索引;counter:计数;first:第一个值; last:最后一个值
    1.forloop.counter:当前循环的索引值(从1开始)
    2.forloop.counter0:当前循环的索引值(从0开始)
    3.forloop.revcounter:当前循环的倒序索引值(从1开始)
    4.forloop.revcounter0:当前循环的倒序索引值(从0开始)
    5.forloop.first:当前循环是不是第一次循环(布尔值)
    6.forloop.last:当前循环是不是最后一次循环(布尔值)
    7.forloop.parentloop:本层循环的外层循环
遍历字典
  # views.py
    def fun(request):
        # l1 = [1,2,3,4,5,6,7]
        dic = {'name':'nana','kwd':123,'gender':'female'}
        return render(request,'fun.html',locals())
  # fun.html
    {% for foo in dic.values %}
    {{ foo }}
    {% endfor %}

    {% for foo1 in dic.items %}
    {{ foo1 }}
    {% endfor %}

    {% for foo2 in dic.keys %}
    {{ foo2 }}
    {% endfor %}
  # 浏览器
    nana 123 female ('name', 'nana') ('kwd', 123) ('gender', 'female') name kwd gender
for...empty --为空执行
1.for标签可以带有一个可选的{% empty %} 从句,在变量person_list为空或者没有被找到时,则执行empty子句
2.
  {% for person in person_list %}
      <p>{{ person.name }}</p>

  {% empty %}
      <p>sorry,no person here</p>
  {% endfor %}

了解:Django框架的for循环,没有break和continue方法,可以使用自定义过滤器实现forloop | continue和forloop | break,参考:djangosnippets.org/snippets/20…

if标签

1.{% if 条件 %}条件为真时if的子句才会生效,条件也可以是一个变量,if会对变量进行求值,在变量值为空、或者视图没有为其传值的情况下均为False

2.具体语法
  {% if num > 100 or num < 0 %}
      <p>无效</p>
  {% elif num > 80 and num < 100 %}
      <p>优秀</p>
  {% else %}
      <p>凑活吧</p>
  {% endif %}

3.if语句支持 andor、==、>、<、!=、<=、>=、innot inisis not判断。

with--起别名

1.ith标签用来为一个复杂的变量名起别名,如果变量的值来自于数据库,在起别名后只需要使用别名即可,无需每次都向数据库发送请求来重新获取变量的值
2.
    l1 = [1,2,3,4,4,[1,2,3,{'name':'nana'}]]
  
    {% endif %}
    {% with l1.5.3.name as v %}
        {{ v }}
    {% endwith %}

csrf_token标签

1..当用form表单提交POST请求时必须加上标签{% csrf_token %},该标签用于防止跨站伪造请求--就可以配置文件:一行的csrf不注释
  <form action="" method="POST">
      {% csrf_token %}
      <p>用户名:<input type="text" name="name"></p>
      <p>密码:<input type="password" name="pwd"></p>
      <p><input type="submit" value="提交"></p>
  </form>
  
2.具体工作原理为:
    1、在GET请求到form表单时,标签{% csrf_token%}会被渲染成一个隐藏的input标签,该标签包含了由服务端生成的一串随机字符串,如<input type="hidden" name="csrfmiddlewaretoken" value="dmje28mFo...OvnZ5">
    2、在使用form表单提交POST请求时,会提交上述随机字符串,服务端在接收到该POST请求时会对比该随机字符串,对比成功则处理该POST请求,否则拒绝,以此来确定客户端的身份
    

模版的继承和导入

模版的继承

需求:模仿x-admin做一个后台管理页面

1.{% extends 'home.html' %}  ---继承home的页面
2.改部分页面内容---在home页面标记
    {% block content %}   ----contend 只是命的名字
      ....
    {% endblock %}
3.在其他页面改被标记的内容
	{% block content %}
			....
	{% endblock %}
  
4. 一个模板页面中应该至少有3块内容可以被替换
    1. css
    2. js
    3. html

4.1 在模版页面head标签内写 
    {% block css %}
        <style>
        </style>
    {% endblock %}
    
4.2 在模版页面body标签内写
    {% block js %}
        <script>
        </script>
    {% endblock %}
    
4.3 在需要修改的页面里写
    {% block css %}
        <style>
    			...
        </style>
    {% endblock %}
    
      {% block js %}
        <script>
        ...
        </script>
    {% endblock %}
    

模版的导入

1.{% include 'welcom.html' %}------>想要导入的页面写