Django视图层和模板层

视图层

网页伪静态(了解)
1.从URL结构以及页面名称看,伪静态和静态页面是一样的。伪静态的页面后缀可以是html,htm或者是目录格式。
2.伪静态只是改变了URL的表现形式,实际上还是动态页面。
3.静态页面可以节省服务器资源,而伪静态严格说是增加服务器资源消耗的。
4.在SEO方面,伪静态和静态页面的功能是相同的,但是伪静态本质上还是动态页面,所以消耗资源是和动态页面一样的,而且因为Rewrite服务器还需要消耗额外的资源。
# 通过写入网页的后缀名将动态网页伪装成静态网页,让服务器误以为这个网页不会经常改变,从而提升网页被搜索引擎收录的概率。表现形式就是网址看着像是一个具体的文件路径

 path('index.html',views.index)
视图函数的返回值
'''视图函数必须返回一个HttpResponse对象''' 
代码验证一下:
def func(request):
     pass
	 
报错信息看下图

image

通过查看HttpResponse源码发现HttpResponse是个类
 class HttpResponse(HttpResponseBase):
     pass

image

那么此时就有一个疑问,同样是django三板斧,视图函数返回值为什么只能返回HttpResponse,而不是另外两个render和redirect呢?
先看看render的源码:
def render(request):
     return HttpResponse(content, content_type, status)
	 
# 通过查看源码发现 render是一个函数,但是!它的返回值是HttpResponse。函数名加括号执行优先级最高,由此可推出render返回值也是一个HttpResponse对象

image

那么再看看redirect的源码来验证上面的结论是否正确
 def redirect(to, *args, permanent=False, **kwargs):
      redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
      return redirect_class(resolve_url(to, *args, **kwargs))

# 此时只能看出redirect是一个函数,再去查看它的返回值源码
class HttpResponsePermanentRedirect(HttpResponseRedirectBase):
    status_code = 301
# 再去查看返回值继承的类
class HttpResponseRedirectBase(HttpResponse):
     pass
'''查看返回值继承的类发现,redirect的返回值继承的元类是HttpResponse类,那么由此可以推导出redirect的返回值返回的也是HttpResponse对象'''

image

image

jsonResponse方法
视图函数返回json格式数据
# 使用import json模块写代码
def func(request):
    d1 = {'name': 'summer哈哈哈', 'age': 18}
    json_str = json.dumps(d1,ensure_ascii=False)
    return HttpResponse(json_str)

运行结果:{"name": "summer哈哈哈", "age": 18}
# 使用django封装的模块JsonResponse
from django.http import JsonResponse
def func(request):
    d1 = {'name': 'summer哈哈哈', 'age': 18}
    return JsonResponse(d1,json_dumps_params={'ensure_ascii':False})

运行结果:{"name": "summer哈哈哈", "age": 18}

image

# 通过查看JsonResponse源码推导出 json_dumps_params可以接收ensure_ascii:False

推导过程:
1.JsonResponse继承了HttpResponse ,也就是当JsonResponse加括号的时候就是实例化了一个对象,对象的第一个参数是self是自己,第二个参数data是括号内是数据,也就是上述字典
2.直接看data赋值符号的右边,是json.dumps把data数据转为json格式,括号内的参数有一个**json_dumps_params
3.在__init__括号内有一个参数json_dumps_params=None,然后再看下面的if判断 if json_dumps_params is None:,json_dumps_params = {}。由此可以推导出,**json_dumps_params是可以接收这种形式的参数ensure_ascii:False
# json格式化非字典类型数据
def func(request):
    l1 = [1,1,1,1,12,2,2,2]
    return JsonResponse(l1,safe=False)
# 通过报错提示,我们可以直接看到其他格式的编写参数

image

form表单携带文件数据

form表单想要携带文件数据的话,前端必须具备两个条件
1.method属性必须是post
2.enctype属性值必须是multipart/form-data
  # form表单默认的是 enctype="application/x-www-form-urlencoded" 这种模式不支持携带文件
后端获取文件:
  request.FILES
代码实操:
def userfile(request):
    if request.method == 'POST':
       # print('request.POST',request.POST) 
       print('request.FILES',request.FILES) 
       file_obj = request.FILES.get('file')  # 如果有多个文件就用getlist
       with open(file_obj.name,'wb')as f:
           for line in file_obj:
               f.write(line)

没有写enctype="multipart/form-data"
image
写了enctype="multipart/form-data"
image

FBV与CBV
在django框架中,视图层中的逻辑即可以使用函数处理也可以使用类进行处理:
FBV(function base views) 就是在视图里使用函数处理请求。
  def index(request):
       return HttpResponse()
path('index/',views.index)
CBV(class base views) 就是在视图里使用类处理请求。
  from django import views
  class myView(views.View):
     def get(self, request):
        return HttpResponse('我是get里面的views')
     def post(self, request):
        return HttpResponse('我是post里面的views')
path('func/',views.myView.as_view())
CBV会根据请求方式的不同,来匹配类中定义的方法,并自动执行!!!
CBV源码(很重要!!!)
'''CBV根据请求方式的不同匹配不同的方法的底层原理'''
# 第一步:
  path('func/',views.myView.as_view())
由于python中的一切皆对象,类点一个名字就相当于对象在点一个名字,这点可以推断as_view不是一个普通的名字,要么是方法要么是功能,而类能点的方法要么是专门绑定给类的方法,要么就是函数,而as_view()没有传参数,由此推断,此方法是专门绑定给类的,类调用就把自身当作第一个参数传进去

 1.类/对象查找属性/方法的第一步是先看自身有没有,自身没有!所以查看源码的入口就是 as_view()
 
 2.查看as_view发现,产生这个方法的类是view,而as_view方法是专门给类调用的,那么此时的cls = myView
   
 3 .再看as_view这个方法返回值是view
   def as_view():
       def view():
	   return view
那么 path('func/',views.myView.as_view())
    也可以写成 path('func/',views.view)
从底层原理上看CBV路由匹配本质:跟FBV是一致的
 

image

image

# 第二步:
1.view这个方法里的self = cls(**initkwargs)就是self = myView()
 类名加括号产生的就是这个类的对象,此时的self就是myView的对象
 
2.查看返回值return self.dispatch(request, *args, **kwargs)
 对象在点一个方法
 '''此时我们就应该想到,对象点方法的查找顺序,如果对象本身没有这个方法,那么就去产生对象的类里面去找,如果对象的类里面没有这个方法,那么就去继承的类里去找'''

image

# 第三步:
1.查看dispatch方法,def dispatch(self, request, *args, **kwargs)
 对象在调用一个方法的时候传的是对象本身,那么此时的self依旧是myView()
 
2.查看if判断:
if request.method.lower() in self.http_method_names
 # 如果myView()的请求方法在http_method_names这个方法列表内
通过反射将对象的请求小写并赋值给handler,最后返回handler()调用
  # 假设是get方法返回的就是get方法的return,post返回的就是post方法的return
  
'''CBV视图层中,dispatch方法可以说是前端向后端发送请求的调度员,可以根据不同的请求的方式执行视图类中对应的方法'''

#  http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

image

模板层

模板语法传值的两种方式
1.指名道姓的传值:
  def func(request):
	name = 'jason'
	return render(request,'myhtml02',{'name':name})
优点:精确度高,有效利用资源,不过多占用内存
缺点是:如果需要传的值比较庞大的时候,那么需要写很多重复的代码,代码冗余,不符合程序员偷懒特性!!
2.关键字locals传值 将整个名称空间的名字全部传入
def func(request):
    name = 'jason'
    age = 88
    hobby = '吨吨吨'
    return render(request,'myhtml02',locals())
优点:传值数据量大的时候,方便快捷,易操作
缺点:当数据量大,但是需要的传值数据就那么一两个的时候 ,占用内存空间
模板语法传值特性
# 模板语法传值是类型范围
python的基本数据类型都可以传值!
ps:python模板语法操作容器类数据的时候只允许使用句点符
# 函数类型传值
def func():
    print('哈喽啊,美好的一天')
    return '美好的周末'
函数的传值会自动加括号执行,并将返回值展示在页面
ps:模板语法不支持有参函数(不支持也不执行不展示),无法给函数传参
# 类传值
def func(request):
    class MyClass(object):
        def get_obj(self):
            return 'obj'
        @classmethod
        def get_cls(cls):
            return 'cls'
        @staticmethod
        def get_func(self):
            return 'func'
    obj = MyClass()
    return render(request, 'myhtml02.html', locals())
# 类名的传递会自动加括号产生对象并展示到页面,对象的传递则直接使用即可
 即:<p>{{ obj.get_func }}</p> 等
ps:魔法语法会自动判断每个名字类型是否可以加括号调用,可以的话直接调用。类似于callable()

图1:
image

模板语法之过滤器
# 类似于python的内置函数
模板方法符号:
    数据使用 :{{     }} 
    方法使用: {%     %}

    <p>统计长度:{{ s|length }}</p>
    <p>加法运算:{{ i|add:123 }}、加法运算:{{ s|add:'heiheihei' }}</p>
	
    # <p>日期转换:{{ s|date:'Y-m-d H:i:s' }}</p>
     from datetime import datetime
     res = datetime.today()
     <p>{{ res|date:'Y-m-d H:i:s' }}</p>
	 
    <p>文件大小:{{ file_size|filesizeformat }}</p>
       file_size = 111111233   # 106.0MB

    <p>数据切片:{{ l|slice:'0:10' }}</p>
	 #
    <p>字符截取(三个点算一个):{{ s1|truncatechars:6 }}</p>
    <p>单词截取(空格):{{ s1|truncatewords:6 }}</p>
	
   # <p>语法转义:{{ script_tag|safe }}</p>
    <p>语法转义:{{ script_tag1|safe }}</p>
    from django.utils.safestring import mark_safe
    script_tag1 = '<script>alert(666)</script>'
    res = mark_safe(script_tag1)
模板语法之标签
# 类似于python中的if判断
{ % if 条件 % }
    条件成立执行的代码
{ % elif 条件 % }
    条件成立执行的代码
{% else %}
    条件不成立执行的代码
{% end if%}
# 类似于python中的for循环  关键字forloop
{ % for i in l%}
  {{  forloop  }} 
{% endfor %}
ps:empty 空 如果是空的话返回empty里面的代码
自定义相关功能
# 自定义标签 ,过滤器,inclusion_tag
如果想自定义 必须先做一下三件事:
  1.在应用下创建一个templates_tag文件夹
  2.在该文件夹创建任意名称的py文件
  3.在该py文件内编写自定义相关代码、

# 自定义过滤器 最多只能有两个参数
from django.template import library
register=Library()
@reginster.filter(name = 'myfilter')
def my_add(a,b):
   return a+b
   
{% load my_tag%}
{{i|myfilter:1}}
# 自定义标签函数  可以用多个参数
@register.simple(name ='mt')
def func(a,b,c,d):
  return a+b+c+d

{% mt 1,2,3,4 %}
# inclusion_tag
@register.inclusion_ta(func='it',filename='it.html')
def index(n):
   html=[]
   for i in range(n):
       html.append('第%s页'%i)
   return locals()

it.html:
{% for i in html % }
  <li>{{i}}</li>
{% endfor %}

调用页面:
 {% index  10 %}
 {% index  5  %}
模板的继承与导入
继承页面:
{%  extends 'home.html'  %}  # 继承
{% block content %} 
  修改的内容
{% endblock %}


被继承页面:
{% block content %}
 可以修改的内容
{% endblock %}


一般模板中至少有三个区域:css js content


posted @ 2022-09-03 16:08  Hsummer  阅读(37)  评论(0编辑  收藏  举报