前言
记录下这些view的使用,方便以后查阅
Model
from django.db import models
from django.conf import settings
from utils.models import BaseModel
class Projects(BaseModel):
id = models.AutoField(primary_key=True,verbose_name='id主键',help_text='id主键')
name = models.CharField('项目名称', max_length=40, unique=True, help_text='项目名称')
leader = models.ForeignKey(to = settings.AUTH_USER_MODEL, verbose_name='负责人',
null=True, on_delete=models.SET_NULL, related_name='projects_leader')
desc = models.CharField('项目描述', max_length=200, null=True, blank=True, default='',
help_text='项目描述')
class Meta:
db_table = 'tb_projects'
verbose_name = '项目信息'
verbose_name_plural = verbose_name
ordering = ['-c_time']
def __str__(self):
return self.name
Serializers
from rest_framework import serializers
from projects.models import Projects
class ProjectModelSerializer(serializers.ModelSerializer):
email = serializers.EmailField(write_only=True)
leader = serializers.ReadOnlyField(source='leader.username')
def validate_name(self, value):
value: str
if not value.endswith('项目'):
raise serializers.ValidationError('项目名称必须得以“项目”结尾')
return value
def create(self, validated_data: dict):
validated_data.pop('email')
obj = Projects.objects.create(**validated_data)
return obj
def update(self, instance, validated_data):
instance.name = validated_data.get('name')
instance.save()
return instance
class Meta:
model = Projects
exclude = ['is_delete', 'u_time']
一、APIView
- 继承APIView的视图类具备View的所有特性
- 提取请求字符串参数的request.query_parms方法,可以获取到前端的查询字符串参数
- 请求体参数的request.data方法,可以获取到请求体参数
- APIView为视图类提供了认证,授权,限流等功能
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from projects.models import Projects
from projects.serializers import ProjectModelSerializer
class ProjectsViews(APIView):
# 获取数据库所有数据
def get(self,request):
# 从数据库查询出所有的数据
project_list = Projects.objects.all()
# 使用serializers里定义的序列化器对库里查出来的数据进行序列化,instance: 要序列化的对象,就是从库里查出来的数据
# many: 如果是查询集对象,many=True;如果是单个对象,many=False
serializer = ProjectModelSerializer(instance=project_list,many=True)
# 将序列化后的数据返回给前端,serializer.data序列化后是字典
return Response(serializer.data)
# 新增
def post(self,request):
# 获取前端传过来的数据,字典格式传入data进行反序列化,创建序列化器对象
serializer = ProjectModelSerializer(data=request.data)
# 校验数据
if serializer.is_valid(): # 如果是TRUE,表示数据校验通过,通过,就保存
# 如果instance为None,调用save本质会调用create--》父类create直接抛异常,所以我们要重写
# 序列化器对象调用save方法时,会调用序列化器类中的create方法,进行数据创建操作
serializer.save() # 就会保存,重写create方法,如果不重写,我们不知道存到哪个表中,前提是使用的serializer,不是modelserializer
# return Response(serializer.data)
return Response(serializer.data, status=status.HTTP_200_OK)
return Response({'code':101,'msg':'数据校验失败','err':serializer.errors})
class ProjectsDetailViews(APIView):
# 获取数据库单条数据
def get(self,requet,pk):
project_detail_list = Projects.objects.filter(pk=pk).first()
serializer = ProjectModelSerializer(instance=project_detail_list)
if project_detail_list:
return Response(serializer.data)
else:
return Response({'code':103,'msg':'数据不存在'}, status=status.HTTP_204_NO_CONTENT)
# 修改单条数据
def put(self,request,pk):
# 用什么数据,修改哪条数据
project_update_one = Projects.objects.filter(pk=pk).first()
# 进行序列化,既有instance又有data,表示修改
serializer = ProjectModelSerializer(instance=project_update_one,data=request.data)
# 校验数据
if serializer.is_valid():
serializer.save() # 重写update方法
return Response(serializer.data)
return Response({'code':102,'msg':'修改出错','err':serializer.errors})
# 删除
def delete(self,request,pk):
# 先获取要删除哪条数据
project_del_one = Projects.objects.filter(pk=pk).delete()
if project_del_one[0]>0:
return Response({'code':100,'msg':'删除成功'}, status=status.HTTP_204_NO_CONTENT)
else:
return Response({'code':103,'msg':'数据不存在'}, status=status.HTTP_204_NO_CONTENT)
二、GenericAPIView
- 具备View的所有特性
- 具备APIView中的认证,授权,限流功能
- 支持对于获取列表数据接口的过滤,排序,分页功能
- 一旦继承了GenericAPIView,往往需要指定queryset,serializer_class类属性
过滤
- 安装django-filter : pip install django-filter
- settings中进行配置
INSTALL_APPS = {
...
'django_filters',
...
}
REST_FRAMEWORK = {
# 通用配置,所有的视图默认使用 #全局配置,对全部视图的查询多条接口都有过滤功能,但是视图里要指定字段
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
}
- 访问127.0.0.1/employees?gender=1时可以过滤出性别字段是1的数据。
class EmployeeViewSet(ModelViewSet):
queryset = Employee.objects.all()
serializer_class = EmployeeSerializer
# 指定可以根据哪些字段进行列表数据的过滤
filterset_fields = ('gender', 'department')
# 单独视图配置
from django_filters.rest_framework import DjangoFilterBackend
class SomeVIew(generics.xxxAPIView):
...
# 指定过滤器
fitler_backends = [DjangoFilterBackend]
# 指定可以根据哪些字段进行列表数据的过滤
filterset_fields = ['project', 'project__name']
排序
- 访问127.0.0.1/employees/?ordering=age(年龄升序)
- 访问127.0.0.1/employees/?ordering=-age(年龄降序)
- 访问127.0.0.1/employees/?ordering=age,-salary(先安装年龄升序来排,如果年龄一样,按工资升序来排)
class EmployeeViewSet(ModelViewSet):
queryset = Employee.objects.all()
serializer_class = EmployeeSerializer
# 新增排序的过滤器
filter_backends = [..., OrderingFilter]
# 指定可以根据哪此字段进行排序
ordering_fields = ('age', 'salary')
分页
- 在settings中配置
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 2 # 每页显示多少条数据
}
定义完分页器后,可以在某个视图里面进行使用:
class DepartmentViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
...
# 指定分页配置
pagination_class = MyPageNumberPagination
...
如果url是127.0.0.1/department?page=3&page_size=5,代表打开第3页,每一页显示5条数据。
- 自定义分页器
class MyPageNumberPagination(PageNumberPagination):
# 指定默认每一页显示的数据条数
page_size = 3
# 前端用于指定页号的查询字符串参数名称
page_query_param = 'page'
# 指定前端用于指定页号的查询字符串参数的描述
page_query_description = '获取的页码'
# page_size_query_param = "page_size"
# 前端用于指定每一页的数据条数,查询字符串参数名称
# 只要设置了page_size_query_param,那么前端就支持指定获取每一页的数据条数
page_size_query_param = "size"
# 前端用于指定每一页的数据条数,查询字符串参数的描述
page_size_query_description = '每一页数据条数'
max_page_size = 100
def get_paginated_response(self, data):
response = super().get_paginated_response(data)
response.data['current_page_num'] = self.page.number
response.data['total_pages'] = self.page.paginator.num_pages
return response
from rest_framework import status
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from projects.models import Projects
from projects.serializers import ProjectModelSerializer
class ProjectsViews(GenericAPIView):
# 需要指定queryset和serializer_class
queryset = Projects.objects.all()
serializer_class = ProjectModelSerializer
# 指定可以根据哪些字段进行列表数据的过滤 ?name=
filterset_fields = ('name', 'leader')
# 需要新增排序的过滤器
filter_backends = [DjangoFilterBackend,OrderingFilter]
# 指定可以根据哪此字段进行排序
ordering_fields = ('id')
# 分页
pagination_class = PageNumberPagination
def get(self, request):
# 直接从数据库取出来数据进行了序列化
serializer = self.get_serializer(instance=self.get_queryset(), many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
def post(self,request):
serializer = self.get_serializer(data = request.data)
serializer.is_valid(raise_exception = True)
serializer.save()
return Response(serializer.data,status = status.HTTP_201_CREATED)
class ProjectsDetailViews(GenericAPIView):
queryset = Projects.objects.all()
serializer_class = ProjectModelSerializer
def get(self,request):
serializer = self.get_serializer(instance = self.get_object())
return Response(serializer.data,status=status.HTTP_200_OK)
def put(self,request):
serializer = self.get_serializer(instance = self.get_object(),data = request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
def delete(self,request):
self.get_object().delete()
return Response({'code':1003,'msg':'数据删除成功'},status=status.HTTP_204_NO_CONTENT)
具备的类属性和方法
类属性:
queryset = None
serializer_class = None
lookup_field = ‘pk’
lookup_url_kwarg = None
filter_backends =api_settings.DEFAULT_FILTER_BACKENDS
pagination_class =api_settings.DEFAULT_PAGINATION_CLASS
- queryset
queryset是用来控制视图返回给前端的数据。如果没什么逻辑,可以直接写在视图的类属性中,如果逻辑比较复杂,也可以重写get_queryset方法用来返回一个queryset对象。如果重写了get_queryset,那么以后获取queryset的时候就需要通过调用get_queryset方法。因为queryset这个属性只会调用一次,以后所有的请求都是使用他的缓存。
- serializer_class
当前类视图的内部的实例方法会用到的序列化器类
- lookup_field
在检索的时候,根据什么参数进行检索。默认是pk,也就是主键。
- lookup_url_kwarg
在检索的url中的参数名称。默认没有设置,跟lookup_field保持一致。
- filter_backends
用于过滤查询集的过滤器后端类的列表。默认值与DEFAULT_FILTER_BACKENDS 设置的值相同。
- pagination_class
当分页列出结果时应使用的分页类。默认值与DEFAULT_PAGINATION_CLASS 设置的值相同,即 ‘rest_framework.pagination.PageNumberPagination’。
方法:
- get_queryset(self)
默认返回由 queryset 属性指定的查询集。默认是返回数据库全部数据,如果想返回其他数据,需要自定义。
def get_queryset(self):
assert self.queryset is not None, (
"'%s' should either include a `queryset` attribute, "
"or override the `get_queryset()` method."
% self.__class__.__name__
)
queryset = self.queryset # 设置queryset等于一个查询集,这里的queryset等于self的queryset
if isinstance(queryset, QuerySet): # 判断queryset是不是查询集类型
queryset = queryset.all() # 是的话就获取所有数据,然后返回
return queryset
- get_object(self)
返回详情pk视图所需的模型类数据对象。默认使用 lookup_field 参数过滤基本的查询集。
def get_object(self):
queryset = self.filter_queryset(self.get_queryset())
# Perform the lookup filtering.
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
assert lookup_url_kwarg in self.kwargs, (
'Expected view %s to be called with a URL keyword argument '
'named "%s". Fix your URL conf, or set the `.lookup_field` '
'attribute on the view correctly.' %
(self.__class__.__name__, lookup_url_kwarg)
)
filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
obj = get_object_or_404(queryset, **filter_kwargs)
# May raise a permission denied
self.check_object_permissions(self.request, obj)
return obj
返回具体pk值的数据
def get_object(self,pk):
try:
return Projects.objects.get(id=pk)
except Exception:
raise Http404
- get_serializer(self, instance=None, data=None, many=False, partial=False)
返回一个序列化器的实例,不需要重写get_serializer()方法,直接调用即可
def get_serializer(self, *args, **kwargs):
serializer_class = self.get_serializer_class() # 调用上面的方法获取serializer_class属性再返回
kwargs.setdefault('context', self.get_serializer_context())
return serializer_class(*args, **kwargs)
- get_serializer_class(self)
返回应用于序列化的类。默认为返回 serializer_class 属性的值。如果您需要根据传入请求提供不同的序列化,您可能需要重写它。
def get_serializer_class(self):
assert self.serializer_class is not None, (
"'%s' should either include a `serializer_class` attribute, "
"or override the `get_serializer_class()` method."
% self.__class__.__name__
)
return self.serializer_class # 返回一个serializer_class,模型序列化器
- filter_queryset(self)
默认不需要过滤,如果需要过滤需要重写
filter_queryset()方法
def filter_queryset(self, queryset):
"""
Given a queryset, filter it with whichever filter backend is in use.
You are unlikely to want to override this method, although you may need
to call it either from a list view, or from a custom `get_object`
method if you want to apply the configured filtering backend to the
default queryset.
"""
for backend in list(self.filter_backends):
queryset = backend().filter_queryset(self.request, queryset, self)
return queryset
- paginate_queryset(self)
a、默认不需要分页,如果需要分页需要重写paginate_queryset()方法
b、如果self.paginator 为 None,不需要进行过滤,否则需要通过self.paginator.paginate_queryset()方法进行过滤
def paginate_queryset(self, queryset):
"""
Return a single page of results, or `None` if pagination is disabled.
"""
if self.paginator is None:
return None
return self.paginator.paginate_queryset(queryset, self.request, view=self)
三、五个扩展类
扩展类 | 作用 | 封装的方法 | 状态码(成功、失败) |
---|---|---|---|
ListModelMixin | 查询多条数据 | list | 200 |
CreateModelMixin | 新增一条数据 | create | 201/400 |
RetrieveModelMixin | 查询一条数据 | retrieve | 200/404 |
UpdateModelMixin | 更新一条数据 | update/partial_update | 200/400 |
DestroyModelMixin | 删除一条数据 | destroy | 204/404 |
from rest_framework.filters import OrderingFilter
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, \
DestroyModelMixin
from projects.models import Projects
from projects.serializers import ProjectModelSerializer
class ProjectsViews(ListModelMixin, CreateModelMixin, GenericAPIView):
# 需要指定queryset和serializer_class
queryset = Projects.objects.all()
serializer_class = ProjectModelSerializer
def get(self, request):
return self.list(request)
def post(self, request):
return self.create(request)
class ProjectsDetailViews(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericAPIView):
queryset = Projects.objects.all()
serializer_class = ProjectModelSerializer
def get(self, request, pk):
return self.retrieve(request, pk)
def post(self, request, pk):
return self.update(request, pk)
def delete(self, request, pk):
return self.destroy(request, pk)
四、子类视图
视图 | 作用 | 方法 |
---|---|---|
ListAPIView | 查询多条数据 | get |
CreateAPIView | 新增一条数据 | post |
RetrieveAPIView | 查询一条数据 | get |
UpdateAPIView | 更新一条数据 | put/patch |
DestroyAPIView | 删除一条数据 | delete |
RetrieveUpdateAPIView | 查询,更新一条数据 | get/put/patch |
RetrieveUpdateDestroyAPIView | 获取,更新,删除一条数据 | get/put/patch/delete |
class DepartmentListAPIView(ListAPIView,CreateAPIView):
”“”实现了查询多条数据和新增一条数据的功能"""
queryset = Department.objects.all()
serializer_class = DepartmentSerializer
class DepartmentDetailAPIView(RetrieveUpdateDestroyAPIView):
"""实现了查询一条数据、修改一条数据、删除一条数据的功能"""
queryset = Department.objects.all()
serializer_class = DepartmentSerializer
五、视图集ModelViewSet
- 继承自GenericViewSet
- 包括了 ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestroyModelMixin
class ProjectsViews(ModelViewSet):
# 需要指定queryset和serializer_class
queryset = Projects.objects.all()
serializer_class = ProjectModelSerializer
路由
urlpatterns = [
path('projects', views.ProjectsViews.as_view({'get':'list','post':'create'})),
path('projects/<int:pk>', views.ProjectsDetailViews.as_view({
'get':'retrieve','put':'update','delete':'destroy'
}))
]