• Django-(4)


    内容概览

    • 网页伪静态
    • 视图层
      • 视图函数的返回值
      • 视图函数返回JSON格式数据
      • form表单携带文件数据
      • FBV与CBV
      • CBV源码分析
    • 模板层
      • 模板语法传值
      • 模板语法传值的范围
      • 模板语法过滤器
      • 模板语法标签
      • 自定义标签函数、过滤器、inclusion_tag
      • 模板的继承
      • 模板的导入

    网页伪静态

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

    urls:
    # 将路由写成文件路径的样式
    urlpatterns=[
    	path('home.html', views.home)
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    视图层

    视图函数的返回值

    如果视图函数不写返回值会直接报错
    在这里插入图片描述

    视图函数必须返回一个HttpResponse对象
    render与redirect其实底层也是返回的HttpResponse对象
    render:
    在这里插入图片描述
    redirect返回的是一个继承了HttpResponse的类的对象:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    视图返回JSON格式数据

    想要返回JSON格式数据可以直接使用json模块序列化

    def fn(request):
    	import json
    	user_dict = {'name': 'jason', 'age': 28}
    	json_str = json.dumps(user_dict, ensure_ascii=False)  # 如果数据中有中文,需要设置ensure_ascii属性确保中文正常显示
    	return HttpResponse(json_str)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    但是django提供了一种更简便的方式

    def fn(request):
    	from django.http import JsonResponse
    	user_dict = {'name': 'jason', 'age': 28}
    	return JsonResponse(user_dict)
    
    • 1
    • 2
    • 3
    • 4

    JsonResponse源码:

    class JsonResponse(HttpResponse):
        def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
                     json_dumps_params=None, **kwargs):
            if safe and not isinstance(data, dict):
                raise TypeError(
                    'In order to allow non-dict objects to be serialized set the '
                    'safe parameter to False.'
                )
            if json_dumps_params is None:
                json_dumps_params = {}  # 如果没有传值,则设置为空字典
            kwargs.setdefault('content_type', 'application/json')
            data = json.dumps(data, cls=encoder, **json_dumps_params)  # 将json_dumps_params拆解为关键字参数
            super().__init__(content=data, **kwargs)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    通过查看源码可以知道,使用JsonResponse想要使中文正常显示,返回值需要这样写:

    return JsonResponse(data, json_dumps_params={ensure_ascii:False})
    # 如果想要序列化非字典类型的数据还需要将参数safe设定为False
    
    • 1
    • 2
    form表单携带文件数据

    想要使后端接收到form表单发送的文件数据,需要下述条件:
    from表单的method属性必须为post;enctype属性值必须是multipart/form-data

    <form method='post' enctype='multipart/form-data'>
    	<input class='file' name='file'>
    	<input class='submit' value='提交'>
    form>
    
    • 1
    • 2
    • 3
    • 4

    后端使用request.FILES接收

    def fn(request):
    	f = request.FILES.get('file')
    	print(f.name)  # 可以用.name获取标签的name属性的值
    
    • 1
    • 2
    • 3
    FBV与CBV

    FBV:基于函数的视图

    """urls"""
    path('func/', views.func)
    """views"""
    def func(request):
    	return HttpResponse()
    
    • 1
    • 2
    • 3
    • 4
    • 5

    CBV:基于类的视图

    """urls"""
    path('func/',views.MyView.as_view())
    # path('路由',views.类名.内置的方法)
    """views"""
    from django import views
    class MyView(views.View):
    	def get(self, request):
    		return HttpResponse('get')
    	
    	def post(self, requese):
    		return HttpResponse('post')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

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

    CBV源码分析

    源码分析入口:

    path('func/', views.MyView.as_view())
    # 在程序运行时,会直接调用as_view()方法
    
    • 1
    • 2

    as_view:
    在这里插入图片描述
    返回了view方法名,那么路由匹配就可以看做是:

    path('func/', views.MyView.view)
    
    • 1

    访问func/触发view执行,接下来就看view中发生了什么

    def view(request, *args, **kwargs):
    	self = cls(**initkwargs)  # cls是之前自动传入的类
    	if hasattr(self, 'get') and not hasattr(self, 'head'):  # hasattr反射函数,通过字符串判断类里是否有get属性或方法
    	    self.head = self.get
    	self.setup(request, *args, **kwargs)
    	if not hasattr(self, 'request'):
    	    raise AttributeError(
    	        "%s instance has no 'request' attribute. Did you override "
    	        "setup() and forget to call super()?" % cls.__name__
    	    )
    	return self.dispatch(request, *args, **kwargs)  #相当于又用类调用了一个方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    dispatch:

    def dispatch(self, request, *args, **kwargs):
        if request.method.lower() in self.http_method_names: 
        # http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] 如果请求方式是这常见的8个,那么就可以直接调用
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)  # request.method获取请求方式,lower转成小写然后获取
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)  # return 调用返回值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    模板层

    模板语法传值
    # 方式一:指定数据
    return render(request, 'modal.html', {'data': data})
    """指定数据传参,不浪费资源;但是文件数量太多会很麻烦"""
    # 方式而:关键字locals()
    return render(request, 'madal.html'locals())
    """将整个局部名称空间中的名字全部传入,简单快捷;但是如果只需要一条数据而传了很多,那么造成了资源浪费"""
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    模板语法传值的范围

    基本数据类型能够直接传递使用:
    int、float、str、bool、list、tuple、set、dict
    函数名的传递会自动加括号调用,并将返回值展示到html页面上;模板语法只支持无参函数,对于有参函数则不会执行和展示
    python:

    def func1(request):
        def fn1():
            return 'from fn1'
    
        def fn2(a):
            return 'from fn2'
    
        return render(request, 'myhtml01.html', locals())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    html:

    <p>{{ fn1 }}p>
    <p>{{ fn2 }}p>
    
    • 1
    • 2

    浏览器:
    在这里插入图片描述
    类名的传递也会自动加括号产生对象并将对象展示到页面上,而对象的传递则可直接使用
    python:

    def func1(request):
        class cls1(object):
            pass
        obj1 = cls1()
        return render(request, 'myhtml01.html', locals())
    
    • 1
    • 2
    • 3
    • 4
    • 5

    html:

    <p>{{ cls1 }}p>
    <p>{{ obj1 }}p>
    
    • 1
    • 2

    浏览器:
    在这里插入图片描述

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

    管道符|与冒号:左右不能有空格

    1. 统计长度
    	<p>{{ s|lenght }}p>				统计s中值的数量
    2. 加法运算
    	<p> {{ i|add:666 }} p>			将i中的值与666相加,可以是算数运算,也可以是字符串拼接;如果都报错则返回空字符串
    3. 日期转换
    	<p>{{ new_date|date:'Y-m-d H:i:s' }}p>	将传入数据转换为格式化日期
    4. 文件大小
    	<p>{{ file_size|filesizeformat }}p>		将传入数据转换为合适的单位展示,最大支持PB
    5. 数据切片
    	<p>{{ l1|slice:'0:2'}}p>			将容器数据类型切片取值,遵循左闭右开原则
    6. 字符截取
    	<p>{{ s1|truncatechars:5 }}p>		截取指定个数字符,如果数据没有被截取完,那么截取的最后一个字符会替换成...
    	<p>{{ s1|truncatewords:2 }}p>		按照空格截取指定个数数据,如果数据没有被截取完,那么在最后会添加...
    7. 语法转义
    	<p>{{ scr|safe }}p>				传入的参数默认全都是字符串传入,使用语法转义后就可以从后端写html的代码,例如:
    	scr = '<script>alert(123)script> <h1>Titleh1>'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    django模板语法中的符号就只有{{}}与{%%}两个
    在需要使用数据的时候使用{{}}
    在需要使用方法的时候使用{%%}

    模板语法标签(类似于流程控制)
    
    {% if 条件1 %}	条件一般是模板语法传过来的数据,已经使用了{%%}符号就直接写名字即可
    	条件1成立执行的代码
    {% elif 条件2 %}
    	条件2成立执行的代码
    {% else %}
    	上述条件都不成立执行的代码
    {% endif %}  结束符
    
    
    {% for i in s %}
    	{% if forloop.first %}
    	    <p>判断是否为第一次循环p>
    	{% endif %} 
    	{% if forloop.counter == 3 %}
    	    <p>counter是当前循环次数,从1开始;counter0从0开始p>
    	{% endif %} 
    	{% if forloop.revcounter == 1 %}
    	    <p>revcounter是倒数,从1开始;revcounter0从0开始p>
    	{% endif %}
    	{% if forloop.last %}
    	    <p>判断是否为最后一次循环p>
    	{% endif %}
    	{% empty %}
    	    <p>传入循环的数据为空p>
    {% endfor %}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    自定义标签函数\过滤器\inclusion_tag

    如果想要使用自定义,有以下条件:

    1. 在应用下创建一个名为templatetags文件夹
    2. 在文件夹内创建一个py文件
    3. 在py文件内编写自定义相关代码
    4. py文件中输入代码
      from django.template import Library
      register = Library()
      
      • 1
      • 2
    5. 在html页面使用前需要先加载文件
    {% load '创建的py文件' %}
    
    • 1
    • 自定义过滤器
    @register.filter(name='myfilter')
    def my_add(a, b):
    	return a + b
    # 最多只支持两个参数传入
    
    • 1
    • 2
    • 3
    • 4
    • 自定义标签函数
    @register.simple_tag(name='mt')
    def fn(a, b, c, d):
    	return a + b + c + d
    # 能够使用多个参数
    # 使用方式:{% fn 1 2 3 4 %}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 自定义inclusion_tag
    @register.inclusion_tag(filename='myhtml.html')  
    def fn2(n):
    	num_list = []
    	    for i in range(n):
            html.append(f'第{i}页')
        return locals()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    myhtml:

    <ul>
    	<% for i in num_list %>
    		<li>{{ i }}li>
    	<% forend %>
    ul>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    提前写好一个动态网页,后续调用函数名相当于插入了一段html代码
    使用方式:

    {% fn2 5 %}
    
    • 1
    模板的继承

    使用{% extends html文件名 %}就相当于是复制了指定html文件的代码过来
    那么如果想要修改其中部分内容,则需要提前在母版中划分哪些部分需要修改
    母版:

    {% block 名字 %}
    	待修改的模板内容
    {% endblock %}
    
    • 1
    • 2
    • 3

    子版:

    {% extends '母版名' %}
    {% block 名字 %}
    	修改的模板内容
    	{{ block.super }}  
    {% endblock %}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    一般情况下母版中至少应该有三个区域可更改:css、模板内容、script;使得扩展性更高

    模板的导入

    将html页面当做模块的形式导入使用

    {% include 'html文件名' %}
    
    • 1

    类似于自定义inclusion_tag;区别在于模板导入的是一个静态的

  • 相关阅读:
    Java知识点补充
    Centos7.9安装mysql5.7.35记录
    python加密Django框架代码(通过修改Cpython解释器)
    React 消息文本循环展示
    Ansible-Playbook
    [NISACTF 2022]下
    算法和数据结构解析-9 : 排序相关问题讲解
    C#文件目录
    纯前端 excel 导出
    【经验模态分解】3.EMD模态分解算法设计与准备工作
  • 原文地址:https://blog.csdn.net/AL_QX/article/details/126665320