【2022-09-29】DRF从入门到入土(四)
drf请求与响应
Request
REST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。
REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典[QueryDict]对象保存到Request对象中。
Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。
无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。
常用属性
# 继承APIView后,请求对象:requets---》每一次请求都是一个新的request
# Request类:属性或方法
data:POST、PUT、PATCH请求方式解析后的数据
原生djagno,put提交的数据在request.POST中是取不到的
query_params
其他的用起来跟之前一样用(FILES,method,path....)--->底层原理 __getattr__
Response
REST framework提供了一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。
REST framework提供了Renderer 渲染器,用来根据请求头中的Accept(接收数据类型声明)来自动转换响应数据到对应格式。如果前端请求中未进行Accept声明,则会采用默认方式处理响应数据,我们可以通过配置来修改默认响应格式。
常用属性
data=None, # 字典,列表---》序列化成json格式字符串,返回给前端(放在http响应的body中了)
status=None, # http 响应的状态码,默认是200,201
drf帮咱们把所有的http响应状态码都做成了常量,可以直接导进来用
headers=None, # http的响应头,字典 {name:jason}
template_name=None, # 了解:在浏览器中看到好看的页面,指定的模板
content_type=None # 响应的编码格式(json)
实例
import json
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class Test(APIView):
def get(self, request):
d = {'name': 'lisa', 'hobby': 'run'}
# return HttpResponse(json.dumps(d))
# return JsonResponse(d)
# return Response(d, status=status.HTTP_400_BAD_REQUEST, headers={'name': 'jason'}) 响应头添加数据,状态码修改
# 原生Django给响应头里添加数据,使用下面的方法:
info = HttpResponse(json.dumps(d))
info['age'] = '18'
return info
参数说明
data: 为响应准备的序列化处理后的数据;
status: 状态码,默认200;
template_name: 模板名称,如果使用HTMLRenderer 时需指明;
headers: 用于存放响应头信息的字典;
content_type: 响应数据的Content-Type,通常此参数无需传递,REST framework会根据前端所需类型数据来设置该参数。
响应状态码
# 正常返回信息1xx
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
# 返回成功2xx
HTTP_200_OK
HTTP_201_CREATED
HTTP_202_ACCEPTED
HTTP_203_NON_AUTHORITATIVE_INFORMATION
HTTP_204_NO_CONTENT
HTTP_205_RESET_CONTENT
HTTP_206_PARTIAL_CONTENT
HTTP_207_MULTI_STATUS
# 重定向3xx
HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT
# 客户端错误4xx
HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_402_PAYMENT_REQUIRED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_406_NOT_ACCEPTABLE
HTTP_407_PROXY_AUTHENTICATION_REQUIRED
HTTP_408_REQUEST_TIMEOUT
HTTP_409_CONFLICT
HTTP_410_GONE
HTTP_411_LENGTH_REQUIRED
HTTP_412_PRECONDITION_FAILED
HTTP_413_REQUEST_ENTITY_TOO_LARGE
HTTP_414_REQUEST_URI_TOO_LONG
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
# 客户端错误5xx
HTTP_500_INTERNAL_SERVER_ERROR
HTTP_501_NOT_IMPLEMENTED
HTTP_502_BAD_GATEWAY
HTTP_503_SERVICE_UNAVAILABLE
HTTP_504_GATEWAY_TIMEOUT
HTTP_505_HTTP_VERSION_NOT_SUPPORTED
HTTP_507_INSUFFICIENT_STORAGE
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED
请求编码
# drf默认能够解析三种编码格式:
urlencoded
form-data
json
# 我们创建的项目中没有配置文件,是在drf内置的配置文件中提前配好了,如果需要,可以在我们自己创建的项目中的settings.py文件中配置即可
-drf也是有两套,一套是项目中得配置(settings.py),一套是默认的配置
-drf的配置文件settings.py中有 DEFAULT_PARSER_CLASSES(默认的解析类)
-'rest_framework.parsers.JSONParser', 可以解析json格式
-'rest_framework.parsers.FormParser', 可以解析urlencoded格式
-'rest_framework.parsers.MultiPartParser' 可以解析form-data格式
想让我们的接口只能接受json格式
方式一:全局配置---》项目配置文件---》以后所有的接口都遵循这个配置
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
# 'rest_framework.parsers.FormParser',
# 'rest_framework.parsers.MultiPartParser',
],
}
方式二:局部配置
class TestView(APIView):
parser_classes = [JSONParser,FormParser,MultiPartParser]
总结:
解析类的使用顺序:优先用视图类自己的,然后用项目配置文件,最后用内置的
实际项目如何配置
基本上都运行JSONParser,FormParser
如果上传文件只允许MultiPartParser
响应编码
# 如果用浏览器,好看的样子,如果用postman看到json格式
-默认请情况下,响应的编码是根据客户端类型决定的
# 全局配置:在项目的配置文件
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
# 'rest_framework.renderers.JSONRenderer', # json格式
'rest_framework.renderers.BrowsableAPIRenderer', #浏览器的格式
]
}
# 局部配置:
class TestView(APIView):
renderer_classes = [JSONRenderer,]
# 实际编码中,响应一般不配,就用默认
drf视图组件
Django REST framwork 提供的视图的主要作用:
- 控制序列化器的执行(检验、保存、转换数据)
- 控制数据库查询的执行
2个视图基类
1 APIView
2 GenericAPIView-->继承了APIView
-类属性:
queryset = User.objects.all()
serializer_class = UserSerializer
-方法:
self.get_object() # 根据pk获取单个数据
self.get_serializer # 获取要使用的序列化类
self.get_queryset() # 获取所有要序列化数据
自主练习
基于APIView+ModelSerializer写出图书表接口和用户表接口
urls.py
from django.contrib import admin
from django.urls import path
from app01.views import BookView, BookDetailView, UserView, UserDetailView
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', BookView.as_view()),
path('books/<int:pk>/', BookDetailView.as_view()),
path('user/', UserView.as_view()),
path('user/<int:pk>/', UserDetailView.as_view()),
]
models.py
from django.db import models
# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
publish = models.CharField(max_length=32)
class User(models.Model):
name = models.CharField(max_length=32)
age = models.CharField(max_length=32)
gender = models.CharField(max_length=32)
address = models.CharField(max_length=255)
Serializer.py
from rest_framework import serializers
from .models import Book, User
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
class UserModelSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
views.py
from django.shortcuts import render
from rest_framework.views import APIView
# Create your views here.
from .models import Book, User
from .serializer import BookModelSerializer, UserModelSerializer
from rest_framework.response import Response
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
info = BookModelSerializer(instance=book_list, many=True)
return Response(info.data)
def post(self, request):
info = BookModelSerializer(data=request.data)
if info.is_valid():
info.save()
return Response({'code': 666, 'msg': '新增成功'})
else:
return Response({'code': 777, 'msg': info.errors})
class BookDetailView(APIView):
def get(self, request, pk):
book = Book.objects.filter(pk=pk).first()
info = BookModelSerializer(instance=book)
return Response(info.data)
def put(self, request, pk):
book = Book.objects.filter(pk=pk).first()
info = BookModelSerializer(instance=book, data=request.data)
if info.is_valid():
info.save()
return Response({'code': 666, 'msg': '修改成功'})
else:
return Response({'code': 777, 'msg': info.errors})
def delete(self, request, pk):
Book.objects.filter(pk=pk).delete()
return Response({'msg': '删除成功'})
class UserView(APIView):
def get(self, request):
user_list = User.objects.all()
info = UserModelSerializer(instance=user_list, many=True)
return Response(info.data)
def post(self, request):
info = UserModelSerializer(data=request.data)
if info.is_valid():
info.save()
return Response({'code': 666, 'msg': '新增成功'})
else:
return Response({'code': 777, 'msg': info.errors})
class UserDetailView(APIView):
def get(self, request, pk):
user = User.objects.filter(pk=pk).first()
info = UserModelSerializer(instance=user)
return Response(info.data)
def put(self, request, pk):
user = User.objects.filter(pk=pk).first()
info = UserModelSerializer(instance=user, data=request.data)
if info.is_valid():
info.save()
return Response({'code': 666, 'msg': '修改成功'})
else:
return Response({'code': 777, 'msg': info.errors})
def delete(self, request, pk):
User.objects.filter(pk=pk).delete()
return Response({'msg': '删除成功'})
基于GenericAPIView写出图书表接口和用户表接口
urls.py
from django.contrib import admin
from django.urls import path
from app01.views import BookView, BookDetailView, UserView, UserDetailView
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', BookView.as_view()),
path('books/<int:pk>/', BookDetailView.as_view()),
path('user/', UserView.as_view()),
path('user/<int:pk>/', UserDetailView.as_view()),
]
models.py
from django.db import models
# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
publish = models.CharField(max_length=32)
class User(models.Model):
name = models.CharField(max_length=32)
age = models.CharField(max_length=32)
gender = models.CharField(max_length=32)
address = models.CharField(max_length=255)
Serializer.py
from rest_framework import serializers
from .models import Book, User
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
class UserModelSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
views.py
from .models import Book, User
from .serializer import BookModelSerializer, UserModelSerializer
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView
class BookView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookModelSerializer
def get(self, request):
book_list = self.get_queryset()
info = self.get_serializer(instance=book_list, many=True)
return Response(info.data)
def post(self, request):
info = self.get_serializer(data=request.data)
if info.is_valid():
info.save()
return Response({'code': 666, 'msg': '新增成功'})
else:
return Response({'code': 777, 'msg': info.errors})
class BookDetailView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookModelSerializer
def get(self, request, pk):
book = self.get_object()
info = self.get_serializer(instance=book)
return Response(info.data)
def put(self, request, pk):
book = self.get_object()
info = self.get_serializer(instance=book, data=request.data)
if info.is_valid():
info.save()
return Response({'code': 666, 'msg': '修改成功'})
else:
return Response({'code': 777, 'msg': info.errors})
def delete(self, request, pk):
self.get_queryset().filter(pk=pk).delete()
return Response({'msg': '删除成功'})
class UserView(GenericAPIView):
queryset = User.objects.all()
serializer_class = UserModelSerializer
def get(self, request):
user_list = self.get_queryset()
info = self.get_serializer(instance=user_list, many=True)
return Response(info.data)
def post(self, request):
info = self.get_serializer(data=request.data)
if info.is_valid():
info.save()
return Response({'code': 666, 'msg': '新增成功'})
else:
return Response({'code': 777, 'msg': info.errors})
class UserDetailView(GenericAPIView):
queryset = User.objects.all()
serializer_class = UserModelSerializer
def get(self, request, pk):
user = self.get_object()
info = self.get_serializer(instance=user)
return Response(info.data)
def put(self, request, pk):
user = self.get_object()
info = self.get_serializer(instance=user, data=request.data)
if info.is_valid():
info.save()
return Response({'code': 666, 'msg': '修改成功'})
else:
return Response({'code': 777, 'msg': info.errors})
def delete(self, request, pk):
self.get_queryset().filter(pk=pk).delete()
return Response({'msg': '删除成功'})
继承GenericAPIView+父类写出图书表接口
urls.py
from django.contrib import admin
from django.urls import path
from app01.views import BookView, BookDetailView
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', BookView.as_view()),
path('books/<int:pk>/', BookDetailView.as_view()),
models.py
from django.db import models
# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
publish = models.CharField(max_length=32)
class User(models.Model):
name = models.CharField(max_length=32)
age = models.CharField(max_length=32)
gender = models.CharField(max_length=32)
address = models.CharField(max_length=255)
Serializer.py
from rest_framework import serializers
from .models import Book, User
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
class UserModelSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
views.py
from .models import Book, User
from .serializer import BookModelSerializer, UserModelSerializer
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView
class GetBooks(object):
def get(self, request):
book_list = Book.objects.all()
info = BookModelSerializer(instance=book_list, many=True)
return Response(info.data)
class AddBook(object):
def post(self, request):
info = BookModelSerializer(data=request.data)
if info.is_valid():
info.save()
return Response({'code': 666, 'msg': '新增成功'})
else:
return Response({'code': 777, 'msg': info.errors})
class BookView(GenericAPIView, GetBooks, AddBook):
queryset = Book.objects.all()
serializer_class = BookModelSerializer
class GetBook(object):
def get(self, request, pk):
book = Book.objects.filter(pk=pk).first()
info = BookModelSerializer(instance=book)
return Response(info.data)
class PutBook(object):
def put(self, request, pk):
book = Book.objects.filter(pk=pk).first()
info = BookModelSerializer(instance=book, data=request.data)
if info.is_valid():
info.save()
return Response({'code': 666, 'msg': '修改成功'})
else:
return Response({'code': 777, 'msg': info.errors})
class DeleteBook(object):
def delete(self, request, pk):
Book.objects.filter(pk=pk).delete()
return Response({'msg': '删除成功'})
class BookDetailView(GenericAPIView, GetBook, PutBook, DeleteBook):
queryset = Book.objects.all()
serializer_class = BookModelSerializer
基于9个视图子类写出图书表接口
urls.py
from django.contrib import admin
from django.urls import path
from app01.views import BookView, BookDetailView
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', BookView.as_view()),
path('books/<int:pk>/', BookDetailView.as_view()),
]
models.py
from django.db import models
# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
publish = models.CharField(max_length=32)
class User(models.Model):
name = models.CharField(max_length=32)
age = models.CharField(max_length=32)
gender = models.CharField(max_length=32)
address = models.CharField(max_length=255)
Serializer.py
from rest_framework import serializers
from .models import Book, User
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
class UserModelSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
views.py
from .models import Book
from .serializer import BookModelSerializer
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView
class GetBooks(object):
def get(self, request):
book_list = Book.objects.all()
info = BookModelSerializer(instance=book_list, many=True)
return Response(info.data)
class AddBook(object):
def post(self, request):
info = BookModelSerializer(data=request.data)
if info.is_valid():
info.save()
return Response({'code': 666, 'msg': '新增成功'})
else:
return Response({'code': 777, 'msg': info.errors})
class GetBook(object):
def get(self, request, pk):
book = Book.objects.filter(pk=pk).first()
info = BookModelSerializer(instance=book)
return Response(info.data)
class PutBook(object):
def put(self, request, pk):
book = Book.objects.filter(pk=pk).first()
info = BookModelSerializer(instance=book, data=request.data)
if info.is_valid():
info.save()
return Response({'code': 666, 'msg': '修改成功'})
else:
return Response({'code': 777, 'msg': info.errors})
class DeleteBook(object):
def delete(self, request, pk):
Book.objects.filter(pk=pk).delete()
return Response({'msg': '删除成功'})
class GettingBooks(GenericAPIView, GetBooks): # 获取所有
pass
class AppendBook(GenericAPIView, AddBook): # 新增
pass
class AccessToAddBook(GenericAPIView, GetBooks, AddBook): # 获取+新增
pass
class GettingBook(GenericAPIView, GetBook): # 获取单条
pass
class ChangeBook(GenericAPIView, PutBook): # 修改
pass
class RemoveBook(GenericAPIView, DeleteBook): # 删除
pass
class AccessToModifyBook(GenericAPIView, GetBook, PutBook): # 获取单条+修改
pass
class ModifyDeleteBook(GenericAPIView, PutBook, DeleteBook): # 修改+删除
pass
class AccessToDeleteBook(GenericAPIView, DeleteBook, GetBook): # 删除+获取单条
pass
class BookView(GettingBooks, AppendBook):
queryset = Book.objects.all()
serializer_class = BookModelSerializer
class BookDetailView(GettingBook, RemoveBook, ChangeBook):
queryset = Book.objects.all()
serializer_class = BookModelSerializer
图例展示
- 查询所有图书
- 查询单个图书
- 新增单个图书
- 修改单个图书
- 删除单个图书
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)