文章目录
前言
视图函数的返回值
为什么视图函数需要返回一个HttpResponse对象?
可以用一个例子来看看:(前提先配置好路由)
def index(request):
return None
然后我们直接开启服务,访问这个路由地址
三板斧源码大概注解
而其中HTML的三种响应方式返回的都是一个HttpResponse对象(可以查看源码)
'''源码大概注解展示'''
class HttpResponse(HttpResponseBase):
'''括号内直接跟一个具体的字符串作为响应体'''
streaming = False # 表示是否支持流式传输
# 初始化HttpResponse实例,设置响应的内容
def __init__(self, content=b'', *args, **kwargs):
super(HttpResponse, self).__init__(*args, **kwargs)
# Content is a bytestring. See the `content` property methods.
self.content = content
......
====================================================================================
def render(request, template_name, context=None, content_type=None, status=None, using=None):
'''
request:用于生成响应的请求对象
template_name:要使用的模版的完整名称,可选的参数
context:添加到模版上细纹的一个字典。默认是空字典。如果字典中的某一个值是可调用的,视图将在渲染模版之前调用它。
render方法就是将一个模版页面中的模版语法进行渲染,最终渲染成一个html页面作为响应体
'''
# 使用Django的模版引擎加载和渲染模版
content = loader.render_to_string(template_name, context, request, using=using)
# 返回一个HttpResponse对象加括号调用HttpResponse的类
return HttpResponse(content, content_type, status)
====================================================================================
def redirect(to, *args, **kwargs):
'传递要重定向的一个硬编码的URL或者路由'
if kwargs.pop('permanent', False):
'如果参数中包含 'permanent',并且其值为 True,则使用 HttpResponsePermanentRedirect 类'
redirect_class = HttpResponsePermanentRedirect
else:
'否则使用默认的 HttpResponseRedirect 类'
redirect_class = HttpResponseRedirect
'''
这里返回一个HttpResponse对象加括号调用HttpResponse的类
创建相应的重定向对象,将重定向目标设置为 to
'''
return redirect_class(resolve_url(to, *args, **kwargs))
'''
这样的设计使得 redirect 函数能够支持两种类型的重定向:
临时重定向(HttpResponseRedirect)和永久重定向(HttpResponsePermanentRedirect),
具体取决于 'permanent' 参数的值。
'''
三板斧的使用
HttpResponse
示例:
from django.shortcuts import HttpResponse
def my_custom_response(request):
# 一些逻辑处理后,生成自定义的响应内容
content = 'This is a custom response.'
# 使用HttpResponse类创建HTTP响应
response = HttpResponse(content, content_type='text/plain', status=200)
# 可以添加自定义的头部信息
response['Custom-Header'] = 'Some value'
return response
from django.shortcuts import HttpResponse
def index(request):
response = HttpResponse() # 实例化产生一个对象
response.content = 'Lucky' # 设置响应内容
response.status_code = 404 # 设置响应状态码
# 直接写出文本
response.write('777777')
# 一次性读取剩余字节,冲刷缓存区
response.flush()
return response
redirect
示例:
from django.shortcuts import redirect
def my_redirect_view(request):
# 某些逻辑处理后,决定重定向到另一个URL
new_url = '/index/'
# 使用redirect函数生成重定向响应
return redirect(new_url)
render
示例:
from django.shortcuts import render
def my_view(request):
# 从数据库获取数据或进行其他逻辑处理
data = {'foo': 'bar'}
# 使用render函数渲染模板,并将数据传递给模板
return render(request, 'my_template.html', {'data': data})
总结:
JsonResponse对象
视图函数返回json格式的数据
方法一
json序列化形式
import json
def Myjson(request):
user_dict = {'name':'oscar','age':18,'hobby':['唱','跳','rap']}
'''如果数据中有中文会进行编码,如果不想它编码就直接设置ensure_ascii=False即可'''
data = json.dumps(user_dict,ensure_ascii=False)
return HttpResponse(data)
方法二
JsonResponse序列化形式
'需要先导入JsonResponse模块'
from django.http import JsonResponse
def js(request):
user_dict = {'name': 'oscar', 'age': 18, 'hobby': ['唱', '跳', 'rap']}
return JsonResponse(user_dict)
form表单携带文件数据
注意事项:
-
enctype属性需要由默认的urlencoded变成form/data(enctype=“multipart/form-data”)
-
method属性需要由默认的get变成post
(目前还需要考虑的是 提交post请求需要将配置文件中的csrf中间件注释) -
如果form表单上传文件 后端需要在request.FILES获取文件数据 而不再是POST里面
首先需要建立一个HTML页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
<input type="text" name="text" placeholder="请输入文字">
<input type="file" name="myfile">
<input type="submit" value="提交">
</form>
</body>
</html>
然后再建立路由和视图函数
'路由文件'
from app import views
urlpatterns = [
url(r'^func/', views.func),
]
'视图文件'
def func(request):
print(request.POST)
return render(request,'index.html')
配置后这些后,直接访问对应的路由,然后点击选择文件后提交
结果发现仅仅只是接收到了普通文本数据,并没有接收到文件数据
这时我们可以使用request.FILES
来获取文件数据
def func(request):
print(request.POST)
print(request.FILES)
return render(request,'index.html')
然后我们可以通过对获取到的文件数据进行写入文件中
- 首先我们从上述过程中,可以知道,得到的数据格式是字典格式,所以我们可以通过字典的方式取出数据
def func(request):
if request.method == 'POST':
file_info= request.FILES.get('myfile')
print(res)
return render(request,'index.html')
- 拿到名字后就可以通过写入文件的方式写入文件数据了,
但是要注意需要使用wb模式写入
,因为wb模式可以把二进制数据转换成str格式。
def func(request):
if request.method == 'POST':
# print(request.FILES)
file_info = request.FILES.get('myfile')
with open(file_info.name,'wb')as f:
'避免文件数据过大,使用一行一行的写入'
for line in file_info:
f.write(line)
return render(request,'index.html')
request对象方法
1.获取请求方式POST/GET
request.method
一个字符串,表示请求使用的HTTP 方法。必须使用大写。
2.request.POST
获取POST请求提交普通的键值对数据 一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成
3.获取GET请求
request.GET
获取GET请求 一个类似于字典的对象,包含 HTTP GET 的所有参数
4.获取文件
request.FILES
一个类似于字典的对象,包含所有的上传文件信息。
FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会包含数据。否则,FILES 将为一个空的类似于字典的对象。
5.原生的浏览器发过来的二进制数据
request.body
一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,
例如:二进制图片、XML,Json等。
6.拿到路由
request.path
个字符串,表示请求的路径组件(不含域名)
7.拿到路由
request.path_info
8.能过获取完整的url及问号后面的参数
request.get_full_path()
FBV与CBV
FBV
CBV
Python是一个面向对象的编程语言,如果只用函数来开发,很多面向对象的优点就错失了(继承、封装、多态)。所以Django在后来加入了Class-Based-View。可以让我们用类写View。这样做的优点主要下面两种:
- 提高代码的复用性,可以使用面向对象的技术。
- 根据不同的类方法处理不同的HTTP请求,而不是通过很多if判断,提高代码可读性。
如果要写一个处理GET请求的view,FBV是这样写的
路由文件
from app import views
urlpatterns = [
url(r'^test/',views.test)
]
视图文件
from django.shortcuts import HttpResponse
def test(request):
if request.method == 'GET':
return HttpResponse('this is test')
使用CBV是这样写的
路由文件
from app import views
urlpatterns = [
url(r'^Mytest/',views.My_test.as_view()),
]
视图文件
from django.shortcuts import HttpResponse
from django.views import View
class My_test(View):
def get(self,request):
return HttpResponse('this is test')
CBV类中的不能随意的定义函数,只能使用八大请求方式
'get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'
'所有的类必须继承django的view类'
from django.views import View
class MyLogin(View):
# 类里面的方法名字不能够随便写,目前只能写get post等
# 访问这个地址必须是get请求方式
def get(self, request):
# get() takes 1 positional argument but 2 were given
print("get")
return HttpResponse("get")
# 访问这个方法必须是psot请求方式
# 通过form表单发送post请求
# 出了form表单,我们还可以使用工具来模拟
def post(self,request):
print("post")
return HttpResponse("post")
postman的官网地址:https://www.postman.com/downloads/
apizza的挂网地址:http://www.apizza.net/
CBV的源码解析
urlpatterns = [
url('^index/', views.index.as_view())
# 手动调用后会拿到view方法的返回值。变成了以下的样子
url('^index/', views.index.view)
# 那么此时Django会帮助我们调用一次这个方法,并且传递一个request请求过去。
]
view方法解析
那么我们再看看view方法干了些什么事情:只看红框内容即可
- 首先是根据cls实例化出一个对象了(这cls就是我们在视图内定义的类)
- 将request请求给这个对象作为属性
- 而args、kwargs则是防止有名分组或无名分组,用于接收分组产生的值。也一同赋给这个对象。
- 调用这个对象下面的dispatch方法,并将Django传递的参数一并传递过去了
dispatch方法解析
再分析一下dispatch方法的作用:只关注红框内容即可
request.method.lower()
将请求的方法变成小写的字符串
主要就是判断:发送请求的方法是否符合正常HTTP请求
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
如果符合的话:使用反射通过拿到的字符串去对象里查找相同名称的函数。比如:
class index(View):
def get(self,request):
return HttpResponse('from GET')
self = index类实例化的对象,并且拥有request、args、kwargs等属性
# 等同于:如果request.method.Lower()是get的话,拿到get方法的函数对象
handle = getattr(self,'get',None) # 地三个参数则是没有找到get方法或属性返回的
handle = get函数对象
handle(request,*args,**kwargs) # 等同于:get(self,request,*args,**kwargs)
调用时将request请求、一些额外参数都传递给了我们定义的类里面的get方法
演示:不定义人任何处理请求的函数
class index(View):
pass
浏览器得不到Django响应的任何数据!
get方法需要返回一个HttpResponse对象,没有返回的话,则页面报错
class index(View):
def get(self,request):
print('......')
注意:如果类里面没有定义处理对应请求的函数,浏览器得不到响应,专门处理某个请求的函数名一定要与请求名一致。
总结
而CBV的实现通过上述源码的分析也可以看出来,大致就是通过URL执行类里面的view方法,再通过其内部的dispatch方法进行分发处理,将浏览器请求交给我们的类里面对应的方法进行处理。