4-1 请求和响应-DRF请求和响应
目录:
- DRF请求和响应介绍
- 装饰器视图 @api_view(['GET','POST'])
- 类视图:APIView
一、DRF请求和响应
请求和响应:
目前我们用的都是Django 里面的 request、也是Django 里面的 response,状态也是django里面的。但是 DRF里面的 request是基于 django 里面的 request 进行的封装。
请求(request):
REST里面有个HttpRequest特别相似的对象叫request,主要获取前端传递过来的数据,获取数据的方法就是request.data
响应(Response):
REST里面有个HttpResponse特别相似的对象叫Response,主要用来给前端传递数据,传递数据的方法就是Response(data)
状态码(status):
REST里面的状态码比较人性化。每个状态都用意思去表示。比如:
HTTP_200_OK = 200 #OK HTTP_201_CREATED = 201 #创建成功 HTTP_403_FORBIDDEN = 403 # 权限拒绝 ''' '''
API视图:
API视图主要为了咱们RESTFUL风格的API。主要用来包装request,response、现在api请求方法。
- 基于函数视图的
@api_view(['GET','POST'])装饰器 - 基于类视图的
APIView类
二、装饰器视图 @api_view(['GET','POST'])
我们根据 DRF 提供我们的 api_view、Response、status、request 来重写我们的视图函数
from .serializers import UserSerializer
from .models import User
from rest_framework.decorators import api_view
from rest_framework.response import Response #提供drf的响应
from rest_framework import status #提供DRF状态码
@api_view(['GET', 'POST']) #首先告诉它支持哪些方法,而且装饰之后不需要crf_token验证,因为api_view已经帮我们做了验证
def user_list(request): #用了api_view装饰器之后,这边的request就已经是DFR的request了。
if request.method == "GET":
arts = User.objects.all()
ser = UserSerializer(instance=arts, many=True, context={'request': request})
return Response(ser.data, status=status.HTTP_200_OK) #直接把序列化数据很状态码传入进去
elif request.method == "POST":
#获取入参直接是 request.data 即可获取
ser = UserSerializer(data=request.data, context={'request': request})
if ser.is_valid():
ser.save()
return Response(ser.data, status=status.HTTP_201_CREATED)
return JSONResponse(ser.errors, status=status.HTTP_401_UNAUTHORIZED)
知识点说明:
@api_view(['GET', 'POST']):
1.告诉它需要支持哪些方法:这边支持POST和GET
2.装饰完api_view,不在需要crf_token验证了,因为api_view已经帮你封装好了
3.用了api_view装饰器之后,request就已经是DRF的request了,不再是 django的 request了 => 调用直接 request.data
drf的响应:from rest_framework.response import Response => Response(data,status=status.HTTP_201_CREATED)
提供DRF状态码:from rest_framework import status => status.HTTP_201_CREATED
我们通过页面来访问一下:(当然也可以通过postman访问)

三、类视图:APIView
我们还有一种方法,可以通过 类视图:APIView,功能跟我们的 @api_view 一样,只不过采用的是CBV的方式
3.1、视图
说明:编辑views.py文件,增加视图类
from .serializers import UserSerializer
from .models import User
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from rest_framework.views import APIView #提供类视图
from django.http import Http404 #提供django的404状态码
@api_view(['GET', 'POST'])
def user_list(request):
...
class UserDetail(APIView): #采用类视图,定义 get、patch、put和delete
def get_object(self, id):
try:
user = User.objects.get(id=id)
return user
except User.DoesNotExist as e:
return Http404
def get(self,request, *args, **kwargs):
user = self.get_object(kwargs.get('id')) #根据传值 **kwargs获取id的值
ser = UserSerializer(instance=user,context={"request": request})
return Response(ser.data, status=status.HTTP_200_OK)
def put(self, request, *args, **kwargs):
user = self.get_object(kwargs.get('id'))
ser = UserSerializer(instance=user,data=request.data, context={"request": request}) #request是drf的了,所以获取数据request.data
if ser.is_valid():
ser.save()
return Response(ser.data, status=status.HTTP_201_CREATED)
return Response(ser.errors, status=status.HTTP_400_BAD_REQUEST)
def patch(self, request, *args, **kwargs):
user = self.get_object(kwargs.get('id'))
ser = UserSerializer(instance=user, data=request.data, context={"request": request},partial=True)
if ser.is_valid():
ser.save()
return Response(ser.data, status=status.HTTP_201_CREATED)
return Response(ser.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, *args, **kwargs):
user = self.get_object(kwargs.get('id'))
user.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
3.2、路由配置
说明:因为我们是采用CBV的方式,所以路由的方式要改变
from django.urls import path
from app03 import views
urlpatterns = [
path("user/", views.user_list, name="user-list"), #FBV的方式
path("user/<int:id>/", views.UserDetail.as_view(), name="user-detail") #cbv方式 => views.UserDetail.as_view()
]
这边还有一个地方需要注意:就是我们前面讲的,在输入 pwd1验证的时候,因为pwd1不属于 User模型类字段,所以我们需要 pop掉,但是这边会报错,所以我们代码优化如下:
编辑 serializers.py文件:
....
class UserSerializer(serializers.ModelSerializer):
....
class Meta:
....
def validate_phone(self, phone): #单个验证
...
def validate(self, attrs): #组合验证
if attrs.get('pwd1') != attrs.get('pwd'):
raise serializers.ValidationError("两次密码不一样")
if "pwd1" in attrs: #这边需要加一个验证,当我通过patch传进来的时候,没有pwd1的参数,则我不删除
attrs.pop('pwd1')
return attrs
3.3、运行结果
1、页面访问:

2、postman请求:
1.GET: http://127.0.0.1:8000/api/user/1/
出参:
{
"id": 1,
"phone": "13641929921",
"name": "gaogao",
"gender": 1
}
2.POST:http://127.0.0.1:8000/api/user/
入参:
{
"phone": "13641929930",
"gender": 2,
"name": "gaogao",
"pwd": "1234",
"pwd1": "1234"
}
出参:
{
"id": 6,
"phone": "13641929930",
"name": "gaogao",
"gender": 2
}
3.PUT:http://127.0.0.1:8000/api/user/1/
入参:
{
"id": 1,
"phone": "13641929923",
"name": "gaogege",
"gender": 1,
"pwd": "1234",
"pwd1": "1234"
}
出参:
{
"id": 1,
"phone": "13641929923",
"name": "gaogege",
"gender": 1
}
4.PATCH: http://127.0.0.1:8000/api/user/1/
入参:
{
"id": 1,
"phone": "13641929924",
"gender": 2
}
出参:
{
"id": 1,
"phone": "13641929924",
"name": "gaogege",
"gender": 2
}
5、DELETE:http://127.0.0.1:8000/api/user/1/
出参:
[]

浙公网安备 33010602011771号