肆拾陆 ---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 }}会被渲染成
<script>alert(123)</script>交给浏览器后会被解析成普通字符”<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视图层与模板层的主要内容,如果未能解决你的问题,请参考以下文章