肆拾陆 ---django视图层与模板层

Posted tangceng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了肆拾陆 ---django视图层与模板层相关的知识,希望对你有一定的参考价值。

django视图层与模板层

一、视图层

1.1 HttpResponse、render、redirect

? HttpResponse:返回字符串;

? redirect:重定向

? render:返回一个html页面,也可以给模板传值

? render的逻辑原理:

from django.template import Template,Context
def index(request):
    res = Template('<h1>{{ user }} </h1>')
    con = Context({'user': {"username": 'xiaohu', 'pwd': '123'}})
    ret = res.render(con)
    print(ret)
    return HttpResponse(ret)

1.2 JsonResponse

? 前后端分离需要使用json格式进行数据传输,后端专门写接口,前端对接口进行调用,获取json格式的字符串,前端利用序列化反序列转换成前端对应的数据类型。

? js常用数据类型:数值类型、字符类型、数组 []、自定义对象 {}、undefined与null、尔值 true false、symbol。

? 前端语法:JSON.stringify --->序列化 ; JSON.parse--->反序列。

? js序列化与反序列化默认对字符串进行ASCII编码,如果有多种文字,需要对默认进行修改:

import json
def index(request):
    user = {'username': 'daxiong大好人', 'pwd': '123'}
    json_str = json.dumps(user, ensure_ascii=False)
    return HttpResponse(json_str)

? 使用JsonResponse表示:

from django.http import JsonResponse
def index(request):
    user = {'username': 'daxiong大好人', 'pwd': '123'}
    return JsonResponse(user, json_dumps_params={'ensure_ascii':False})

? JsonResponse默认只支持序列化字典,如果想序列化其他类型(json能够支持的类型),需要将safe参数由默认的True改成False。

from django.http import JsonResponse
    l = [1,2,3,4,5,5,6]
    return JsonResponse(l,safe=False)

? 如若想使用js转换不支持的类型数据,可使用元类增加数据类型,例如datetime:

class MyJsonClass(json.JSONEncoder):
    def default(self,o):
        # 如果o不是json默认能够序列化,就在该方法内给他处理成json能够转的类型
        if isinstence(o,datetime):
            return o.strftime('%Y-%m-%d')
        else:
            super().default(self,o)
            
d = {'ctime':datetime.today()}
print(json.dumps(d,cls=MyJsonClass))

1.3 form表单上传文件

? 前端向后端传输form表单,需要使用request.FILES方法,并且将前端的form的enctype由默认的application/x-www-form-urlencoded改成multipart/form-data。

? 前端:

<body>
    <form action="" method="post" enctype="multipart/form-data">
    </form>
</body>

? 后端:

def up(request):
    if request.method =="POST":
        print(request.POST)
        print(request.FILES)
        # 获取文件对象
        file_obj = request.FILES.get('myfile')
        print(file_obj.name)
        with open(file_obj.name,'wb') as f:
            for line in file_obj:
            # 推荐写法
            # for chunk in file_obj.chunks():
                f.write(chuck)
     return render(request, 'uo.html')

1.4 CBV源码分析

? CBV(Class Based View):基于类的试图。

? 类中有get和post方法,如何实现前端发送什么请求,后端就会触发什么请求呢?

? CBV路由:

url(r'^reg/',views.MyReg.as_view())

? views:

rom django.views import View

class MyReg(View):
    def get(self,request):
        return render(request,'reg.html')

    def post(self,request):
        return HttpResponse("我是MyReg类中post方法")

? 源码:

@classonlymethod
        def as_view(cls, **initkwargs):
            def view(request, *args, **kwargs):
                self = cls(**initkwargs)  # cls就是我们自己的写的MyReg类
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
                self.request = request
                self.args = args
                self.kwargs = kwargs
                # 上面的一通操作就是给写的类的对象赋值
                return self.dispatch(request, *args, **kwargs)
                # 对象在查找属性或方法的顺序是先从自己找,再从产生对象的类中找,再去类的父类中找
            return view
        

 """重要部分"""
        def dispatch(self, request, *args, **kwargs):
            # 判断当前请求方式在不在默认的八个请求方式中
            if request.method.lower() in self.http_method_names:
                # handler = getattr(自己写的类产生的对象,'小写的请求方法(getpost)','获取不到对应的方法就报错')
                handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
                
                # handler就是自己定义的跟请求方法相对应的方法的函数内存地址
            else:
                handler = self.http_method_not_allowed
            # 再调用获取到的方法
            return handler(request, *args, **kwargs)  

1.5 django settings源码分析及实际应用

? django的配置文件有两个,一个是暴露给用户可以自定义配置的,一个是默认的全局配置文件。用户指定了就用用户的,用户没有指定就用默认的。

? settings源码:

settings = LazySettings()
        
        class LazySettings(LazyObject):
            
            def _setup(self, name=None):
                # os.environ你可以把它看成是一个全局的大字典
                settings_module = os.environ.get(ENVIRONMENT_VARIABLE)  # 从大字典中取值
                # settings_module = 'day59.settings'
                self._wrapped = Settings(settings_module)  # Settings('day59.settings')
        
        class Settings(object):
            def __init__(self, settings_module):  # settings_module = 'day59.settings'
                for setting in dir(global_settings):  # 循环获取global_settings文件中所有的名字
                    if setting.isupper():  # 在判断名字是否是大写
                        # 如果是大写 利用反射 获取到大写的名字所对应的值  不停地添加到对象中
                        setattr(self, setting, getattr(global_settings, setting))
                # store the settings module in case someone later cares
                self.SETTINGS_MODULE = settings_module
                mod = importlib.import_module(self.SETTINGS_MODULE)  # 'day59.settings'
                # from day59 import settings
                # mod 指代的就是暴露给用户的配置文件模块名
               
                for setting in dir(mod):  # 循环获取暴露给用户配置文件中所有的名字
                    if setting.isupper():  # 判断是否是大写
                        setting_value = getattr(mod, setting)  # 如果是大写 获取大写的变量名所对应的值
                        setattr(self, setting, setting_value)  # 不停的给对象设置值

二、模板层

2.1 模板传值

? 传函数名的时候 会自动加括号调用函数 将函数的返回值展示在html页面上,django模板语法不支持函数传参。django模板语法在获取容器类型内部元素的值的时候 统一只采用 句点符(.)。

? views:

def login(request):
    n = 123
    f = 12.12
    s = '你妹的 真难'
    l = [1,2,3,4,5,6]
    d = {'username':'jason','password':[123,222,444]}
    t = (1,2,3,4,5)
    se = {1,2,3,4}
    b = True

? login.html:

<p>{{ n }}</p>
<p>{{ f }}</p>
<p>{{ s }}</p>
<p>{{ l }}</p>
<p>{{ d }}</p>
<p>{{ se }}</p>
<p>{{ t }}</p>
<p>{{ b }}</p>
<p>{{ obj }}</p>
<p>{{l.1 }}</p>
<p>{{ l.3 }}</p>

<p>{{ d.username }}</p>
<p>{{ d.password }}</p>
<p>{{ d.password.1 }}</p>
 <p>{{ func }}</p>

2.2 过滤器

? 过滤器类似于python的内置函数,用来把视图传入的变量值加以修饰后再显示,具体语法如下:

{{ 变量名|过滤器名:传给过滤器的参数 }}

? 常用过滤器:

#1、default
#作用:如果一个变量值是False或者为空,使用default后指定的默认值,否则,使用变量本身的值,如果
value=’‘则输出“nothing”
{{ value|default:"nothing" }}
#2、length
#作用:返回值的长度。它对字符串、列表、字典等容器类型都起作用,如果value是 ['a', 'b', 'c', 'd'],那
么输出是4
{{ value|length }}
#3、filesizeformat
#作用:将值的格式化为一个"人类可读的"文件尺寸(如13KB、4.1 MB、102bytes等等),如果 value 是
12312312321,输出将会是 11.5 GB
{{ value|filesizeformat }}
#4、date
#作用:将日期按照指定的格式输出,如果value=datetime.datetime.now(),按照格式Y-m-d则输出2019-02-02
{{ value|date:"Y-m-d" }}
#5、slice
#作用:对输出的字符串进行切片操作,顾头不顾尾,如果value=“egon“,则输出"eg"
{{ value|slice:"0:2" }}
#6、truncatechars
#作用:如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾,
如果value=”hello world egon 嘎嘎“,则输出"hello...",注意8个字符也包含末尾的3个点
{{ value|truncatechars:8 }}
#7、truncatewords
#作用:同truncatechars,但truncatewords是按照单词截断,注意末尾的3个点不算作单词,如果value=”
hello world egon 嘎嘎“,则输出"hello world ..."
{{ value|truncatewords:2 }}
#8、safe
#作用:出于安全考虑,Django的模板会对HTML标签、JS等语法标签进行自动转义,例如value="
<script>alert(123)</script>",模板变量{{ value }}会被渲染成
&lt;script&gt;alert(123)&lt;/script&gt;交给浏览器后会被解析成普通字符”<script>alert(123)
</script>“,失去了js代码的语法意义,但如果我们就想让模板变量{{ value }}被渲染的结果又语法意义,那么就
用到了过滤器safe,比如value='<a href="https://www.baidu.com">点我啊</a>',在被safe过滤器处理后
就成为了真正的超链接,不加safe过滤器则会当做普通字符显示’<a href="https://www.baidu.com">点我啊
</a>‘
{{ value|safe }}

2.3 标签

? 标签是为了在模板中完成一些特殊功能,语法为{% 标签名 %},一些标签还需要搭,配结束标签 {% endtag %}。

? for标签:

#1、遍历每一个元素:
{% for person in person_list %}
 <p>{{ person.name }}</p>
{% endfor %}
#2、可以利用{% for obj in list reversed %}反向循环。
#3、遍历一个字典:
{% for key,val in dic.items %}
 <p>{{ key }}:{{ val }}</p>
{% endfor %}
#4、循环序号可以通过{{ forloop }}显示
forloop.counter 当前循环的索引值(从1开始)
forloop.counter0 当前循环的索引值(从0开始)
forloop.revcounter 当前循环的倒序索引值(从1开始)
forloop.revcounter0 当前循环的倒序索引值(从0开始)
forloop.first 当前循环是第一次循环则返回True,否则返回False
forloop.last 当前循环是最后一次循环则返回True,否则返回False
forloop.parentloop 本层循环的外层循环
#5、for标签可以带有一个可选的{% empty %} 从句,在变量person_list为空或者没有被找到时,则执行empty子
句
{% for person in person_list %}
 <p>{{ person.name }}</p>
{% empty %}
 <p>sorry,no person here</p>
{% endfor %}

? 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语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。

? with标签:

# with标签用来为一个复杂的变量名起别名,如果变量的值来自于数据库,在起别名后只需要使用别名即可,无需每次
都向数据库发送请求来重新获取变量的值
{% with li.1.upper as v %}
 {{ v }}
{% endwith %}

2.4 自定义标签和过滤器

? 步骤:

? 1 在应用名下面新建一个templatetags文件夹(必须叫这个名字)

? 2 在改文件夹下 新建一个任意名称的py文件

? 3 在该py文件内 固定先写两行代码

from django.template import Library

register = Library()

? 自定义的过滤器和标签:

@register.filter(name='myplus')
def index(a,b):
    return a + b
    
@register.simple_tag(name='mysm')
def login(a,b,c,d):
    return '%s/%s/%s/%s'%(a,b,c,d)

? 区别:标签不能在if中使用:

{% if 0|myplus:123 %}  可以用
    <p>有值</p>
{% endif %}

{% if mysm 1 2 3 4 %}  不能用
    <p>有值</p>
{% endif %}

2.5 模板的继承

? 在实际开发中,模板文件彼此之间可能会有大量冗余代码,为此django提供了专门的语法来解决这个问题,主要围绕三种标签的使用:include标签、extends标签、block标签,详解如下:

#作用:在一个模板文件中,引入/重用另外一个模板文件的内容,
{% include '模版名称' %}
#作用:在一个模板文件中,引入/重用另外一个模板文件的内容
{% extends "模版名称" %}
# 也就是说include有的功能extends全都有,但是extends可以搭配一个block标签,用于在继承的基础上定制新的内容,例如css,js,content等,还可以使用.super来继续使用母版上的内容。

? 1、标签extends必须放在首行,base.html中block越多可定制性越强

? 2、include仅仅只是完全引用其他模板文件,而extends却可以搭配block在引用的基础上进行扩写

? 3、变量{{ block.super }} 可以重用父类的内容,然后在父类基础上增加新内容,而不是完全覆盖

? 4、为了提升可读性,我们可以给标签{% endblock %} 起一个名字 。例如:
{% block content %}
...
{% endblock content %}
? 5、在一个模版中不能出现重名的block标签。

2.6 模板的导入

? 当你写了一个特别好看的form表单 你想再多个页面上都使用这个form表单,你就可以将你写的form表单当作模块的形式导入 导入过来之后 就可以直接展示。

{% include 'good_page.html' %}

以上是关于肆拾陆 ---django视图层与模板层的主要内容,如果未能解决你的问题,请参考以下文章

记录去大搜车的一道笔试题

试用资源|《鼎秀古籍全文检索平台V1.0》开通试用啦!