Django 04
视图层
三个常用方法
- HttpResponse
- render
- redirect
- render和redirect都继承了HttpResponse
- 视图函数必须要有一个返回值, 而且这个返回值必须是HttpResponse对象

JsonResponse
通常情况下, 前后端数据交互采用的都是json字符串 (字典)
我们先来回忆下前后端序列化和反序列化
| 操作 | python后端 | js前端 |
|---|---|---|
| 序列化 | json.dumps() | JSON.stringify() |
| 反序列化 | json.loads() | JSON.parse() |
现在我们要向前端返回一个json字符串, 该怎么操作呢?
利用我们已经学习的知识, 很容易实现
def index(request):
user_dic = {'name': 'bigb', 'password': '123'}
json_str = json.dumps(user_dic)
return HttpResponse(json_str)
现在我们访问 /index/, 页面显示为 {"name": "bigb", "password": "123"}
so far so good, right?
现在我们把字典改一下
def index(request):
# 将name改为我的中文名
user_dic = {'name': '彭于晏', 'password': '123'}
json_str = json.dumps(user_dic)
return HttpResponse(json_str)
现在我们再来访问 /index/, 结果: {"name": "\u5f6d\u4e8e\u664f", "password": "123"}
这又是咋回事呢?
我们来看一下dumps方法的源代码

原来dumps方法有一个默认参数 ensure_ascii=True , 默认的编码格式是ascii编码, ascii是不支持中文字符的
因此我们只要修改 ensure_ascii=Flase 就可以了
def index(request):
user_dic = {'name': '彭于晏', 'password': '123'}
# 修改默认参数ensure_ascii为Flase
json_str = json.dumps(user_dic, ensure_ascii=False)
return HttpResponse(json_str)
再来访问 /index/, 完美将我的中文名显示出来了 {"name": "彭于晏", "password": "123"}
扯了半天, 差点把主角 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)
super(JsonResponse, self).__init__(content=data, **kwargs)
显然, JsonResponse是一个类, 同样也继承了HttpResponse
再来看这一行代码 data = json.dumps(data, cls=encoder, **json_dumps_params)
可见JsonResponse帮我们对数据进行了json序列化处理, 我们直接传入数据即可
def index(request):
user_dic = {'name': '彭于晏', 'password': '123'}
return JsonResponse(user_dic)
来, /index/走一个, 然后... {"name": "\u5f6d\u4e8e\u664f", "password": "123"}
还是同样问题, 反正都是用的也是dumps方法, 将 ensure_ascii=Flase 传给dumps方法不就行了吗
怎么传呢? 看图

因此
def index(request):
user_dic = {'name': '彭于晏', 'password': '123'}
# 借助JsonResponse, 给其中的dumps方法传参, 修改其默认的ascii编码为Flase
return JsonResponse(user_dic, json_dumps_params={'ensure_ascii': False})
然后, 我们再来 /index/, 结果: {"name": "彭于晏", "password": "123"}
至此, 我们就把 JsonResponse 方法给拿下了!
然而自觉告诉我, 事情没那简单, 我们再来看

可见 JsonResponse 默认只支持字典这一种数据格式
如果我们想让其支持更多的数据格式, 很简单, 源码中注释也提示我们了, 将 safe=True 这个默认参数设置为 Flase 就行了
def index(request):
lis = ['彭于晏', '123']
# 设置safe=False参数, 使得JsonResponse支持更多数据格式
return JsonResponse(user_dic, json_dumps_params={'ensure_ascii': False}, safe=Flase)
FBV 和 CBV
- FBV 基于函数视图
- CBV 基于类视图, 也就是说我们可以在视图层来定义类
FBV我们已经很熟悉了, 我们来看下CBV如何使用
首先我们先来看下CBV的路由层的写法
urlpatterns = [
url(r'^login/', views.Login.as_view()),
]
再来看下CBV 视图层的写法, 注意我们定义视图类时要继承View类, 需要先导入View
from django.shortcuts import render, HttpResponse, redirect
from django.views import View
# 要继承View类
class Login(View):
def get(self, request):
return render(request, 'login.html')
def post(self, request):
return HttpResponse('login_post')
get方法我们返回了一个html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<form action="" method="post">
<h1>点击提交post请求</h1>
<input type="submit">
</form>
</body>
</html>
路由层和视图层还有模板层都写好了, 访问一下 /login/ 试试吧

显然, 我们访问 /login/, 既向后端发送get请求, 触发了Login这个类下面的get方法, get方法将我们的login.html文件返回了到了前端
然后我们点击页面上的提交按钮

当我们点击提交按钮, 向后端发放post请求, 触发了Login这个类下面的post方法
感觉CBV有点牛逼的样子啊, 可以根据前端的请求方式, 触发类中对应的方法
是如何做到的呢?
我们从路由层开始入手

通过源码我们发现 as_view 是一个函数, 我们知道, 函数加括号就会调用, 因此项目一启动, 就执行了 as_view 这个函数
执行这个函数发生了啥呢? 不废话, 我们直接上源码 (为了方便分析, 这里剔除了一些代码)
@classonlymethod
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
# self是我们定义视图类的对象
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
# 这里调用了dispatch函数, 因此view函数的返回值就是dispatch的返回值
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs
return view
def dispatch(self, request, *args, **kwargs):
# 判断请求方式是符合http的请求方式
if request.method.lower() in self.http_method_names:
# 利用反射, 得到视图类下面的相应的方法
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
显然,
as_view是一个闭包函数, 调用as_view会返回内层函数view, 那这个view函数又是个什么鬼啊我们来看
view函数的返回值:return self.dispatch(request, *args, **kwargs), 这里调用了dispatch函数, 因此view函数的返回值就是dispatch函数的返回值, 现在我们将目光转移到dispatch函数上老规矩, 我们先来看
dispatch函数的返回值:return handler(request, *args, **kwargs), 又来了
handler 函数, 快被整懵逼了... 不慌, 容我对源码稍作处理:
handler = getattr(self, 请求方式, 默认值) self是我们定义的视图类的对象
这下明白了吗? 就是利用反射来获取对象的方法, 如果请求方式是post, 这个handler就是对象的post方法啦
总结:
- 不管是FBV还是CBV, 路由层中匹配的都是函数
- 执行view函数---> 执行dispatch函数---> 通过反射得到类对象的方法并执行, 最终执行view函数返回的就是执行类对象方法返回的结果

别急, 还没完, 再补充一个知识点: 如何 给视图类加装饰器
- 在方法上直接加装饰器
@method.decorator(time_counter) - 在类上面
@method.decorator(time_counter, name='get')给get方法添加装饰器
# 需要导入
from django.utils.decorators import method_decorator
# 在类上面给某个方法添加装饰器
@method_decorator(time_counter, name='get')
class Login(View):
def get(self, request):
return render(request, 'login.html')
# 在方法上添加装饰器
@method.decorator(time_counter)
def post(self, request):
return HttpResponse('login_post')
在类中定义一个dispatch方法, 给dispatch添加装饰器, 这样就给类下面的所有方法都加装了装饰器
(把上面CBV原理搞懂了, 这个就不难理解了, 这里就不做过多阐述了)
from django.utils.decorators import method_decorator
@method_decorator(time_counter, name='dispatch')
class Login(View):
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
模板层
模板语法
模板语法只有两种格式:
- {{ }} 变量相关
- {% %} 逻辑和功能相关
模板传值
我们来看下模板传值支持哪些数据格式
首先我们需要知道的是视图层 给html文件传值的两种方式
- 用字典传值
- 用
locals()传值, 会将当前所在的名称空间中所有的名字传递给html文件
# views.py
def test(request):
i = 1
f = 1.1
s = 'django'
l = [1, 2, 3]
d = {'name': 'bigb', 'super_power': 'handsome'}
t = (1, 2, 3)
se = {1, 2, 3}
b = True
# 字典传值
# return render(request, 'test.html', {'i': i, 'f': f, 's':s, ...})
# locals()传值
return render(request, 'test.html', locals())
模板层接收视图层传过来的数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板传值</title>
</head>
<body>
<p> {{ i }}</p>
<p> {{ f }}</p>
<p> {{ s }}</p>
<p> {{ l }}</p>
<p> {{ d }}</p>
<p> {{ t }}</p>
<p> {{ se }}</p>
<p> {{ b }}</p>
</body>
</html>
别忘了路由层的的路由和视图函数的匹配
万事俱备, 让我们走起...

可见模板语法传值支持python 8大基本数据类型
我们再来试下模板传值可不可以传函数
def test(request):
def func():
return 'func的返回值'
# locals()传值
return render(request, 'test.html', locals())
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板传值</title>
</head>
<body>
<p>{{ func }}</p>
</body>
</html>
结果

因此在给html文件传递函数名的时候, 会自动加括号调用, 并将函数的返回值展示出来
需要注意的是:
模板语法不支持函数传参, 也就意味着 在给html文件传递函数名的时候, 必须是无参函数或者无须传参的函数
既然都可以传函数, 那能不能传类和对象呢?
def test(request):
class MyClass:
def func1(self):
return 'func1'
@classmethod
def func2(cls):
return 'func2'
@staticmethod
def func3():
return 'func3'
my_obj = MyClass()
# locals()传值
return render(request, 'test.html', locals())
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板传值</title>
</head>
<body>
<p>传类{{ MyClass }}</p>
<p>传对象{{ my_obj }}</p>
</body>
</html>
我们访问/test/看下结果

我们传的明明是一个类和一个对象, 咋变成两个对象了呢?
原来在给html文件传递类的时候, 模板语法会自动加括号调用类实例化对象
当然上面的结果也证明了: 模板语法支持传递对象
需要说明的是我们还可以在html文件中调用对象的属性和方法
我们来总结一下:
对象传值支持python 8大基本数据类型, 函数, 类和对象
只要是能加括号调用的, 传给到html页面上都会自动加括号调用
过滤器
什么是过滤器呢?
过滤器就是模板语法提供的一些内置方法, 可以帮助我们在html文件里快速处理数据
我们先来看下过滤器的语法结构
{{ 参数1|过滤器:[参数2 ]}}
注意: 过滤器参数最多不超过两个
下面是几个常用的过滤器
| 过滤器 | 效果 |
|---|---|
{{ arg|length }} |
返回参数arg的长度 |
{{ arg1|add:arg2 }} |
数字相加, 字符串拼接 |
{{ arg|slice:'0:5:2' }} |
切片, 顾头不顾尾, 支持切片 |
{{ file_size|filesizeformat }} |
文件大小的格式处理 |
{{ str|truncatechars:n }} |
从str中截取n个字符, 包含 '...' |
{{ str|truncatewords:n }} |
从str中截取n个单词, 不包含三个点 |
{{ arg|default:s为空 }} |
arg有值展示值, 没值返回默认值 |
{{ str|safe }} |
前端取消转义, 将含有标签的str转成前端代码 |
后端取消转义: mark_safe(str)
from django.utils.safestring import mark_safe
def test(request):
s = '<h1>这是一个h1标签</h1>'
res = mark_safe(s)
# locals()传值
return render(request, 'test.html', locals())
标签
**if判断 **
{% if s %}
<p>s</p>
{% else %}
<p>s为空</p>
{% endif %}
for循环
<!--对lis=[1, 2, 3]进行for循环-->
{% for foo in lis %}
<p>{{ foo }}</p>
{% endfor %}
for循环中有一个forloop对象
这玩意可以判断第一次循环和最后一次循环, 还可以记录循环次数
<!--forloop对象-->
{% for foo in lis %}
<p>{{ fooloop }}</p>
{% endfor %}

{% empty %} 当for循环的对象是空的时候, 就会触发
<!--lis为空-->
{% for foo in lis %}
<p>{{ foo }}</p>
{% empty %}
<p>lis为空</p>
{% endfor %}
结合使用
<!--对lis=[1, 2, 3]进行for循环-->
{% for foo in lis %}
{% if forloop.first %}
<p>这是第一次循环</p>
{% elif forloop.last %}
<p>这是最后一次循环</p>
{% else %}
<p>这是中间的循环</p>
{% endif %}
{% empty %}
<p>lis为空</p>
{% endfor %}
取别名: {% with... as ... %}
注意只能在with上下文中使用
{% with lis as l %}
<p>l</p>
{% endwith %}
注意: 不管你是字典还是列表, 模板语法的取值只有一种方式, 统一采用 . 取值的方式
自定义过滤器和标签
在应用名下新建一个
templatetags文件夹在该文件夹内新建一个任意名称的py文件, 比如
mytag.py在
mytag.py文件中
from django.template import Library
register = Library()
# 自定义过滤器
@register.filter(name='my_sum')
def index1(a, b):
return a + b
# 自定义标签
@register.simple_tag(name='my_tag')
def index2(a, b, c, d):
return f'{a}-{b}-{c}-{d}'
# 自定义inclusion_tag
"""
是一个函数, 能够接收参数, 可以返回一段html代码, 在哪里调用, 就把这段html代码放在哪里
"""
@register.inclusion_tag(filename='mytag.html', name='my_inclu')
def index3(n):
lis = []
for i in range(n):
lis.append(f'第{n}项')
return locals()
pass
- 如何使用自定义过滤器和标签
<!--首先将我们的自定义的py文件给导到html页面来-->
{% load mytag %}
<p>{ 1|my_sum:1 }</p>
<p>{% my_tag 'a' 'b' 'c' 'd' %}</p>
{% my_inclu 5 %}
注意: 自定义的过滤器可以在逻辑语句中使用, 而自定义的标签不可以
模板的继承
- 首先要在我们想要继承的html文件上划定可修改区域
{% block <blockname> %}
可修改区域
{% endblock %}
- 继承
{% extends 'home.html' %}
- 写可修改区域代码
{% block <对应父模板的可修改区域的名字> %}
可修改区域
{% endblock %}
- 在子页面沿用父页的内容
{% block <对应父模板的可修改区域的名字> %}
{{ block.super }}
{% endblock %}
模板的导入
- 将html文件当做模块导入使用
{% include 'html文件' %}
Django 04的更多相关文章
- Django 04 模板标签(if、for、url、with、autoeacape、模板继承于引用、静态文件加载)
Django 04 模板标签(if.for.url.with.autoeacape.模板继承于引用.静态文件加载) 一.if.for.url.with.autoescape urlpatterns = ...
- day61 Pyhton 框架Django 04
内容回顾 1.django处理请求的流程: 1. 在浏览器的地址栏输入地址,回车发get请求: 2. wsgi模块接收请求: 3. 在urls.py文件中匹配地址,找到对应的函数: 4. 执行函数,返 ...
- Ubuntu14.04 Django Mysql安装部署全过程
Ubuntu14.04 Django Mysql安装部署全过程 一.简要步骤.(阿里云Ubuntu14.04) Python安装 Django Mysql的安装与配置 记录一下我的部署过程,也方便 ...
- Ubuntu16.04 apache2 wsgi 部署django
在Ubuntu16.04上部署django其实还算简单直观,最重要的问题就是路径设置正确,并且保证版本统一,这个测试是在 Apache/2.4.18 (Ubuntu) apt-get install ...
- Ubuntu 14.04下Django+MySQL安装部署全过程
一.简要步骤.(Ubuntu14.04) Python安装 Django Mysql的安装与配置 记录一下我的部署过程,也方便一些有需要的童鞋,大神勿喷~ 二.Python的安装 由于博主使用的环境是 ...
- [Django] Setting up Django Development Environment in Ubuntu 14.04
1. Python Of course you will need Python. Still Python 2.7 is preferred, however if you would like t ...
- 在 ubuntu18.04 中搭建 Django 开发环境
在Ubuntu 18.04 安装 python3.pip3.pycharm,搭建 Django 开发环境. 1.安装 python3 pip3 sudo apt-get install python3 ...
- 如何在Ubuntu 18.04上安装Django
Django是一个免费的开源高级Python Web框架,旨在帮助开发人员构建安全,可扩展和可维护的Web应用程序. 根据您的需要,有不同的方法来安装Django.它可以使用pip在系统范围内安装或在 ...
- Python web项目Django部署在Ubuntu18.04腾讯云主机上
Django2.1 + Python3.6 + nginx + uwsgi 部署到Ubuntu18.04 材料准备 准备一个Django项目 准备一台Ubuntu18.04的主机 ssh连接到主机(腾 ...
随机推荐
- PHP 教你使用 Swoole-Tracker 秒级定位 PHP 卡死问题
PHPer 肯定收到过这样的投诉:小菊花一直在转!你们网站怎么这么卡!当我们线上业务遇到这种卡住(阻塞)的情况,大部分 PHPer 会两眼一抹黑,随后想起那句名言:性能瓶颈都在数据库然后把锅甩给DBA ...
- 为什么Python类语法应该不同?
做过python的人你会发现想要的东西跟它原有的是不同的.Python对我来说是真的是这样.如果可以的话,对于Python中很多的我想要改的东西,我有很多的想法.现在我向您讲述其中一个:类定义的语法. ...
- rabittmq详解
交换机(exchange): 声明交换机: Name Durability (消息代理重启后,交换机是否还存在) Auto-delete (当所有与之绑定的消息队列都完成了对此交换机的使用后,删掉它) ...
- thinkphp6.0 多应用模块下提示控制器不存在
thinkphp6.0 多应用模块下提示控制器不存在 在项目根目录下使用Composer composer require topthink/think-multi-app 参考链接
- hdu 1269 迷宫城堡 (tarjan)
迷宫城堡Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submiss ...
- .NET Core 获取数据库上下文实例的方法和配置连接字符串
目录 .NET Core 获取数据库上下文实例的方法和配置连接字符串 ASP.NET Core 注入 .NET Core 注入 无签名上下文 OnConfigure 配置 有签名上下文构造函数和自己n ...
- CSS:CSS弹性盒子布局 Flexible Box
一.简介 flexbox:全称Flexible Box, 弹性盒子布局.可以简单实现各种伸缩性的设计,它是由伸缩容器和伸缩项目组成.任何一个元素都可以指定为flexbox布局.这种新的布局方案在200 ...
- 初识JVM内存模型
计算机内存模型 在程序运行时,CPU通过访问主存获取数据,但随着CPU的快速发展,CPU访问速度越来越高,硬件无法满足CPU的条件下,大多内存加入了高速缓存机制,不同CPU都有对应的多级(一般为三)缓 ...
- 记一次LDAP主从同步配置
LDAP主从同步 OpenLDAP在2.3版本之前的同步复制带有一系列缺点如只支持一主多从模式等,在此缺点就不多说,下文着重介绍一下OpenLDAP V2.4以后的同步负复制功能 同步功能 2.4版最 ...
- proxy protocol
Proxy protocol 是haproxy 作者开发和设计的一个inernet 协议, 用于获取客户端的IP地址. 在使用7层代理是可以向http协议添加X-Forword-For来实现,而4层协 ...