视图层
视图层之 HttpResponse 对象
响应对象主要由三种形式
HttpResponse()
redirect()
render()
小白必备三板斧
HttpResponse # 返回字符串
redirect # 返回
render # 返回 html 文件
render() 不仅可以返回 html 文件,还可以给模板传值,通过字典给该页面传递数据,并返回一个渲染后的HttpResponse对象
from django.template import Template, Context
def index(request):
res = Template("<h1> {{ user}} </h1>") # 参数表示要渲染的模板样式及对象
con = Context({"user": {'username': 'jason','password': 123}}) # 被渲染对象具体对应的内容
ret = res.render(con)
print(ret)
return HttpResponse(ret) #{'username': 'jason', 'password': 123}
-
JsonResponse
返回 json格式数据
为什么要给前端返回 json格式字符串:前后端分离,就是基于 json格式传输数据,后端就专门写接口,前端调用你这个接口,就能拿到一个 json 格式的字符串,然后利用序列化反序列化转换成前端对应的数据类型
js 常用数据类型:
数值类型
字符类型
数组 []
自定义对象 {}
undefined 与 null
布尔值 true, false
symbol 标志
前端的 json
JSON.stringify() 序列化 >>> json.dumps
JSON.parse() 反序列化 >>> json.loads
python后端的 json
json.dumps
json.loads
import json
from django.http import JsonResponse
def index(request):
user = {'username': 'jason你很帅', 'pwd': 123}
# 1.HttpResponse,使用json转换数据格式
json_str = json.dumps(user, ensure_ascii=False) # 取消中文转换,默认为True
# return HttpResponse(json_str) #{"username": "jason", "pwd": 123}
# 2.使用JsonResponse转换数据格式
return JsonResponse(user, json_dumps_params={'ensure_ascii': False}) # 取消中文转换
# l = [1,2,3,4,5,6]
# return JsonResponse(l, safe=False) #对非字典类型,需要修改 safe参数为 False
总结:HttpResponse序列化数据 需要导入 json模块, 而 JsonResponse可直接对字典类型数据进行序列化操作,对于非字典类型数据需要修改 安全参数 safe=False 后才能转换,而且也是返回给页面,
form 表单上传文件
注意事项
1. 提交方式必须是post
- enctype参数必须由默认的 urlencode 变成 formdata,修改后才能上传文件
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="myfile">
<input type="text" name="password">
<input type="submit" value="提交">
</form>
def up(request):
if request.method == 'POST':
file_obj = request.FILES.get('myfile')
print(file_obj.name) #考试内容.txt
with open(file_obj.name, 'wb') as f:
# for line in file_obj: # file_obj你可以之前看成文件句柄f
for chunk in file_obj.chunks():
f.write(chunk)
return render(request, 'up.html')
注意:form表单上传文件,后端需要在 request.FILES 中获取文件数据,而不再是 POST里面
FBV(Function Based View)基于函数的视图,面向函数式编程
CBV(Class Based View) 基于类的视图,面向对象式编程
基于 CBV 的视图(get请求来就会走类里面的 get方法,post请求来就走类里面的 post方法)
需要注意的几点设置:
1. urls.py
url(r'^login/', views.MyLogin.as_view())
- views.py(get请求就走get方法,post请求就走post方法)
# CBV 基于类的视图
from django.views import View
class MyReg(View):
def get(self, request):
return render(request, 'reg.html')
def post(self, request):
return HttpResponse('我是MyReg类中的post方法')
模板层
模板层就是 html 页面,Django系统中的(template)
html 内 接收 views.py 内函数传入的变量, 用 {{ }}接收
模板传值
方式一:通过键值对的形式传参,指名道姓的传参
n = 123
m = [1,2,3]
return render(request, 'login.html', {'n':n, 'm': m}) # 前面的n是参数名, 后面n才是具体的值
方式二:使用 locals()传全部的值
def login(request):
n = 123
f = 12.3
s = '你妹的'
l = [1,2,3,4,5]
d = {'name': 'jason', 'pwd': 123}
t =(1,2,3,4,5,)
se = {1,2,3,4,5}
b = True
def func():
return '你妹的'
class MyClass(object):
@classmethod
def get_cls(cls):
return 'cls'
obj = MyClass()
return render(request, 'login.html', locals())
<body>
<p>{{ n }}</p>
<p>{{ f }}</p>
<p>{{ s }}</p>
<p>{{ l }}</p>
<p>{{ d }}</p>
<p>{{ t }}</p>
<p>{{ se }}</p>
<p>{{ b }}</p>
<p>
{{
obj.get_cls
}}
</p>
</body>
注意事项:
1.传函数给前端的时候,只要再模板层写函数名{{login}},传函数名会自动加()调用用函数,将函数的返回值展示在 html 页面上
2.django 模板语法不支持函数传参
3.django 模板语法在获取容器类型内部元素的值的时候,统一只采用 句点符(.),就是只能通过 ‘点取值’
4.对象也可以传递:{{ 0bj.方法名 }}
模板层的变量
模板语法:分为两大类
{{变量名}} 变量相关
{{% %}} 逻辑相关
<p>字符串:{{ name }}</p> # 相当于print(name)
<p>数字:{{ age }}</p> # 相当于print(age)
<p>列表:{{ ll }}</p> # 相当于print(ll)
<p>元祖:{{ tu }}</p> # 相当于print(tu)
<p>字典:{{ dic }}</p> # 相当于print(dic)
{#只写函数名:相当于函数名(),执行该函数#}
<p>函数:{{ test }}</p> # 相当于print(test()) 前端展示函数调用的返回值
{#对象内存地址#}
<p>对象:{{ lxx }}</p> # 相当于print(lxx)
<p>列表套对象:{{ person_list }}</p>
<p>字典套对象:{{ person_dic }}</p>
模板查询,统一使用句点符 ‘.‘
<p>列表第0个值:{{ ll.0 }}</p>
<p>列表第3个值:{{ ll.3 }}</p>
<p>字典取值:{{ dic.name }}</p>
<p>字典取列表值:{{ dic.ll }}</p>
{#再继续取值,继续点#}
<p>对象取数据属性:{{ lxx.name }}</p>
<p>对象取绑定给对象的函数属性:{{ lxx.get_name }}</p>
<p>对象取绑定给类的函数属性:{{ lxx.cls_test }}</p>
<p>对象取静态方法:{{ lxx.static_test }}</p>
<p>把对象列表中egon年龄取出来:{{ person_list.1.age }}</p>
{#拓展:不能调有参数的方法#}
<p>字符串的方法:{{ name.upper }}</p>
过滤器 (|) :类似于小的方法
过滤器是对 后端 传到 html页面前端的变量进行处理操作,是在 html文件中处理
过滤器的语法:{{ value|filter_name:参数}}
使用管道符 '|' 来应用过滤器
{{需要过滤的数据|过滤器的名字:过滤参数}}
常用的过滤器
- default 如果一个变量是 false或者为空,使用给定的默认值。否则,使用变量的值
<p>
{{value|default:'123'}}
</p>
2.length 返回值的长度,作用于统计字符串和列表的长度
{{value|length}}
3.filesizeformat 将值格式化为一个可读的文件尺寸(例如'13kb','4.1MB',等等)
{{ value|filesizeformat }}
如果 value 是 123456789,输出将会是 117.7 MB
4.slice 切片
{{value|slice:'2:-1'}} 前闭后开区间支持设置步长{{name|slice:'0:3:3'}}
5.date 时间格式化
from datetime import datetime
ctime = datetime.now()
{{ ctime|date:"Y-m-d H:i:s"}}
6.safe 取消转义
前端取消转义可以用 |safe (正常显示出html,js标签样式)
视图层
xxx='<h1>波波棋牌室</h1>'
模板层
{{xxx|safe}} #取消转义h1标签就会起作用
后端取消转义
from django.utils.safestring import make_safe
zzz = make_safe(''<h1>啊啊啊啊</h1>')
模板层,直接写
{{zzz}}
7.truncatechars 按照指定字符截取内容,截断的字符串以省略号(...)结尾(省略号算3个字符数量)
参数:指定截断的字符数
{{ info|truncatechars:6 }}
8.truncatewords 按空格截取(数字显示的是截取的空格数,三个点不包含)
{{ info|truncatewords:3 }}
9.cut 移除value中所有的与给出的变量相同的字符串
{{ value|cut:' ' }} #移除 ' '
如果value为'i love you',那么将输出'iloveyou'.
9.add 拼接(数字就相加,字符串就是拼接)
{{ n|add:100 }}
{{ s|add:'hahah 翻车啦' }}
其他过滤器
过滤器 | 描述 | 示例 |
---|---|---|
upper | 以大写方式输出 | {{ user.name | upper }} |
add | 给value加上一个数值 | {{ user.age | add:”5” }} |
addslashes | 单引号加上转义号 | |
capfirst | 第一个字母大写 | {{ ‘good’| capfirst }} 返回”Good” |
center | 输出指定长度的字符串,把变量居中 | {{ “abcd”| center:”50” }} |
cut | 删除指定字符串 | {{ “You are not a Englishman” | cut:”not” }} |
date | 格式化日期 | |
default | 如果值不存在,则使用默认值代替 | {{ value | default:”(N/A)” }} |
default_if_none | 如果值为None, 则使用默认值代替 | |
dictsort | 按某字段排序,变量必须是一个dictionary | {% for moment in moments | dictsort:”id” %} |
dictsortreversed | 按某字段倒序排序,变量必须是dictionary | |
divisibleby | 判断是否可以被数字整除 | `{{ 224 |
escape | 按HTML转义,比如将”<”转换为”<” | |
filesizeformat | 增加数字的可读性,转换结果为13KB,89MB,3Bytes等 | `{{ 1024 |
first | 返回列表的第1个元素,变量必须是一个列表 | |
floatformat | 转换为指定精度的小数,默认保留1位小数 | {{ 3.1415926 | floatformat:3 }} 返回 3.142 四舍五入 |
get_digit | 从个位数开始截取指定位置的数字 | {{ 123456 | get_digit:’1’}} |
join | 用指定分隔符连接列表 | {{ [‘abc’,’45’] | join:’’ }} 返回 abc45 |
length | 返回列表中元素的个数或字符串长度 | |
length_is | 检查列表,字符串长度是否符合指定的值 | {{ ‘hello’| length_is:’3’ }} |
linebreaks | 用或 标签包裹变量 | {{ “Hi David”|linebreaks }} 返回HiDavid |
linebreaksbr | 用 标签代替换行符 | |
linenumbers | 为变量中的每一行加上行号 | |
ljust | 输出指定长度的字符串,变量左对齐 | {{‘ab’|ljust:5}}返回 ‘ab ’ |
lower | 字符串变小写 | |
make_list | 将字符串转换为列表 | |
pluralize | 根据数字确定是否输出英文复数符号 | |
random | 返回列表的随机一项 | |
removetags | 删除字符串中指定的HTML标记 | {{value | removetags: “h1 h2”}} |
rjust | 输出指定长度的字符串,变量右对齐 | |
slice | 切片操作, 返回列表 | {{[3,9,1] | slice:’:2’}} 返回 [3,9] `{{ 'asdikfjhihgie' |
slugify | 在字符串中留下减号和下划线,其它符号删除,空格用减号替换 | `{{ '5-2=3and5 2=3' |
stringformat | 字符串格式化,语法同python | |
time | 返回日期的时间部分 | |
timesince | 以“到现在为止过了多长时间”显示时间变量 | 结果可能为 45days, 3 hours |
timeuntil | 以“从现在开始到时间变量”还有多长时间显示时间变量 | |
title | 每个单词首字母大写 | |
truncatewords | 将字符串转换为省略表达方式 | `{{ 'This is a pen' |
truncatewords_html | 同上,但保留其中的HTML标签 | `{{ 'This is a pen' |
urlencode | 将字符串中的特殊字符转换为url兼容表达方式 | {{ ‘http://www.aaa.com/foo?a=b&b=c’ | urlencode}} |
urlize | 将变量字符串中的url由纯文本变为链接 | |
wordcount | 返回变量字符串中的单词数 | |
yesno | 将布尔变量转换为字符串yes, no 或maybe | `{{ True |
特点:会将 | 左边的当做过滤器的第一个参数, |右边的当做第二个参数
在 Django的模板语法中,通过过滤器来改变变量在页面的显示
前端代码并不一定非要写在前端,也可以在后端写好,传递给前端页面
前后端取消转义
前端: |safe
后端:from django.utils.safestring import make_safe
标签
基本用法:遍历每个元素
for循环标签
视图层:
def test(request):
l=[1,2,3,4,5]
return render(request,'login.html',locals())
模板层:
{% for foo in l %}
{{ foo }} # 1,2,3,4,5
{% endfor %}
forloop对象,打印forloop可以得到所有循环后的各种信息值
% for foo in l %}
{{forloop }}
{% endfor %}
% for foo in l %}
{% if forloop.first %}
<p>这是我的第一次</p>
{% elif forloop.last %}
<p>这是最后一次了啊</p>
{% else %}
<p>嗨起来 大宝贝~</p>
{% endif %}
{% endfor %}
for...empty
for标签带有一个可选的{% empty %}从句,在给出的循环对象是空或者没有被找到时执行
% for foo in l %}
<p>{{ forloop.counter }}:{{ foo }} </p> # 给循环的值编号
{% empty %} # 在对象为空或者找不到时被执行
<p>对象为空,不能循环</p>
{% endfor %}
If 标签
if/elif/else
{% if user_list %}
用户人数:{{ user_list|length }}
{% elif black_list %}
黑名单数:{{ black_list|length }}
{% else %}
没有用户
{% endif %}
{% if user_list|length > 5 %}
七座豪华SUV
{% else %}
黄包车
{% endif %}
for循环和判断一起使用
{% for foo in l %}
{% if forloop.first %}
这是第一次
{% elif forloop.last %}
这是最后一次
{% else %}
来啊来啊
{% endif %}
{% endfor %}
自定义 过滤器
步骤:
1.在应用名下面新建一个templatetags 文件夹(必须交这个名字)
2.在该文件夹下 创建一个任意名称的 py文件
3.在该 py 文件内固定先写两行代码
from django.template import Library
register = Library()
- 写一个函数,用@register.filter(name='yyy')装饰一下(可以指定别名)
@register.filter(name='yyy')
def str_add(x,y):
return x+y
在模板里:(新定定义的标签,过滤器,都要重启程序)
{% load mytag %}
{{'lqz'|str_add:'nb'}}
自定义标签
1.在应用名下面新建一个templatetags 文件夹(必须交这个名字)
2.在该文件夹下 创建一个任意名称的 py文件
3.在该 py 文件内固定先写两行代码
from django.template import Library
register = Library()
写一个函数,用@register.simple_tag()装饰(可以指定别名)
@register.simple_tag()
def add_nb(value):
return value+'nb'
模板中:(多个参数,以空格区分)
{% load mytag %}
{% add_nb 'lqz'%}
模板的继承
当多个页面整体的样式都大差不差的情况下,可以设置一个模板文件,在该母板文件中,使用block块划分多个预期,相当于用block占位,之后子版在使用模板的时候,可以通过block的名字,来区分需要修改哪一部分区域。
模板一般情况下,应该至少有三个被修改的区域:css,子页面的html代码,js
1.使用模板的继承
写一个母版,需要留一个或多个可以扩展的区域。母版中主要是使用空的block完成页面的搭建
{%block 名字 %}
可以修改的内容
{%endblock%}
母版页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
{% block css %} #母版的css 内容
{% endblock %}
</head>
<body>
<h1>这是母板的标题</h1>
{% block content %} #母版的content内容
{% endblock %}
<h1>母板底部内容</h1>
{% block js %} #母版js内容
{% endblock %}
</body>
</html>
在子模板中使用,子模板主要内容是填空母版中空的block
# extends 告诉模板引擎,这个模板继承了另一个模板
{% extends "base.html" %}
{% block 名字 %}
子模板的内容
{% endblock 名字 %}
{% extends 'home.html' %}
{% block css %}
<style>
h1 {
color: red;
}
</style>
{% endblock %}
{% block content %}
{% include 'beautiful.html' %}
<h1>登陆页面</h1>
<form action="">
<p>username:<input type="text" class="form-control"></p>
<p>password:<input type="text" class="form-control"></p>
<input type="submit" class="btn btn-danger">
</form>
{% endblock %}
{% block js %}
{% endblock %}
强调(注意点)
- 如果母版的block中写了内容,子模板页面没有重写,那么就会使用母版的内容,所以我们在设置母版的block时,一般都是设置空内容。
- 一旦子模板页面重写了母版的block,往里面写值了,那么就会覆盖掉母版中block的内容
- 不能在一个模板中定义多个相同的block标签
模板的导入
要反复的使用一个组件,可以将该组件写在一个文件中,在使用的时候导入就可以,在模板中使用
语法
{% include '模板名字' %}
{% include 'beautiful.html' %}