django的视图层和模版层

视图层

视图函数的返回值问题

当视图函数不返回HttpResponse的情况

# 1.在urls.py开设一个路由
path('test/',views.test)

# 2.在views.py写test视图函数并返回一个None
def test(request):
    return None

会报错,意思就是没有返回一个HttpResponse对象

image-20220902160257859

查看三板斧HttpResponse、render、redirect返回的对象

通过查询三板斧HttpResponse、render、redirect源码分析,它们最终都直接或间接的返回了一个response对象

  • HttpResponse
# 源码
class HttpResponse(HttpResponseBase):
  ...
  
# 视图函数
def test(request):
  return HttpResponse('xxx')

在视图函数test,返回的是一个HttpResponse对象:HttpResponse类加括号实例化一个对象

  • render
# render源码
def render(request, template_name, context=None, content_type=None, status=None, using=None):
  content = loader.render_to_string(template_name, context, request, using=using)
  return HttpResponse(content, content_type, status)

由源码可以看出,render本质上返回的是一个HttpResponse对象

  • redirect

可以看出redirect方法返回的是如图所指的类实例化的对象

image-20220902162413412

点进去查看这两个类,发现它们都继承了HttpResponseRedirectBase父类

image-20220902162039135

查看HttpResponseRedirectBase类,发现继承于HttpResponse类

image-20220902162745698

所以,redirect本质也是返回的HttpResponse对象

总结

视图函数必须返回一个HttpResponse对象

视图函数返回json格式数据

用json模块

import json
def test1(request):
    info_dict={'name':'jason','age':18,'hobby':'打篮球,踢足球'}
    json_info=json.dumps(info_dict,ensure_ascii=False)  
    return HttpResponse(json_info)

ensure_ascii=False显示中文,不设置此参数就会以二进制字节展示

用django自带JsonResponse模块

from django.http import JsonResponse
def test1(request):
    info_dict={'name':'jason','age':18,'hobby':'打篮球,踢足球'}
    return JsonResponse(info_dict)

image-20220902164053175

默认也是将不显示中文,通过查看源码可知,HttpResponse也是利用json进行序列化,并继承并重写了json.JsonEncoder类,它想要传dumps括号后面的参数可以通过json_dumps_params = {}的形式,将关键字参数按k:v的形式传进去。

image-20220902164428042

如果我们想在页面显示中文,写如下代码就行

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

序列化非字典类型数据

当序列化非字典类型页面会报错

image-20220902165445341

只需要指定safe参数为False就行了

from django.http import JsonResponse
def test1(request):
    info_dict={'name':'jason','age':18,'hobby':'打篮球,踢足球'}
    a_list=[1,2,3,'打篮球']
    return JsonResponse(a_list,safe=False,json_dumps_params={'ensure_ascii':False})

image-20220902165633461

form表单携带文件数据

form表单需要具备的条件

  • method属性值必须是post
  • enctype属性值必须是multipart/form-data

后端获取文件数据的操作

  • request.FILES

代码演示

# 1. 路由层开设路由
path('file/',views.file)

# 2. 视图函数写file函数
def file(request):
    if request.method=='POST':
        file_b=request.FILES.get('file')
        with open('file_a','wb') as f:  # 指定文件写入的路径
            for line in file_b:
                f.write(line)
    return render(request,'file.html')
  
# 3.前端页面
<form action="" method="post" enctype="multipart/form-data">
    <p><input type="file" name="file"></p>
    <p><input type="submit" value="提交"></p>
</form>
</body>

FBV与CBV

FBV:基于函数的视图

def index(request):
  return HttpResponse()
	path('index/', views.index)

CBV:基于类的视图

用不同的函数针对不同的HTTP方法处理,而不是通过if判断,提高代码的可读性

# 1. 路由层开设路由
path('view/',views.View.as_view())

# 2. 写类视图
from django import views
class view(views.View):
  def get(self,request):
    return HttpResponse("我是CBV的get方法")
	def post(self,request):
    return HttpResponse("我是CBV的post方法")

CBV会自动根据请求方法的不同匹配类中定义的方法并自动执行

CBV源码分析(重要)

源码分析入口

path('view/',views.View.as_view())
  1. 绑定给类的as_view方法

image-20220902174830943

  1. CBV路由匹配本质:跟FBV是一致的
# 等价于
path('view/',views.view)
  1. 访问func触发view执行

通过View类实例化产生对象,在通过对象点dispatch方法

image-20220902175300059

  1. 研究dispatch方法

调用父类的dispatch方法后,将用户的请求方式转为小写,通过反射判断请求在不在类中方法,在就执行对应请求函数,不在则无法正常显示页面,日志会打印:Method Not Allowed: /view/

image-20220902175827809

涉及到对象点名字,一定要确定对象是谁,再确定查找顺序

模版层

模版语法传值

  • 指名道姓:指名道姓传参,不浪费资源。
return render(request, 'modal.html', {'name':name})
  • 关键字locals():将整个局部名称空间的名字全部传入,简单快捷。
return render(request,'modal.html',locals())

模版语法传值的范围

  1. 基本数据类型直接传递使用

  2. 函数名的传递会自动加括号执行并将返回值展示到页面上

  3. 类名的传递也会自动加括号产生对象并展示到页面上

  4. 对象的传递则直接使用即可

  5. django的模版语法在操作容器类型的时候只允许使用句点符

注意函数如果有参数则不会执行也不会展示,模版语法不支持有参函数

# urls.py开设路由
path('test2/',views.test2)

#views.py写逻辑代码
def aaa(): 
    return 'aaa'

class Person:
    def __init__(self):
        pass

def test2(request):
    p=Person     # 类
    p1=Person()  # 对象
    a=aaa        # 函数名
    return render(request,'test2.html',locals())
  
# html页面
<body>
<h3>{{ p }}</h3>
<h3>{{ p1 }}</h3>
<h3>{{ a }}</h3>
</body>

浏览器输入url

image-20220902182416540

模版语法过滤器(类似于python内置函数)

import datetime
def filter1(request):
    a='hello,world!'
    b=10
    c=datetime.datetime.today()
    d=23232323232
    e=[1,2,3,4,5,6]
    f='my name is jason'
    css_tag='<i>你好</i>'
    script_tag='<script>alert(123)</script>'
    
    # 语法转义第二种方式
    from django.utils.safestring import mark_safe
    res=mark_safe('<script>alert(333)</script>')
    return render(request,'filter.html',locals())
<body>
<h3>统计字符长度{{ a|length }}</h3>           
<h3>加法运算:{{ b|add:100 }}</h3>
<h3>时间日期转换{{ c|date:'Y-m-d H:i:s' }}</h3>
<h3>字符串拼接{{ a|add:'hello' }}</h3>
<h3>文件大小{{ d|filesizeformat }}</h3>
<h3>数据切片{{ e|slice:'0:10' }}</h3>
<h3>字符截取{{ f|truncatechars:4 }}</h3>   // ...也算一个字符
<h3>单词截取{{ f|truncatewords:4}}</h3>
<h3>语法转义:{{ css_tag|safe }}</h3>
<h3>语法转义{{ script_tag|safe }}</h3>
<h3>语法转义的第二种方式:{{ res }}</h3>
</body>

image-20220902184759368

django模版语法中的符号就两个,一个{{}},一个{%%}

  • 需要使用数据的时候:{
  • 需要使用方法的时候:

模版语法标签(类似于python流程控制)

if语句

<body>
    {% if 1 %}
        <h1>我是if</h1>
    {% elif 1 %}
        <h1>我是elif</h1>
        {% else  %}
        <h>我是else</h>
    {% endif %}
</body>

for语句

def test3(request):
    a=False
    b=True
    s='helloworld'
    d=''
    return render(request,'test3.html',locals())
<body>
    {% for i in s %}
        {% if forloop.first %}
            <p>first</p>
            {% elif forloop.last %}
            <p>last</p>
            {% else %}
            <p>{{ i }}</p>
        {% endif %}
  				<p>你给我的是空,我怎么循环</p>
    {% endfor %}
</body>

自定义标签函数、过滤器、inclusion_tag

如果想自定义,必须先做一下三件事

  1. 在应用下创建一个名为templatetags的文件夹
  2. 在该文件夹创建任意名称的py文件
  3. 在该py文件内编写自定义相关代码

自定义过滤器

  1. 在templatetags文件夹创建一个mytag的py文件
from django.template import Library
register=Library()

@register.filter(name='myfilter')
def add(a,b):
    return a+b
  1. 在前端页面需要先导入mytag
{% load mytag %}
<h2>{{ d|myfilter:100 }}</h2>

自定义标签函数

@register.simple_tag(name='mt')
def func(a,b,c,d):
    return a+b+c+d
<h2>{% mt 1 2 3 4 %}</h2>

自定义inclusion_tag

  1. 在mytag文件夹
@register.inclusion_tag(filename='inclu.html')
def index(n):
    html=[]
    for i in range(n):
        html.append(f'第{i}页')
    return locals()
  1. 创建一个名为inclu的html文件
{% for i in html %}
    <ul>
        <li>{{ i }}</li>
    </ul>
{% endfor %}
  1. 在需要导入的html页面导入
{% load mytag %}
{% index 10 %}  <!-- 10为显示数量可随意设定-->

模版的继承

{% extends 'html文件名' %}
{% block 名字 %}
	模板内容
{% endblock %}


{% block 名字 %}
	子板内容
{% endblock %}

一般情况下母板中至少应该有三个区域使得扩展性更高:css、content、js

{% block css %}
	# css代码区
{% endblock %}

{% block content %}
# 内容区
{% endblock %}

{% block js %}
# js代码区
{% endblock %}

模版的导入

将html页面的某个部分当做模块的形式导入使用

{% include 'menu.html' %}

网页伪装态

将动态网页伪装成静态网页,从而提升网页被搜索引擎收录的概率,表现形式就是网站看着像一个具体的文件路径

path('index.html',view.index)
posted @ 2022-09-02 20:45  荀飞  阅读(20)  评论(0编辑  收藏  举报