上一小节我们成功从客户端访问的url中提取到了路径信息,但是路径里面包含的自定义信息毕竟少,更多的时候是通过查询参数和POST上去的内容。那么这一小节我们就来看看如何获取这些信息。
我是T型人小付,一位坚持终身学习的互联网从业者。喜欢我的博客欢迎在csdn上关注我,如果有问题欢迎在底下的评论区交流,谢谢。
操作环境
先总结下我的操作环境:
- Centos 7
- Python 3.7
- Pycharm 2019.3
- Django 2.2
因为Django长期支持版本2.2LTS和前一个长期支持版本1.11LTS有许多地方不一样,需要小心区分。
获取url的查询参数信息
实际场景的路径信息是不太频繁变换的,更多的请求信息都在查询参数当中,如果是POST场景下甚至都不在url里面。这些信息要怎么获取呢?需要借助于Django中的Request和Response对象了。这一节我们来认识一下这个Request对象,后面的小节我们再看Response。
Request和Response的详细说明可以参考官方文档
不管是GET或是POST方法,都会创建一个HttpRequest对象,Django会将这个对象传递给view函数的第一个参数request。同时每个view函数返回的一定是一个HttpResponse对象。
即使是render方法,返回的也是一个HttpResponse对象
通过这个HttpRequest对象的属性,不仅可以获得我们上面提到的信息,还有很多额外的东西可以提取出来。我们用实例来感受下。
创建路由以及view函数如下
path('sendrequest/',views.sendrequest),
def sendrequest(request):
print(request.path)
print(request.body)
print(request.method)
print(request.GET)
print(request.POST)
print(request.get_full_path())
print(request.headers)
return HttpResponse('Request Success.')
如果只是简单访问http://127.0.0.1:8000/two/sendrequest/
,打印出来的内容如下
/two/sendrequest/
b''
GET
<QueryDict: {}>
<QueryDict: {}>
/two/sendrequest/
{'Content-Length': '', 'Content-Type': 'text/plain', 'Host': '127.0.0.1:8000', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36', 'Sec-Fetch-Dest': 'document', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 'Sec-Fetch-Site': 'none', 'Sec-Fetch-Mode': 'navigate', 'Sec-Fetch-User': '?1', 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'en-US,en;q=0.9', 'Cookie': 'csrftoken=JsThoZrM2vXjwuRbpAiFPctv0wnVZdJrv6ACMojCttBADOYaQ21romkzRtd5gJ9T'}
可以看到,request.GET
和request.POST
返回了一个QueryDict类型的数据,这是字典类型的一个子类,区别就在于key可以重复。
QueryDict类型的官方文档
加一点查询参数进去试试,访问http://127.0.0.1:8000/two/sendrequest/?name=xiaofu&name=james&age=99&power=100
,打印出来的内容如下
/two/sendrequest/
b''
GET
<QueryDict: {'name': ['xiaofu', 'james'], 'age': ['99'], 'power': ['100']}>
<QueryDict: {}>
/two/sendrequest/?name=xiaofu&name=james&age=99&power=100
{'Content-Length': '', 'Content-Type': 'text/plain', 'Host': '127.0.0.1:8000', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36', 'Sec-Fetch-Dest': 'document', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 'Sec-Fetch-Site': 'none', 'Sec-Fetch-Mode': 'navigate', 'Sec-Fetch-User': '?1', 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'en-US,en;q=0.9', 'Cookie': 'csrftoken=JsThoZrM2vXjwuRbpAiFPctv0wnVZdJrv6ACMojCttBADOYaQ21romkzRtd5gJ9T'}
重点看一下request.GET
返回的内容
<QueryDict: {'name': ['xiaofu', 'james'], 'age': ['99'], 'power': ['100']}>
这时候直接用key应该就能获取value了,我们来试试,修改view函数如下
def sendrequest(request):
print(request.GET.get('name'))
return HttpResponse('Request Success.')
但是却发现,如果value是一个list的话,通过key只能取出list的最后一个值。
james
如果要取出整个list的话,需要用到另一个方法
def sendrequest(request):
print(request.GET.getlist('name'))
return HttpResponse('Request Success.')
打印出的结果如下
['xiaofu', 'james']
这里需要注意的是,即使查询参数只传递了一个值进来,也可以用getlist方法,此时获得的是一个单个元素的list,并不会报错
获取POST方法传递的内容
既然能获得GET方法传递的内容,当然获取POST方法也类似。同样用一个实例来验证一下。
首先创建路由和对应的view函数如下
path('submitinfo', views.submitinfo),
def submitinfo(request):
return render(request,'submitinfo.html')
然后创建对应的h5页面submitinfo.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sumbit Info</title>
</head>
<body>
<form action="{% url 'test_namespace:accept' %}" method="post">
<label for="name">Name:</label><input type="text" name="name" id="name" placeholder="Please input your name">
<br>
<label for="age">Age:</label><input type="text" name="age" id="age" placeholder="Please input your age">
<br>
<input type="submit">
</form>
</body>
</html>
这里是采用反向解析的方式创建的action链接,对应的路由和view函数如下
path('acceptinfo', views.acceptinfo, name='accept'),
def acceptinfo(request):
name = request.POST.get('name')
age = request.POST.get('age')
return HttpResponse('Name: {}, Age: {}'.format(name, age))
这时候如果在页面submitinfo.html
中填好信息点击Submit
的话,可能会在浏览器看到如下错误信息
Forbidden (403)
CSRF verification failed. Request aborted.
这里我们简便起见,直接先关闭Django中的CSRF中间件,在settings.py
中注释掉下面这行
'django.middleware.csrf.CsrfViewMiddleware',
csrf技术我们后面还会再讲
再去尝试,像如下当时填写信息
点击Submit
按钮后跳转到如下页面
说明提交上去的POST内容被成功捕获。
META信息
HttpRequest对象还有一个非常重要的属性叫做META,这里面包含了跟客户端有关的很多信息,甚至于包括用户名,home目录等等。
view函数中request.META
返回的是一个字典类型的数据,通过下面方法查看,具体结果因为涉及到太多个人机器信息我就不举例了,大家可以自己试试看。
for key in request.META:
print(key, request.META.get(key))
自定义错误码页面
这里顺便补充一下错误码的页面重写。
如果想重写默认的错误页面,例如404页面,不需要任何路由或者view函数,直接在模板文件夹中加一个404.html
即可。
因为没有修改到python代码,所以Django自带的测试服务器不会自动重启生效,必须手动重启。同时记得将settings.py
中的DEBUG开关调整为False。
因为就近原则,我们重写的404页面会覆盖系统自带的404页面。如果想查看系统自带的404页面,可以点击右侧的放大镜进行全局搜索,或者是点击两下Shift调出全局搜索框。勾选Include Non-project items,然后搜索404。就会找到Admin/404.html
页面了。
总结
这一小节我们通过HttpRequest对象获取到了我们想要的信息,下一小节我们来看看另一个更为强大的HttpResponse对象。