Django Rest_Framework(二)
文章目录
- 1. http请求响应
- 1.1. 请求与响应
- 1.1.1 Request
- 1.1.1.1 常用属性
- 1).data
- 2).query_params
- 3)request._request
- 基本使用
- 1.1.2 Response
- 1.1.2.1 构造方式
- 1.1.2.2 response对象的属性
- 1).data
- 2).status_code
- 3).content
- 1.1.2.3 状态码
- 1)信息告知 - 1xx
- 2)成功 - 2xx
- 3)重定向 - 3xx
- 4)客户端错误 - 4xx
- 5)服务器错误 - 5xx
- 1. 视图
- 1.2 普通视图
- 1.2.1 2个视图基类
- 1.2.1.1 APIView基本视图类
- 1.2.1.2 GenericAPIView[通用视图类]
- get_serializer(self, *args, \**kwargs)
- 1.2.2 5个视图扩展类
- 1)ListModelMixin
- 2)CreateModelMixin
- 3)RetrieveModelMixin
- 4)UpdateModelMixin
- 5)DestroyModelMixin
- 1.2.3 9个视图子类
- 1)CreateAPIView
- 2)ListAPIView
- 3)RetrieveAPIView
- 4)DestoryAPIView
- 5)UpdateAPIView
- 6)ListCreateAPIView
- 7)RetrieveUpdateAPIView
- 8)RetrieveDestoryAPIView
- 9)RetrieveUpdateDestoryAPIView
- 1.3 视图集ViewSet
- 1.3.1 常用视图集父类
- 1) ViewSet
- 2)GenericViewSet
- 3)ModelViewSet
- 4)ReadOnlyModelViewSet
- 2. 路由Routers
- 2.1 使用方法
- 2.2 视图集中附加action的声明
- 2.3 路由router形成URL的方式
什么时候声明的序列化器需要继承序列化器基类Serializer,什么时候继承模型序列化器类ModelSerializer?
继承序列化器类Serializer字段声明验证添加/保存数据功能
继承模型序列化器类ModelSerializer字段声明[可选,看需要]Meta声明验证添加/保存数据功能[可选]
看数据是否从mysql数据库中获取,如果是则使用ModelSerializer,不是则使用Serializer
1. http请求响应
drf除了在数据序列化部分简写代码以外,还在视图中提供了简写操作。所以在django原有的django.views.View类基础上,drf封装了多个视图子类出来提供给我们使用。
Django REST framwork 提供的视图的主要作用:
- 控制序列化器的执行(检验、保存、转换数据)
- 控制数据库查询的执行
- 调用请求类和响应类[这两个类也是由drf帮我们再次扩展了一些功能类。]
为了方便我们学习,所以先创建一个子应用req
python manage.py startapp req
注册子引用:
INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','rest_framework','students','sers', # 序列化器"school", # 序列化器嵌套'req', # 请求与响应
]
注册路由
# 子应用路由
from django.urls import path
from . import views
urlpatterns = []# 总路由
from django.contrib import admin
from django.urls import path, includeurlpatterns = [path('admin/', admin.site.urls),path('students/', include("students.urls")),path('sers/', include("sers.urls")),path('school/', include("school.urls")),path("req/", include("req.urls")),
]
1.1. 请求与响应
内容协商:drf在django原有的基础上,新增了一个request对象继承到了APIVIew视图类,并在django原有的HttpResponse响应类的基础上实现了一个子类rest_framework.response.Response响应类。这两个类,都是基于内容协商来完成数据的格式转换的。
request->parser解析类->识别客户端请求头中的Content-Type来完成数据转换成->类字典(QueryDict,字典的子类)
response->renderer渲染类->识别客户端请求头的"Accept"来提取客户端期望的返回数据格式,-> 转换成客户端的期望格式数据
1.1.1 Request
REST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。
REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典[QueryDict]对象保存到Request对象中。
Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。
无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。
1.1.1.1 常用属性
1).data
request.data
返回解析之后的请求体数据。类似于Django中标准的request.POST
和 request.FILES
属性,但提供如下特性:
- 包含了解析之后的文件和非文件数据
- 包含了对POST、PUT、PATCH请求方式解析后的数据
- 利用了REST framework的parser解析器,不仅支持表单类型数据,也支持JSON数据
2).query_params
query_params,查询参数,也叫查询字符串(query string )
request.query_params
与Django标准的request.GET
相同,只是更换了更正确的名称而已。
3)request._request
获取django封装的Request对象
基本使用
视图代码:
from django.views import View
from django.http.response import HttpResponse
from django.http.request import HttpRequest
from django.core.handlers.wsgi import WSGIRequest
class ReqView(View):def get(self,request):print(request)return HttpResponse("ok")"""
默认情况下, 编写视图类时,如果继承的是django内置的django.view.View视图基类,
则视图方法中得到的request对象,是django默认提供的django.core.handlers.wsgi.WSGIRequest
WSGIRequest这个请求处理对象,无法直接提供的关于json数据数据处理。
在编写api接口时很不方便,所以drf为了简写这块内容,在原来的HttpRequest的基础上面,新增了一个Request对象
这个Request对象是单独声明的和原来django的HttpRequest不是父子关系。
同时注意:要使用drf提供的Request请求处理对象,必须在编写视图类时继承drf提供的视图基类from rest_framework.views import APIView如果使用drf提供的视图基类APIView编写类视图,则必须使用来自drf提供的Request请求对象和Response响应对象
"""
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class ReqAPIView(APIView):def get(self,request):# rest_framework.request.Request对象print(request) # <rest_framework.request.Request: GET '/req/req2?name=xiaoming&age=17&lve=swim&lve=code'># 获取查询字符串print(request.query_params)# 没有参数情况下: <QueryDict: {}># 有参数的情况下: <QueryDict: {'name': ['xiaoming'], 'age': ['17'], 'lve': ['swim', 'code']}># 所以,request.query_params的返回值操作和原来在django里面是一模一样的print(request.query_params.get("name")) # xiaomingprint(request.query_params.getlist("lve")) # ['swim', 'code']return Response("ok")def post(self, request):# 获取请求体print(request.data) # {'name': 'xiaoming', 'age': 16, 'lve': ['swim', 'code']}"""直接从请求体中提取数据转# 客户端如果上传了json数据,直接返回字典{'name': '灰太狼', 'age': 20, 'sex': 1, 'classmate': '301', 'description': '我还会再回来的~'}# 客户端如果上传了表单数据,直接返回QueryDict<QueryDict: {'name': ['xiaohui'], 'age': ['18']}>"""print(request.FILES) # 获取上传文件列表# 要获取django原生提供的HttpRequest对象,可以通过request._request来获取到print(request._request.META.get("Accept")) # 当值为None时,drf默认在响应数据时按json格式返回# response = Response(data="not ok", status=204, headers={"Company":"Oldboy"})response = Response(data="not ok", status=status.HTTP_400_BAD_REQUEST, headers={"Company":"Oldboy"})return response
1.1.2 Response
rest_framework.response.Response
REST framework提供了一个响应类Response
,使用该类构造响应对象时,响应的具体数据内容会被转换(renderer渲染器)成符合前端需求的类型。
REST framework提供了Renderer
渲染器,用来根据请求头中的Accept
(接收数据类型声明)来自动转换响应数据到对应格式。如果前端请求中未进行声明Accept,则会采用Content-Type方式处理响应数据,我们可以通过配置来修改默认响应格式。
可以在rest_framework.settings查找所有的drf默认配置项
REST_FRAMEWORK = {'DEFAULT_RENDERER_CLASSES': ( # 默认响应渲染类'rest_framework.renderers.JSONRenderer', # json渲染器,返回json数据'rest_framework.renderers.BrowsableAPIRenderer', # 浏览器API渲染器,返回调试界面)
}
1.1.2.1 构造方式
Response(data, status=None, template_name=None, headers=None, content_type=None)
drf的响应处理类和请求处理类不一样,Response就是django的HttpResponse响应处理类的子类。
data
数据不要是render处理之后的数据,只需传递python的内建类型数据即可,REST framework会使用renderer
渲染器处理data
。
data
不能是复杂结构的数据,如Django的模型类对象,对于这样的数据我们可以使用Serializer
序列化器序列化处理后(转为了Python字典类型)再传递给data
参数。
参数说明:
data
: 为响应准备的序列化处理后的数据;status
: 状态码,默认200;template_name
: 模板名称,如果使用HTMLRenderer
时需指明;headers
: 用于存放响应头信息的字典;content_type
: 响应数据的Content-Type,通常此参数无需传递,REST framework会根据前端所需类型数据来设置该参数。
1.1.2.2 response对象的属性
工作少用,
1).data
传给response对象的序列化后,但尚未render处理的数据
2).status_code
状态码的数字
3).content
经过render处理后的响应数据
1.1.2.3 状态码
为了方便设置状态码,REST framewrok在rest_framework.status
模块中提供了常用http状态码的常量。
1)信息告知 - 1xx
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
2)成功 - 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
3)重定向 - 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
4)客户端错误 - 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
5)服务器错误 - 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提供的视图里面的内容知识,我们另外创建一个子应用来展示
python manage.py startapp demo
注册子应用
INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','rest_framework','students','sers', # 序列化器"school", # 序列化器嵌套'req', # 请求与响应'demo', # 视图
]
总路由,代码:
from django.contrib import admin
from django.urls import path, includeurlpatterns = [path('admin/', admin.site.urls),path('students/', include("students.urls")),path('sers/', include("sers.urls")),path('school/', include("school.urls")),path("req/", include("req.urls")),path("demo/", include("demo.urls")),
]
子应用路由,代码:
from django.urls import path
from . import viewsurlpatterns = []
1. 视图
Django REST framwork 提供的视图的主要作用:
- 控制序列化器的执行(检验、保存、转换数据)
- 控制数据库模型的操作
1.2 普通视图
REST framework 提供了众多的通用视图基类与扩展类,以简化视图的编写。
1.2.1 2个视图基类
1.2.1.1 APIView基本视图类
rest_framework.views.APIView
APIView
是REST framework提供的所有视图类的基类,继承自Django的View
父类。
APIView
与View
的不同之处在于:
-
传入到视图方法中的是REST framework的
Request
对象,而不是Django的HttpRequeset
对象; -
视图方法可以返回REST framework的
Response
对象,视图会为响应数据设置(renderer)符合前端期望要求的格式; -
任何
APIException
异常都会被捕获到,并且处理成合适格式的响应信息返回给客户端;django 的View中所有异常全部以HTML格式显示
drf的APIVIew或者APIView的子类会自动根据客户端的Accept进行错误信息的格式转换。
-
重新声明了一个新的as_view方法并在dispatch()进行路由分发前,会对请求的客户端进行身份认证、权限检查、流量控制。
APIView除了继承了View原有的属性方法意外,还新增了类属性:
- authentication_classes 列表或元组,身份认证类
- permissoin_classes 列表或元组,权限检查类
- throttle_classes 列表或元祖,流量控制类
在APIView
中仍以常规的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。
序列化器,demo/serializers.py,代码:
from rest_framework import serializers
from stuapi.models import Studentclass StudentModelSerializer(serializers.ModelSerializer):class Meta:model = Studentfields = "__all__"extra_kwargs = {"age": {"max_value": 25,"error_messages": {"max_value": "年龄不能超过25岁!",}}}
视图代码:
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from stuapi.models import Student
from .serializers import StudentModelSerializer
"""
GET /demo/students/ 获取所有学生信息
POST /demo/students/ 添加一个学生信息 GET /demo/students/<pk> 获取一个学生信息
PUT /demo/students/<pk> 更新一个学生信息
DELETE /demo/students/<pk> 删除一个学生信息
"""# Create your views here.
class StudentAPIView(APIView):def get(self,request):"""获取所有学生信息"""# 1. 从数据库中读取学生列表信息student_list = Student.objects.all()# 2. 实例化序列化器,获取序列化对象serializer = StudentModelSerializer(instance=student_list, many=True)# 3. 转换数据并返回给客户端return Response(serializer.data)def post(self,request):"""添加一条数据"""# 1. 获取客户端提交的数据,实例化序列化器,获取序列化对象serializer = StudentModelSerializer(data=request.data)# 2. 反序列化[验证数据、保存数据到数据库]serializer.is_valid(raise_exception=True)serializer.save()# 3. 返回新增的模型数据给客户单return Response(serializer.data, status=status.HTTP_201_CREATED)class StudentInfoAPIView(APIView):def get(self,request, pk):"""获取一条数据"""# 1. 使用pk作为条件获取模型对象try:student = Student.objects.get(pk=pk)except Student.DoesNotExist:return Response(status=status.HTTP_404_NOT_FOUND)# 2. 序列化serializer = StudentModelSerializer(instance=student)# 3. 返回结果return Response(serializer.data)def put(self,request,pk):"""更新数据"""# 1. 使用pk作为条件获取模型对象try:student = Student.objects.get(pk=pk)except Student.DoesNotExist:return Response(status=status.HTTP_404_NOT_FOUND)# 2. 获取客户端提交的数据serializer = StudentModelSerializer(instance=student, data=request.data)# 3. 反序列化[验证数据和数据保存]serializer.is_valid(raise_exception=True)serializer.save()# 4. 返回结果return Response(serializer.data, status=status.HTTP_201_CREATED)def delete(self,request,pk):"""删除数据"""# 1. 根据PK值获取要删除的数据并删除try:Student.objects.get(pk=pk).delete()except Student.DoesNotExist:pass# 2. 返回结果return Response(status=status.HTTP_204_NO_CONTENT)
路由代码:
from django.urls import path, re_path
from . import viewsurlpatterns = [path("students/", views.StudentAPIView.as_view()),re_path("^students/(?P<pk>\d+)/$", views.StudentInfoAPIView.as_view()),
]
1.2.1.2 GenericAPIView[通用视图类]
通用视图类主要作用就是把视图中的独特的代码抽取出来,让视图方法中的代码更加通用,方便把通用代码进行简写。
rest_framework.generics.GenericAPIView
继承自APIView
,主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。通常在使用时,可搭配一个或多个Mixin扩展类。
提供的关于序列化器使用的属性与方法
-
属性:
- serializer_class 指明视图使用的序列化器类
-
方法:
-
get_serializer_class(self)
当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中通过返回不同的序列化器类名就可以让视图方法执行不同的序列化器对象了。
返回序列化器类,默认返回
serializer_class
,可以重写,例如:class Student2GenericAPIView(GenericAPIView):# 整个视图类只使用一个序列化器的情况# serializer_class = StudentModelSerializert# 整个视图类中使用多个序列化器的情况def get_serializer_class(self):if self.request.method.lower() == "put":return StudentModelSerializerelse:return Student2ModelSerializerqueryset = Student.objectsdef get(self, request, pk):"""获取一个模型信息"""serializer = self.get_serializer(instance=self.get_object())return Response(serializer.data)def put(self, request, pk):"""更新一个模型信息"""serializer = self.get_serializer(instance=self.get_object(), data=request.data)serializer.is_valid(raise_exception=True)serializer.save()return Response(serializer.data)
-
get_serializer(self, *args, **kwargs)
返回序列化器对象,主要用来提供给Mixin扩展类使用,如果我们在视图中想要获取序列化器对象,也可以直接调用此方法。
注意,该方法在提供序列化器对象的时候,会向序列化器对象的context属性补充三个数据:request、format、view,这三个数据对象可以在定义序列化器时使用。
- request 当前视图的请求对象
- view 当前请求的类视图对象
- format 当前请求期望返回的数据格式
-
提供的关于数据库查询的属性与方法
-
属性:
- queryset 指明使用的数据查询集
-
方法:
-
get_queryset(self)
返回视图使用的查询集,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回
queryset
属性,可以重写,例如:def get_queryset(self):user = self.request.userreturn user.accounts.all()
-
get_object(self)
返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用。
在试图中可以调用该方法获取详情信息的模型类对象。
若详情访问的模型类对象不存在,会返回404。
该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。
举例:
# url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()), class BookDetailView(GenericAPIView):queryset = BookInfo.objects.all()serializer_class = BookInfoSerializerdef get(self, request, pk):book = self.get_object() # get_object()方法根据pk参数查找queryset中的数据对象serializer = self.get_serializer(book)return Response(serializer.data)
-
其他可以设置的属性
- pagination_class 指明分页控制类
- filter_backends 指明数据过滤控制后端
视图,代码:
"""
APIView中的api接口代码,除了部分涉及到调用模型和序列化器的代码以外,其他代码几乎都是固定写法。
所以,当我们将来针对增删查改的通用api接口编写时,完全可以基于原有的代码进行复用,
那么,drf也考虑到了这个问题,所以提供了一个GenericAPIView(通用视图类),让我们可以把接口中独特的代码单独提取出来作为属性存在。
rest_framework.generics.GenericAPIView是APIView的子类,在APIView的基础上进行属性扩展提供了2个属性,4个方法,方便我们针对通用接口进行编写。
"""
"""GenericAPIView 通用视图类"""
from rest_framework.generics import GenericAPIViewclass StudentGenericAPIView(GenericAPIView):queryset = Student.objects.all()serializer_class = StudentModelSerializerdef get(self,request):"""获取所有数据"""# 1. 从数据库中读取模型列表信息queryset = self.get_queryset() # GenericAPIView提供的get_queryset# 2. 序列化serializer = self.get_serializer(instance=queryset, many=True)# 3. 转换数据并返回给客户端return Response(serializer.data)def post(self,request):"""添加一个数据"""# 1. 获取客户端提交的数据,实例化序列化器,获取序列化对象serializer = self.get_serializer(data=request.data)# 2. 反序列化[验证数据、保存数据到数据库]serializer.is_valid(raise_exception=True)serializer.save()# 3. 返回新增的模型数据给客户单return Response(serializer.data, status=status.HTTP_201_CREATED)class StudentInfoGenericAPIView(GenericAPIView):queryset = Student.objects.all()serializer_class = StudentModelSerializerdef get(self,request,pk):"""获取一个数据"""# 1. 使用pk作为条件获取模型对象instance = self.get_object()# 2.序列化serializer = self.get_serializer(instance=instance)# 3. 返回结果return Response(serializer.data)def put(self, request, pk):"""更新一个数据"""# 1. 使用pk作为条件获取模型对象instance = self.get_object()# 2. 获取客户端提交的数据serializer = self.get_serializer(instance=instance, data=request.data)# 3. 反序列化[验证数据和数据保存]serializer.is_valid(raise_exception=True)serializer.save()# 4. 返回结果return Response(serializer.data, status=status.HTTP_201_CREATED)def delete(self,request,pk):"""删除一个数据"""# 1. 根据PK值获取要删除的数据并删除self.get_object().delete()# 2. 返回结果return Response(status=status.HTTP_204_NO_CONTENT)
序列化器类:
from rest_framework import serializers
from stuapi.models import Studentclass StudentModelSerializer(serializers.ModelSerializer):class Meta:model = Studentfields = "__all__"extra_kwargs = {"age": {"max_value": 25,"error_messages": {"max_value": "年龄不能超过25岁!",}}}
路由代码:
from django.urls import path, re_path
from . import viewsurlpatterns = [# APIViewpath("students/", views.StudentAPIView.as_view()),re_path("^students/(?P<pk>\d+)/$", views.StudentInfoAPIView.as_view()),# GenericAPIViewpath("students2/", views.StudentGenericAPIView.as_view()),re_path("^students2/(?P<pk>\d+)/$", views.StudentInfoGenericAPIView.as_view()),
]
1.2.2 5个视图扩展类
也叫混入类。
作用:
提供了几种后端视图(对数据资源进行增删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。
这五个扩展类需要搭配GenericAPIView通用视图基类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。
1)ListModelMixin
列表视图扩展类,提供list(request, *args, **kwargs)
方法快速实现列表视图,返回200状态码。
该Mixin的list方法会对数据进行过滤和分页。
源代码:
class ListModelMixin(object):"""List a queryset."""def list(self, request, *args, **kwargs):# 过滤queryset = self.filter_queryset(self.get_queryset())# 分页page = self.paginate_queryset(queryset)if page is not None:serializer = self.get_serializer(page, many=True)return self.get_paginated_response(serializer.data)# 序列化serializer = self.get_serializer(queryset, many=True)return Response(serializer.data)
举例:
from rest_framework.mixins import ListModelMixin,CreateModelMixin
class StudentMixinAPIView(GenericAPIView,ListModelMixin,CreateModelMixin):serializer_class = StudentModelSerializerqueryset = Student.objectsdef get(self,request,*args,**kwargs):"""获取所有模型信息"""return self.list(request,*args,**kwargs)
2)CreateModelMixin
创建视图扩展类,提供create(request, *args, **kwargs)
方法快速实现创建资源的视图,成功返回201状态码。
如果序列化器对前端发送的数据验证失败,返回400错误。
源代码:
class CreateModelMixin(object):"""Create a model instance."""def create(self, request, *args, **kwargs):# 获取序列化器serializer = self.get_serializer(data=request.data)# 验证serializer.is_valid(raise_exception=True)# 保存self.perform_create(serializer)headers = self.get_success_headers(serializer.data)return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)def perform_create(self, serializer):serializer.save()def get_success_headers(self, data):try:return {'Location': str(data[api_settings.URL_FIELD_NAME])}except (TypeError, KeyError):return {}
视图代码:
from rest_framework.mixins import ListModelMixin,CreateModelMixin
class StudentMixinAPIView(GenericAPIView,ListModelMixin,CreateModelMixin):serializer_class = StudentModelSerializerqueryset = Student.objectsdef get(self,request,*args,**kwargs):"""获取所有模型信息"""return self.list(request,*args,**kwargs)def post(self,request):"""添加一个模型信息"""return self.create(request)
3)RetrieveModelMixin
详情视图扩展类,提供retrieve(request, *args, **kwargs)
方法,可以快速实现返回一个存在的数据对象。
如果存在,返回200, 否则返回404。
源代码:
class RetrieveModelMixin(object):"""Retrieve a model instance."""def retrieve(self, request, *args, **kwargs):# 获取对象,会检查对象的权限instance = self.get_object()# 序列化serializer = self.get_serializer(instance)return Response(serializer.data)
视图代码:
from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student1MixinAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):serializer_class = StudentModelSerializerqueryset = Student.objectsdef get(self,request,pk):"""获取一个模型信息"""return self.retrieve(request,pk)
4)UpdateModelMixin
更新视图扩展类,提供update(request, *args, **kwargs)
方法,可以快速实现更新一个存在的数据对象。
同时也提供partial_update(request, *args, **kwargs)
方法,可以实现局部更新。
成功返回200,序列化器校验数据失败时,返回400错误。
源代码:
class UpdateModelMixin(object):"""Update a model instance."""def update(self, request, *args, **kwargs):partial = kwargs.pop('partial', False)instance = self.get_object()serializer = self.get_serializer(instance, data=request.data, partial=partial)serializer.is_valid(raise_exception=True)self.perform_update(serializer)if getattr(instance, '_prefetched_objects_cache', None):# If 'prefetch_related' has been applied to a queryset, we need to# forcibly invalidate the prefetch cache on the instance.instance._prefetched_objects_cache = {}return Response(serializer.data)def perform_update(self, serializer):serializer.save()def partial_update(self, request, *args, **kwargs):kwargs['partial'] = Truereturn self.update(request, *args, **kwargs)
视图代码:
from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student1MixinAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):serializer_class = StudentModelSerializerqueryset = Student.objectsdef get(self,request,pk):"""获取一个模型信息"""return self.retrieve(request,pk)def put(self,request,pk):"""更新一个模型信息"""return self.update(request,pk)
5)DestroyModelMixin
删除视图扩展类,提供destroy(request, *args, **kwargs)
方法,可以快速实现删除一个存在的数据对象。
成功返回204,不存在返回404。
源代码:
class DestroyModelMixin(object):"""Destroy a model instance."""def destroy(self, request, *args, **kwargs):instance = self.get_object()self.perform_destroy(instance)return Response(status=status.HTTP_204_NO_CONTENT)def perform_destroy(self, instance):instance.delete()
视图代码:
from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student1MixinAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):serializer_class = StudentModelSerializerqueryset = Student.objectsdef get(self,request,pk):"""获取一个模型信息"""return self.retrieve(request,pk)def put(self,request,pk):"""更新一个模型信息"""return self.update(request,pk)def delete(self,request,pk):"""删除一个模型信息"""return self.destroy(request,pk)
整体代码,使用GenericAPIView结合视图扩展类,实现5个基本api接口,视图代码:
"""
使用drf内置的模型扩展类[混入类]结合GenericAPIView实现通用视图方法的简写操作
from rest_framework.mixins import ListModelMixin 获取多条数据,返回响应结果 list
from rest_framework.mixins import CreateModelMixin 添加一条数据,返回响应结果 create
from rest_framework.mixins import RetrieveModelMixin 获取一条数据,返回响应结果 retrieve
from rest_framework.mixins import UpdateModelMixin 更新一条数据,返回响应结果 update(更新全部字段)和partial_update(更新单个或部分字段,例如修改密码,修改头像)
from rest_framework.mixins import DestroyModelMixin 删除一条数据,返回响应结果 destroy
"""
from rest_framework.mixins import ListModelMixin, CreateModelMixinclass StudentMixinView(GenericAPIView, ListModelMixin, CreateModelMixin):queryset = Student.objects.all()serializer_class = StudentModelSerializerdef get(self,request):"""获取所有数据"""return self.list(request)def post(self,request):"""添加一条数据"""return self.create(request)from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin, DestroyModelMixinclass StudentInfoMixinView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):queryset = Student.objects.all()serializer_class = StudentModelSerializerdef get(self,request,pk):return self.retrieve(request, pk=pk)def put(self,request, pk):return self.update(request, pk=pk)def delete(self,request, pk):return self.destroy(request, pk=pk)
序列化器,代码:
from rest_framework import serializers
from stuapi.models import Studentclass StudentModelSerializer(serializers.ModelSerializer):class Meta:model = Studentfields = "__all__"extra_kwargs = {"age": {"max_value": 25,"error_messages": {"max_value": "年龄不能超过25岁!",}}}
路由代码:
from django.urls import path, re_path
from . import viewsurlpatterns = [# APIViewpath("students/", views.StudentAPIView.as_view()),re_path("^students/(?P<pk>\d+)/$", views.StudentInfoAPIView.as_view()),# GenericAPIViewpath("students2/", views.StudentGenericAPIView.as_view()),re_path("^students2/(?P<pk>\d+)/$", views.StudentInfoGenericAPIView.as_view()),# GenericAPIView + mixinspath("students3/", views.StudentMixinView.as_view()),re_path("^students3/(?P<pk>\d+)/$", views.StudentInfoMixinView.as_view()),
]
1.2.3 9个视图子类
1)CreateAPIView
提供了post方法,内部调用了create方法
继承自: GenericAPIView、CreateModelMixin
2)ListAPIView
提供了get方法,内部调用了list方法
继承自:GenericAPIView、ListModelMixin
3)RetrieveAPIView
提供了get方法,内部调用了retrieve方法
继承自: GenericAPIView、RetrieveModelMixin
4)DestoryAPIView
提供了delete方法,内部调用了destory方法
继承自:GenericAPIView、DestoryModelMixin
5)UpdateAPIView
提供了put和patch方法,内部调用了update和partial_update方法
继承自:GenericAPIView、UpdateModelMixin
6)ListCreateAPIView
提供了get和post方法,内部调用了list和create方法
继承自:GenericAPIView、ListModelMixin、CreateModelMixin
7)RetrieveUpdateAPIView
提供 get、put、patch方法
继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
8)RetrieveDestoryAPIView
提供 get、delete方法
继承自:GenericAPIView、RetrieveModelMixin、DestoryModelMixin
9)RetrieveUpdateDestoryAPIView
提供 get、put、patch、delete方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
视图代码:
"""
上面的接口代码还可以继续更加的精简,drf在使用GenericAPIView和Mixins进行组合以后,还提供了视图子类。
视图子类,提供了各种的视图方法调用mixins操作ListAPIView = GenericAPIView + ListModelMixin 获取多条数据的视图方法CreateAPIView = GenericAPIView + CreateModelMixin 添加一条数据的视图方法RetrieveAPIView = GenericAPIView + RetrieveModelMixin 获取一条数据的视图方法UpdateAPIView = GenericAPIView + UpdateModelMixin 更新一条数据的视图方法DestroyAPIView = GenericAPIView + DestroyModelMixin 删除一条数据的视图方法
组合视图子类ListCreateAPIView = ListAPIView + CreateAPIViewRetrieveUpdateAPIView = RetrieveAPIView + UpdateAPIViewRetrieveDestroyAPIView = RetrieveAPIView + DestroyAPIViewRetrieveUpdateDestroyAPIView = RetrieveAPIView + UpdateAPIView + DestroyAPIView
"""
# from rest_framework.generics import ListAPIView, CreateAPIView
from rest_framework.generics import ListCreateAPIView
class StudentListAPIView(ListCreateAPIView):queryset = Student.objects.all()serializer_class = StudentModelSerializer# from rest_framework.generics import RetrieveAPIView, UpdateAPIView, DestroyAPIView
# from rest_framework.generics import RetrieveUpdateAPIView, DestroyAPIView
# from rest_framework.generics import RetrieveDestroyAPIView, UpdateAPIView
from rest_framework.generics import RetrieveUpdateDestroyAPIView # 四行代码一样意思
class StudentInfoAPIView(RetrieveUpdateDestroyAPIView):queryset = Student.objects.all()serializer_class = StudentModelSerializer
序列化器,代码:
from rest_framework import serializers
from school.models import Student
class StudentModelSerializer(serializers.ModelSerializer):class Meta:model = Studentfields = "__all__"
路由,代码:
from django.urls import path
from . import viewsurlpatterns = [path("s1/", views.StudentList1APIView.as_view()),path("s1/<int:pk>/", views.StudentInfo1APIView.as_view()),path("s2/", views.StudentList2GenericAPIView.as_view()),path("s2/<int:pk>/", views.StudentInfo2GenericAPIView.as_view()),path("s3/", views.StudentList3GenericAPIView.as_view()),path("s3/<int:pk>/", views.StudentInfo3GenericAPIView.as_view()),path("s4/", views.StudentListAPIView.as_view()),path("s4/<int:pk>/", views.StudentInfoAPIView.as_view()),
]
1.3 视图集ViewSet
使用视图集ViewSet,可以将一系列视图相关的代码逻辑和相关的http请求动作封装到一个类中:
- list() 提供一组数据
- retrieve() 提供单个数据
- create() 创建数据
- update() 保存数据
- destory() 删除数据
ViewSet视图集类不再限制视图方法名只允许get()、post()等这种情况了,而是实现允许开发者根据自己的需要定义自定义方法名,例如 list() 、create() 等,然后经过路由中使用http和这些视图方法名进行绑定调用。
视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上。如:
"""
针对视图子类这种写法写法虽然已经省略了http请求,但是在开发通用5个api接口时,还是会出现需要2个类来实现5个接口的情况。
这主要的原因是2点:
1. 获取多条数据与获取一条数据的http请求重复了。在django中依赖于请求方法来响应不同的http请求
2. 部分接口需要pk值作为url地址。drf为了解决上面的2个问题,提供了视图集和路由集。
视图集就可以帮我们实现一个视图类响应多种重复的http请求
路由集就可以帮我们实现自动根据不同的视图方法来生成不同参数的路由地址。
from rest_framework.viewsets import ViewSet # ViewSet是APIView的子类,是所有drf中的视图集的父类
"""
from rest_framework.viewsets import ViewSet
class StudentViewSet(ViewSet):# ViewSet不再需要我们使用http请求作为视图方法了。当然,如果你还希望使用http作为视图方法也可以。def get_all(self,request):queryset = Student.objects.all()# 实例化序列化器对象serializer = StudentModelSerializer(instance=queryset, many=True)# 返回序列化后的数据列表return Response(serializer.data)def create(self,request):"""添加一条数据"""# 接收客户端提交的数据# 1. 实例化序列化器对象,获取来自客户端的请求数据作为参数serializer = StudentModelSerializer(data=request.data)# 2. 反序列化, 调用is_valid进行数据校验serializer.is_valid(raise_exception=True)# 3. 反序列化, 调用save保存数据serializer.save()# 4. 序列化,把新增后的模型对象返回给客户端return Response(serializer.data, status=status.HTTP_201_CREATED)def get_one(self,request,pk):try:# 模型操作,根据pk值获取指定数据instance = Student.objects.get(pk=pk)# 实例化序列化器对象serializer = StudentModelSerializer(instance=instance)# 返回序列化后的数据return Response(serializer.data)except Student.DoesNotExist:return Response({"msg":"当前学生不存在!"}, status=status.HTTP_404_NOT_FOUND)def put(self,request,pk):"""更新一条数据"""try:# 获取要更新的模型对象instance = Student.objects.get(pk=pk)# 实例化序列化器对象,参数分别是本次更新的模型对象以及接受来自客户端提交的更新数据serializer = StudentModelSerializer(instance=instance, data=request.data)# 反序列化,验证数据serializer.is_valid(raise_exception=True)# 反序列化器,保存数据serializer.save()# 序列化,返回更新后的数据return Response(serializer.data)except Student.DoesNotExist:return Response({"msg": "当前学生不存在!"}, status=status.HTTP_404_NOT_FOUND)def delete(self,request,pk):"""删除一条数据"""try:# 获取要更新的模型对象student = Student.objects.get(pk=pk)student.delete()return Response(status=status.HTTP_204_NO_CONTENT)except Student.DoesNotExist:return Response({"msg": "当前学生不存在!"}, status=status.HTTP_404_NOT_FOUND)
在设置路由时,我们可以如下操作
from django.urls import path
from . import viewsurlpatterns = [path("s1/", views.StudentList1APIView.as_view()),path("s1/<int:pk>/", views.StudentInfo1APIView.as_view()),path("s2/", views.StudentList2GenericAPIView.as_view()),path("s2/<int:pk>/", views.StudentInfo2GenericAPIView.as_view()),path("s3/", views.StudentList3GenericAPIView.as_view()),path("s3/<int:pk>/", views.StudentInfo3GenericAPIView.as_view()),path("s4/", views.StudentListAPIView.as_view()),path("s4/<int:pk>/", views.StudentInfoAPIView.as_view()),path("s5/", views.StudentViewSet.as_view(actions={"get":"get_all","post":"create"})),path("s5/<int:pk>/", views.StudentViewSet.as_view({"get":"get_one","put":"put","delete":"delete"})),
]
1.3.1 常用视图集父类
1) ViewSet
继承自APIView
与ViewSetMixin
,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。
ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典{“http请求”:“视图方法”}的映射处理工作,如{‘get’:‘list’},
在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。
2)GenericViewSet
继承自GenericAPIView和ViewSetMixin,作用让视图集的视图代码变得更加通用,抽离独特代码作为视图类的属性。
使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与GenericAPIView
,所以还需要继承GenericAPIView
。
GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIView
与ViewSetMixin
,在实现了调用as_view()时传入字典(如{'get':'list'}
)的映射处理工作的同时,还提供了GenericAPIView
提供的基础方法,可以直接搭配Mixin扩展类使用。
视图代码:
from rest_framework.viewsets import GenericViewSetclass StudentGenericViewSet(GenericViewSet):queryset = Student.objects.all()serializer_class = StudentModelSerializerdef list(self,request):"""获取多条数据"""# 获取模型对象列表,实例化序列化器对象serializer = self.get_serializer(instance=self.get_queryset(), many=True)# 返回序列化后的数据列表return Response(serializer.data)def post(self,request):"""添加一条数据"""serializer = self.get_serializer(data=request.data)# 2. 反序列化, 调用is_valid进行数据校验serializer.is_valid(raise_exception=True)# 3. 反序列化, 调用save保存数据serializer.save()# 4. 序列化,把新增后的模型对象返回给客户端return Response(serializer.data, status=status.HTTP_201_CREATED)def retrieve(self, request, pk):"""获取一条数据"""# 模型操作,根据pk值获取指定数据instance = self.get_object() # 上面代码的简写,而且对错误进行格式处理# 实例化序列化器对象serializer = self.get_serializer(instance=instance)# 返回序列化后的数据列表return Response(serializer.data)def update(self, request, pk):"""更新一条数据"""instance = self.get_object() # 不要漏了pk参数serializer = self.get_serializer(instance=instance, data=request.data)# 反序列化,验证数据serializer.is_valid(raise_exception=True)# 反序列化器,保存数据serializer.save()# 序列化,返回更新后的数据return Response(serializer.data)def delete(self, request, pk):instance = self.get_object()instance.delete()return Response(status=status.HTTP_204_NO_CONTENT)
路由代码:
from django.urls import path
from . import viewsurlpatterns = [path("s1/", views.StudentList1APIView.as_view()),path("s1/<int:pk>/", views.StudentInfo1APIView.as_view()),path("s2/", views.StudentList2GenericAPIView.as_view()),path("s2/<int:pk>/", views.StudentInfo2GenericAPIView.as_view()),path("s3/", views.StudentList3GenericAPIView.as_view()),path("s3/<int:pk>/", views.StudentInfo3GenericAPIView.as_view()),path("s4/", views.StudentListAPIView.as_view()),path("s4/<int:pk>/", views.StudentInfoAPIView.as_view()),# path("url地址/", views.StudentViewSet.as_view({"http请求方法名":"视图方法名","http请求方法名":"视图方法名",....})),path("s5/", views.StudentViewSet.as_view({"get":"get_all","post":"create"})),path("s5/<int:pk>/", views.StudentViewSet.as_view({"get":"get_one","put":"put","delete":"delete"})),path("s6/", views.StudentGenericViewSet.as_view({"get":"list","post":"post"})),path("s6/<int:pk>/", views.StudentGenericViewSet.as_view({"get":"retrieve","put":"update","delete":"delete"})),
]
集合我们上面学习的模型扩展类,实现简写操作,视图,代码:
"""
GenericViewSet结合Mixins的混入类,直接视图接口,这次连视图子类都不需要了。
ViewSet
GenericViewSet
ModelViewSet = GenericViewSet + ListModelMixin + CreateModelMixin + UpdateModelMixin + RetrieveModelMixin + DestroyModelMixin
ReadOnlyModelViewSet = GenericViewSet + ListModelMixin + RetrieveModelMixin
"""
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin
class StudentMixinViewSet(GenericViewSet, ListModelMixin, CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin):queryset = Student.objects.all()serializer_class = StudentModelSerializer
路由,代码:
from django.urls import path
from . import viewsurlpatterns = [path("s1/", views.StudentList1APIView.as_view()),path("s1/<int:pk>/", views.StudentInfo1APIView.as_view()),path("s2/", views.StudentList2GenericAPIView.as_view()),path("s2/<int:pk>/", views.StudentInfo2GenericAPIView.as_view()),path("s3/", views.StudentList3GenericAPIView.as_view()),path("s3/<int:pk>/", views.StudentInfo3GenericAPIView.as_view()),path("s4/", views.StudentListAPIView.as_view()),path("s4/<int:pk>/", views.StudentInfoAPIView.as_view()),# path("url地址/", views.StudentViewSet.as_view({"http请求方法名":"视图方法名","http请求方法名":"视图方法名",....})),path("s5/", views.StudentViewSet.as_view({"get":"get_all","post":"create"})),path("s5/<int:pk>/", views.StudentViewSet.as_view({"get":"get_one","put":"put","delete":"delete"})),path("s6/", views.StudentGenericViewSet.as_view({"get":"list","post":"post"})),path("s6/<int:pk>/", views.StudentGenericViewSet.as_view({"get":"retrieve","put":"update","delete":"delete"})),path("s7/", views.StudentMixinViewSet.as_view({"get":"list","post":"create"})),path("s7/<int:pk>/", views.StudentMixinViewSet.as_view({"get":"retrieve","put":"update","delete":"destroy"})),
]
3)ModelViewSet
继承自GenericViewSet
,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。
4)ReadOnlyModelViewSet
继承自GenericViewSet
,同时包括了ListModelMixin、RetrieveModelMixin。
视图代码:
"""
GenericViewSet结合Mixins的混入类,直接视图接口,这次连视图子类都不需要了。
ViewSet
GenericViewSet
ModelViewSet = GenericViewSet + ListModelMixin + CreateModelMixin + UpdateModelMixin + RetrieveModelMixin + DestroyModelMixin
ReadOnlyModelViewSet = GenericViewSet + ListModelMixin + RetrieveModelMixin
"""
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin
from rest_framework.viewsets import ModelViewSet # 万能视图集,5个接口的简写
from rest_framework.viewsets import ReadOnlyModelViewSet # 只读视图集,2个接口的简写
class StudentMixinViewSet(ModelViewSet):queryset = Student.objects.all()serializer_class = StudentModelSerializer
路由代码:
from django.urls import path
from . import viewsurlpatterns = [path("s1/", views.StudentList1APIView.as_view()),path("s1/<int:pk>/", views.StudentInfo1APIView.as_view()),path("s2/", views.StudentList2GenericAPIView.as_view()),path("s2/<int:pk>/", views.StudentInfo2GenericAPIView.as_view()),path("s3/", views.StudentList3GenericAPIView.as_view()),path("s3/<int:pk>/", views.StudentInfo3GenericAPIView.as_view()),path("s4/", views.StudentListAPIView.as_view()),path("s4/<int:pk>/", views.StudentInfoAPIView.as_view()),# path("url地址/", views.StudentViewSet.as_view({"http请求方法名":"视图方法名","http请求方法名":"视图方法名",....})),path("s5/", views.StudentViewSet.as_view({"get":"get_all","post":"create"})),path("s5/<int:pk>/", views.StudentViewSet.as_view({"get":"get_one","put":"put","delete":"delete"})),path("s6/", views.StudentGenericViewSet.as_view({"get":"list","post":"post"})),path("s6/<int:pk>/", views.StudentGenericViewSet.as_view({"get":"retrieve","put":"update","delete":"delete"})),path("s7/", views.StudentMixinViewSet.as_view({"get":"list","post":"create"})),path("s7/<int:pk>/", views.StudentMixinViewSet.as_view({"get":"retrieve","put":"update","delete":"destroy"})),
]
2. 路由Routers
对于视图集ViewSet,我们除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息。如果是非视图集,不需要使用路由集routers
REST framework提供了两个router,使用方式一致的。结果多一个或少一个根目录url地址的问题而已。
- SimpleRouter
- DefaultRouter
2.1 使用方法
1) 创建router对象,并注册视图集,例如
from django.urls import path
from . import viewsurlpatterns = [# 省略....# path("s7/", views.StudentMixinViewSet.as_view({"get":"list","post":"create"})),# path("s7/<int:pk>/", views.StudentMixinViewSet.as_view({"get":"retrieve","put":"update","delete":"destroy"})),
]# 路由集的操作
from rest_framework.routers import DefaultRouter,SimpleRouter
router = DefaultRouter()
# 注册视图(访问前缀,视图集类,调用别名)
router.register("s7", views.StudentMixinViewSet, "s7")
# 把路由对象生成的视图集路由列表合并追加路由列表中
print(router.urls)
urlpatterns += router.urls
register(prefix, viewset, basename)
- prefix 该视图集的路由前缀
- viewset 视图集
- basename 路由别名的前缀
如上述代码会形成的路由如下:
url: ^s7/$ basename: s7-list
url: ^s7/(?P<pk>[^/.]+)/$ basename: s7-detail
2)把路由对象生成的视图集的路由列表添加到django的路由中可以有两种方式:
urlpatterns = [...
]urlpatterns += router.urls
或
from django.urls import include,re_path
urlpatterns = [...re_path('^', include(router.urls))
]
2.2 视图集中附加action的声明
在视图集中,如果想要让Router自动帮助我们为自定义的动作生成路由信息,需要使用rest_framework.decorators.action
装饰器。
以action装饰器装饰的方法名会作为action动作名,与list、retrieve等同。
action装饰器可以接收两个参数:
-
methods: 声明该action对应的请求方式,列表传递
-
detail: 声明该action的路径是否与单一资源对应
路由前缀/<pk>/action方法名/
- True 表示路径格式是
xxx/<pk>/action方法名/
- False 表示路径格式是
xxx/action方法名/
- True 表示路径格式是
-
url_path:声明该action的路由尾缀。
举例:
from rest_framework.viewsets import ModelViewSet # 万能视图集,5个接口的简写
from rest_framework.viewsets import ReadOnlyModelViewSet # 只读视图集,2个接口的简写
from rest_framework.decorators import action
class StudentMixinViewSet(ModelViewSet):queryset = Student.objects.all()serializer_class = StudentModelSerializer# 路由对象给视图集生成路由信息时,只会生成5个基本api接口,这主要是router只识别5个混入类的原因,# 而针对我们开发者自定义的视图方法,路由对象不会自动生成路由信息,# 所以下面这个login,如果希望被外界访问到,则必须通过action装饰器告诉路由对象要给它生成一个路由信息。@action(methods=["get","post"], detail=False, url_path="login")# action的参数# methods, 列表,指定允许哪些http请求方法可以访问当前视图方法# detail, 布尔值,告诉路由对象在生成路由信息时,是否要自动生成pk值,True表示需要,False表示不需要。# url_path,字符串,访问视图的url地址,如果不设置,则默认采用视图方法名作为访问后缀# http://127.0.0.1:8000/demo/s7/login/def login(self, request):"""登录视图"""return Response({"msg":"登录成功"})@action(methods=["get"], detail=True, url_path="login/log")# http://127.0.0.1:8000/demo/s7/23/login/log/def login_log(self,request,pk):"""用户登录历史记录"""# 视图集类中# 可以通过self.method获取本次客户端的http请求# 可以通过self.action获取本次客户端请求的视图方法名[ViewSet提供的]print(self.action) # login_logreturn Response({"msg": "用户登录历史记录"})
由路由器自动为此视图集自定义action方法形成的路由会是如下内容:
url: ^s7/login/$ basename: s7-login
url: ^s7/(?P<pk>[^/.]+)/login/log/$ basename: s7-login-log
2.3 路由router形成URL的方式
1) SimpleRouter(prefix=“路由前缀”,viewset=视图集类,basename=“路由别名”)
2)DefaultRouter
DefaultRouter与SimpleRouter的区别是,DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据。
相关文章:

Django Rest_Framework(二)
文章目录 1. http请求响应1.1. 请求与响应1.1.1 Request1.1.1.1 常用属性1).data2).query_params3)request._request 基本使用 1.1.2 Response1.1.2.1 构造方式1.1.2.2 response对象的属性1).data2).status_code3&…...

Kotlin~Visitor访问者模式
概念 将数据结构和操作分离,使操作集合可以独立于数据结构变化。 角色介绍 Visitor:抽象访问者,为对象结构每个具体元素类声明一个访问操作。Element:抽象元素,定义一个accept方法ConcreteElement:具体元…...

LVS-DR模式集群构建过程演示
一、工作原理 LVS的工作原理 1.当用户向负载均衡调度器(Director Server)发起请求,调度器将请求发往至内核空间 2.PREROUTING链首先会接收到用户请求,判断目标IP确定是本机IP,将数据包发往INPUT链 3.IPVS是工作在IN…...

UML-A 卷-知识考卷
UML-A 卷-知识考卷 UML有多少种图,请列出每种图的名字: 常用的几种UML图: 类图(Class Diagram):类图是描述类、接口、关联关系和继承关系的图形化表示。它展示了系统中各个类之间的静态结构和关系。时序…...

BpBinder与PPBinder调用过程——Android开发Binder IPC通信技术
在Android系统中,进程间通信(IPC)是一个非常重要的话题。Android系统通过Binder IPC机制实现进程间通信,而Binder IPC通信技术则是Android系统中最为重要的进程间通信技术之一。本文将介绍Binder IPC通信技术的原理,并…...
篇十五:模板方法模式:固定算法的步骤
篇十五:"模板方法模式:固定算法的步骤" 设计模式是软件开发中的重要知识,模板方法模式(Template Method Pattern)是一种行为型设计模式,用于定义一个算法的骨架,将算法中一些步骤的具…...

web-ssrf
目录 ssrf介绍 以pikachu靶场为例 curl 访问外网链接 利用file协议查看本地文件 利用dict协议扫描内网主机开放端口 file_get_content 利用file协议查看本地文件: fsockopen() 防御方式: ssrf介绍 服务器端请求伪造,是一种由攻击者构造形成…...
【HarmonyOS】【续集】实现从视频提取音频并保存到pcm文件功能(API6 Java)
【关键字】 视频提取类Extractor、视频编解码、保存pcm文件、getAudioTime 【背景和问题】 上篇中介绍了从视频提取音频并保存到pcm文件功能,请参考文档:https://developer.huawei.com/consumer/cn/forum/topic/0209125665541017202?fid0101591351254…...
MySQL为什么要使用 B+Tree 作为索引结构?
MySQL为什么要使用 BTree 作为索引结构? 基本情况 常规的数据库存储引擎 ,一般都是采用 B 树或者 B树来实现索引的存储。B树是一种多路平衡树,用这种存储结构来存储大量数据,它的整个高度 会相比二叉树来说 ,会矮很多…...

Three.js阴影
目录 Three.js入门 Three.js光源 Three.js阴影 使用灯光后,场景中就会产生阴影。物体的背面确实在黑暗中,这称为核心阴影(core shadow)。我们缺少的是落下的阴影(drop shadow),即对象在其他…...

VSCode Remote-SSH (Windows)
1. VSCode 安装 VSCode 2. 安装扩展 Remote SSH Getting started Follow the step-by-step tutorial or if you have a simple SSH host setup, connect to it as follows: Press F1 and run the Remote-SSH: Open SSH Host… command.Enter your user and host/IP in the …...

现代C++中的从头开始深度学习【1/8】:基础知识
一、说明 提及机器学习框架与研究和工业的相关性。现在很少有项目不使用Google TensorFlow或Meta PyTorch,在于它们的可扩展性和灵活性。也就是说,花时间从头开始编码机器学习算法似乎违反直觉,即没有任何基本框架。然而,事实并非…...

Jwt(Json web token)——使用token的权限验证方法 用户+角色+权限表设计 SpringBoot项目应用
目录 引出使用token的权限验证方法流程 用户、角色、权限表设计权限表角色表角色-权限关联表用户表查询用户的权限(四表联查)数据库的视图 项目中的应用自定义注解拦截器controller层DTO返回给前端枚举类型的json化日期json问题 实体类-DAO 总结 引出 1.…...

SpringWeb项目核心功能总结
SpringWeb项目核心功能总结 文章目录 SpringWeb项目核心功能总结1.浏览器与Java程序的连接(个人偏好使用RequestMapping)2.参数的传入3.结果的返回请求转发和请求重定向的区别 核心功能用到的注解: RestControllerControllerResponseBodyRequ…...
Django------信号
Django 框架包含了一个信号机制,它允许若干个发送者(sender)通知一组接收者(receiver)某些特定操作或事件(events)已经发生了, 接收者收到指令信号(signals)后再去执行特定的操作。本文主要讲解Django信号(…...

HTML5 中新增了哪些表单元素?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ HTML5 中新增了的表单元素⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚…...

[考研机试] KY20 完数VS盈数 清华大学复试上机题 C++实现
描述 一个数如果恰好等于它的各因子(该数本身除外)子和,如:6321。则称其为“完数”;若因子之和大于该数,则称其为“盈数”。 求出2到60之间所有“完数”和“盈数”。 输入描述: 题目没有任何输入。 输出描述&#…...

re学习(30)攻防世界-hackme(代码复原2)
思路: 1.输出成功,v26不为0,说明关系式:v21((unsigned __int8)v24 ^ v20) →2.在汇编代码第37行,输入v16v20,所以求的值为v20 →3.根据关系式,求的值v20v21^v24 →4.v21在第汇编代码第36行也可以提取出来…...

Go Windows下开发环境配置(图文)
Go Windows下开发环境配置 下载 安装 点击下载的安装包进行安装。安装路径可以选择到自己的目录。 环境变量配置 GOROOT:(指定到安装目录下) GOPATH:(是工作空间) path:在安装时已经添加了…...
【人工智能概述】python妙用 __str__()
【人工智能概述】python妙用 str() 文章目录 【人工智能概述】python妙用 __str__()一.python内置函数__str__() 一.python内置函数__str__() 通过自定义__str__()函数可以打印对象中相关的内容。 class Person(object):def __init__(self, name tom, age 10):self.name n…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...

聚六亚甲基单胍盐酸盐市场深度解析:现状、挑战与机遇
根据 QYResearch 发布的市场报告显示,全球市场规模预计在 2031 年达到 9848 万美元,2025 - 2031 年期间年复合增长率(CAGR)为 3.7%。在竞争格局上,市场集中度较高,2024 年全球前十强厂商占据约 74.0% 的市场…...

Copilot for Xcode (iOS的 AI辅助编程)
Copilot for Xcode 简介Copilot下载与安装 体验环境要求下载最新的安装包安装登录系统权限设置 AI辅助编程生成注释代码补全简单需求代码生成辅助编程行间代码生成注释联想 代码生成 总结 简介 尝试使用了Copilot,它能根据上下文补全代码,快速生成常用…...
[QMT量化交易小白入门]-六十二、ETF轮动中简单的评分算法如何获取历史年化收益32.7%
本专栏主要是介绍QMT的基础用法,常见函数,写策略的方法,也会分享一些量化交易的思路,大概会写100篇左右。 QMT的相关资料较少,在使用过程中不断的摸索,遇到了一些问题,记录下来和大家一起沟通,共同进步。 文章目录 相关阅读1. 策略概述2. 趋势评分模块3 代码解析4 木头…...

java 局域网 rtsp 取流 WebSocket 推送到前端显示 低延迟
众所周知 摄像头取流推流显示前端延迟大 传统方法是服务器取摄像头的rtsp流 然后客户端连服务器 中转多了,延迟一定不小。 假设相机没有专网 公网 1相机自带推流 直接推送到云服务器 然后客户端拉去 2相机只有rtsp ,边缘服务器拉流推送到云服务器 …...
【Pandas】pandas DataFrame dropna
Pandas2.2 DataFrame Missing data handling 方法描述DataFrame.fillna([value, method, axis, …])用于填充 DataFrame 中的缺失值(NaN)DataFrame.backfill(*[, axis, inplace, …])用于**使用后向填充(即“下一个有效观测值”)…...