汕头哪里做网站/hao123影视
类视图
- 为同一接口支持不同的请求类型
- request
- 支持不同的请求类型
- 类视图
- 前后端不分离
- 前后端分离
- 后端给前端返回json数据
- 后端解析前端的数据
- query string参数接收
- 请求体参数接收
- x-www-form-urlencoded
- json参数
- form-data
- 请求头参数
为同一接口支持不同的请求类型
request
我们知道当URL文件匹配到用户输入的路径后,会调用对应的view函数,并将request对象作为第一个参数传入该函数。request就是HttpRequest对象的实例,属性包含了关于此次请求的大多数重要信息。
支持不同的请求类型
既然request带有类型,我们就根据不同类型判断,执行对应的操作。修改子应用的views.py文件。
def login(request):if request.method == 'GET':return HttpResponse('Hello, 这是一个get请求的登录的页面!')elif request.method == 'POST':return HttpResponse('Hello, 这是一个post请求的登录的页面!')else:return HttpResponse(f'Hello, 这是一个其他请求的登录的页面!{request.method}')
测试的时候发现,除get外,其他请求方式会报403错误。
这是因为Django发起其他请求时,会验证CSRF,需要携带CSRF TOKE才行,如果没有,就会报这个异常。我们可以在setting.py文件中关掉CsrfViewMiddleware中间件。
但是这种函数视图不好管理,所有的代码都在一个方法中,不好维护,我们可以使用类视图来优化一下。
类视图
我们将上面那个例子改写成类视图的写法:
class user_login(View):def get(self, request):return HttpResponse('Hello, 这是一个get请求的登录的页面!')def post(self, request):return HttpResponse('Hello, 这是一个post请求的登录的页面!')def put(self, request):return HttpResponse('Hello, 这是一个put请求的登录的页面!')
需要注意的是类视图要继承View。不同的请求方式是与请求方法对应的,如get请求就会自动调用get方法。
看了View的源码,支持的请求方式有:http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
修改完视图后,还需新增一个路由。修改urls.py文件:
urlpatterns = [path('user_login/', user_login.as_view()),
]
与函数视图的路由不同的是,第二个参数为函数名.as_view()
。
总结一下,类视图可读性和复用性更好,不同的请求方式以不同的方法呈现,后面我们就都用类视图了。
我们前面的例子都有一个问题,就是没有一个完整的前端页面,我们现在把前端页面也加上。
在项目根目录新建一个templates文件夹,专门放前端代码。在此文件夹中新建一个login.html。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>项目列表页</title><style>.container-fluid {margin-top: 100px;}.table-striped th, .table-striped td {text-align: center;}</style>
</head>
<body><div class="container-fluid"><div class="row" style="margin-bottom: 30px"><div class="col"></div><div class="col"><h2 class="text-center text-info">项目列表信息</h2></div><div class="col"></div></div><div class="row"><div class="col"></div><div class="col"><table class="table table-striped"><thead class="thead-dark"><tr><th scope="col">序号</th><th scope="col">项目名称</th><th scope="col">项目负责人</th><th scope="col">应用名称</th></tr></thead><tbody><tr><th scope="row">1</th><td>一个测试项目</td><td>Aaron</td><td>测试项目</td></tr></tbody></table></div><div class="col"></div></div></div>
</body>
</html>
写完前端代码后,还需要在setting.py文件中指定前端代码的存放路径。
然后修改子应用的views.py文件,在适当的时候返回这个页面。
class user_login(View):def get(self, request):return render(request, 'login.html')
再刷新一下页面就看到效果了。
前后端不分离
前面的例子有一个缺点,就是页面是写死的,但是一般来说,我们前端页面的数据都是从数据库取的,所以还需要在修改一下。
将前端的页面修改一下,把刚才写好的数据删掉,替换成动态的(这个不需要掌握,了解一下即可):
{% for foo in datas %}<tr><th scope="row">{{ forloop.counter }}</th><td>{{ foo.project_name }}</td><td>{{ foo.leader }}</td><td>{{ foo.app_name }}</td></tr>
{% endfor %}
修改子应用的views.py文件。
class user_login(View):def get(self, request):# 假设这是从数据库取的数据datas = [{"project_name": "项目1","leader": "Aaron","app_name": "第一个app"},{"project_name": "项目2","leader": "小伍","app_name": "第二个app"},]return render(request, 'login.html', context=locals()) # context参数把数据传到html中
此时就可以看到前端页面数据是上面列表中的数据了。
但是这种方法不好,前后端职责不清,后端还需要去改前端代码,造成项目管理混乱,而且拓展性也差。所以一般我们不使用这种做法。我们采用前后端分离来做。
前后端分离
后端给前端返回json数据
如果需要后端给前端返回数据,那么子应用的views.py文件中,该方法的返回值就需要修改一下:
def get(self, request, pk):# a.使用JsonResponse可以返回json数据# b.如果第一个参数为字典,那么无需指定safe关键字参数# c.如果第一个参数为嵌套字典的列表,那么必须指定safe=False关键字参数# d.可以使用status来指定响应状态码return JsonResponse(data=datas, safe=False, status=201)
后端解析前端的数据
query string参数接收
http://127.0.0.1:8000/login/user_login/?name=Aaron&age=18中的?name=Aaron&age=18
就是query string查询字符串参数。
通过debug我们不难发现,传入的参数在request对象中。
我们通过
request.GET
就能获取到前端传来的query string字符串参数,request.GET获取到的是一个QueryDict类型的参数,这是继承了Dict的类型,我们可以使用字典的取值方式来取值。
如果字符串参数中的key重复,会把相同key的值放入列表。例如:?name=Aaron&age=18&name=heihei,我们获取到的就是{‘name’:['Aaron','heihei'],'age','18'}
,此时再使用字典获取值的方式获取name,获取到的数据就是‘heihei’,我们想要获取到name列表,就要用到QueryDict的getlist方法来获取。request.GET.getlist('name')
。
请求体参数接收
x-www-form-urlencoded
可以使用request.POST
获取x-www-form-urlencoded参数,具体操作方式同上面的query string参数。
json参数
可以使用request.body
获取json参数,获取到的是字节类型,我们需要使用decode('utf-8')
进行解码,解码后得到一个json的字符串形式,我们在转换成字典就可以取值了。
json_dict = json.loads(request.body.decode('utf-8')) # {‘name’:'Aaron','age','18'}
form-data
form-data和x-www-form-urlencoded的区别是form-data可以传文件参数,form-data的文本参数使用request.POST
获取,非文本参数使用request.body
获取。
请求头参数
可以使用request.META
获取请求头参数,传入的请求头参数为{‘name’:‘Aaron’,‘age’,‘18’},python会把参数名转换为大写,并且加上前缀HTTP_
。如果参数名有-,就转换成_。