一、单查、群查、单增、单总体改、单局部改均可以直接使用继承GenericAPIView和mixins对应的包下面的功能数据库
二、单删不能直接使用,由于默认提供的功能是删除数据库数据,而不是咱们自定义的is_delete字段值修改,因此须要咱们来实现django
三、除了群查之外的群接口咱们都须要本身来实现api
注:给序列化类的context={'request': request},序列化类就能够自动补全后台图片的连接,不须要咱们手动拼接了app
from rest_framework.generics import GenericAPIView from rest_framework import mixins from . import models, serializers from rest_framework.response import Response class BookV1APIView(GenericAPIView, mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin): queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookModelSerializer def get(self, request, *args, **kwargs): if 'pk' in kwargs: # 单查 return self.retrieve(request, *args, **kwargs) # 群查 return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs): if not isinstance(request.data, list): # 单增 return self.create(request, *args, **kwargs) # 群增 serializer = self.get_serializer(data=request.data, many=True) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=201, headers=headers) def put(self, request, *args, **kwargs): if 'pk' in kwargs: # 单总体改 return self.update(request, *args, **kwargs) # 群总体改,须要配合serializers中的ListSerializer重写update方法 pks = [] try: for dic in request.data: pks.append(dic.pop('pk')) objs = models.Book.objects.filter(is_delete=False, pk__in=pks) assert len(objs) == len(request.data) except: return Response(status=400) serializer = serializers.BookModelSerializer(instance=objs, data=request.data, many=True) serializer.is_valid(raise_exception=True) objs = serializer.save() return Response(serializers.BookModelSerializer(objs, many=True).data) def patch(self, request, *args, **kwargs): if 'pk' in kwargs: # 单局部改 return self.partial_update(request, *args, **kwargs) # 群局部改,须要配合serializers中的ListSerializer重写update方法 pks = [] try: for dic in request.data: pks.append(dic.pop('pk')) objs = models.Book.objects.filter(is_delete=False, pk__in=pks) assert len(objs) == len(request.data) except: return Response(status=400) serializer = serializers.BookModelSerializer(instance=objs, data=request.data, many=True, partial=True) serializer.is_valid(raise_exception=True) objs = serializer.save() return Response(serializers.BookModelSerializer(objs, many=True).data) def delete(self, request, *args, **kwargs): pk = kwargs.get('pk') if pk: # 单删 pks = [pk] else: # 群删 pks = request.data try: rows = models.Book.objects.filter(is_delete=False, pk__in=pks).update(is_delete=True) except: return Response(status=400) if rows: return Response(status=204) return Response(status=400)
serializers.py框架
from rest_framework import serializers from . import models # 只有群改接口时才须要用到Listserializer,重写update方法 class BookListSerializer(serializers.ListSerializer): def update(self, queryset, validated_data_list): return [ self.child.update(queryset[index], validated_data) for index, validated_data in enumerate(validated_data_list) ] class BookModelSerializer(serializers.ModelSerializer): class Meta: # 群改配置 list_serializer_class = BookListSerializer model = models.Book fields = ['name', 'price', 'image', 'publish', 'authors','publish_name', 'author_list'] extra_kwargs = { 'publish':{ 'write_only': True }, 'authors':{ 'write_only': True } }
一、单查群查不能共存ide
二、单删不会使用自带的通常都重写函数
# 基于generics下的六大基础接口 from rest_framework import generics class BookV2APIView(generics.RetrieveAPIView, generics.ListAPIView, generics.CreateAPIView, generics.UpdateAPIView, generics.DestroyAPIView): queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookModelSerializer # 单查和群查不能共存,因此咱们重写get方法 def get(self, request, *args, **kwargs): if 'pk' in kwargs: return self.retrieve(request, *args, **kwargs) return self.list(request, *args, **kwargs) # 删除是默认删除数据库,因此咱们重写删除接口 def delete(self, request, *args, **kwargs): # 单删 pk = kwargs.get('pk') models.Book.objects.filter(is_delete=False, pk=pk).update(is_delete=True) return Response(status=204)
一、工具视图类,能够完成应对六大基础接口,惟一的缺点就是单查和群查不能共存(只须要配置queryset、serializer_class、lookup_field)工具
二、不能共存的缘由:RetrieveAPIView和ListAPIView都是get方法,无论带不带pk的get请求,只能映射给一个get方法源码分析
三、修改映射关系来改善此缺点:将群查映射给list,单查映射给retrieve方法,甚至能够自定义映射关系post
@classonlymethod def as_view(cls, actions=None, **initkwargs): ... # 没有actions,也就是调用as_view()没有传参,像as_view({'get': 'list'}) if not actions: raise TypeError("The `actions` argument must be provided when " "calling `.as_view()` on a ViewSet. For example " "`.as_view({'get': 'list'})`") ... # 请求来了走view函数,解析出actions中是什么请求,再经过dispatch完成分发 def view(request, *args, **kwargs): ... # 解析actions,修改 请求分发 - 响应函数 映射关系 self.action_map = actions for method, action in actions.items(): # method:get | action:list handler = getattr(self, action) # 从咱们视图类用action:list去反射,因此handler是list函数,不是get函数 setattr(self, method, handler) # 将get请求对应list函数,因此在dispath分发请求时,会将get请求分发给list函数 ... # 经过视图类的dispatch完成最后的请求分发 return self.dispatch(request, *args, **kwargs) ... # 保存actions映射关系,以便后期使用 view.actions = actions return csrf_exempt(view)
一、能够直接继承ModelViewSet,实现六大继承接口(是否重写destroy方法或其余自定义方法根据需求决定)
二、能够继承ReadOnlyModelViewSet,仅实现只读(单查、群查)
三、继承Viewset类与Model类关系不是很密切的接口:登陆post请求,查询操做,短信验证码接口,借助第三方平台
四、继承继承GenericViewSet类,必需要配合mixins包完成任意的组合
五、继承以上4个视图集中的任何一个,均可以与路由as_view({映射})配合,完成自定义的请求响应方法
urls.py
url(r'^v3/books/$', views.BookV3APIView.as_view( {'get': 'list', 'post': 'create', 'delete': 'multiple_destroy'} )), url(r'^v3/books/(?P<pk>\d+)/$', views.BookV3APIView.as_view( {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'} )),
views.py
from rest_framework.viewsets import ModelViewSet from rest_framework.response import Response class BookV3APIView(ModelViewSet): queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookModelSerializer ---------------------若是不须要自定义五大基础接口上述两行代码便可------------------ # 能够在urls.py中as_view({'get': 'my_list'})自定义的请求映射 def my_list(self, request, *args, **kwargs): return Response('ok') # 须要完成字段删除,不是重写delete方法,而是重写destroy方法 def destroy(self, request, *args, **kwargs): pk = kwargs.get('pk') models.Book.objects.filter(is_delete=False, pk=pk).update(is_delete=True) return Response(status=204) # 群删接口 def multiple_destroy(self, request, *args, **kwargs): try: models.Book.objects.filter(is_delete=False, pk__in=request.data).update(is_delete=True) except: return Response(status=400) return Response(status=204)
二、继承ReadOnlyModelViewSet,仅实现只读(单查、群查)
from rest_framework.viewsets import ReadOnlyModelViewSet class BookV4APIView(ReadOnlyModelViewSet): queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookModelSerializer
必须配合视图集使用
urls.py
from django.conf.urls import url, include from . import views # 路由组件,必须配合视图集使用 from rest_framework.routers import SimpleRouter router = SimpleRouter() # 之后就写视图集的注册便可:BookV3APIView和BookV4APIView都是视图集,路由后不须要加/,router中带的有 router.register('v3/books', views.BookV3APIView, 'book') router.register('v4/books', views.BookV4APIView, 'book') urlpatterns = [ url('', include(router.urls)) ]
views.py
from rest_framework.viewsets import ModelViewSet from rest_framework.response import Response class BookV3APIView(ModelViewSet): queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookModelSerializer from rest_framework.viewsets import ReadOnlyModelViewSet class BookV4APIView(ReadOnlyModelViewSet): queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookModelSerializer
新建自定义router.py文件,自定义后在urls.py中使用咱们自定义的router
router.py
from rest_framework.routers import SimpleRouter as DrfSimpleRouter from rest_framework.routers import Route, DynamicRoute class SimpleRouter(DrfSimpleRouter): routes = [ # List route. Route( url=r'^{prefix}{trailing_slash}$', mapping={ 'get': 'list', 'post': 'create', # 注:群增只能本身在视图类中重写create方法,完成区分 'delete': 'multiple_destroy', # 新增:群删 'put': 'multiple_update', # 新增:群总体改 'patch': 'multiple_partial_update' # 新增:群局部改 }, name='{basename}-list', detail=False, initkwargs={'suffix': 'List'} ), # Dynamically generated list routes. Generated using # @action(detail=False) decorator on methods of the viewset. DynamicRoute( url=r'^{prefix}/{url_path}{trailing_slash}$', name='{basename}-{url_name}', detail=False, initkwargs={} ), # Detail route. Route( url=r'^{prefix}/{lookup}{trailing_slash}$', mapping={ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy' }, name='{basename}-detail', detail=True, initkwargs={'suffix': 'Instance'} ), # Dynamically generated detail routes. Generated using # @action(detail=True) decorator on methods of the viewset. DynamicRoute( url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$', name='{basename}-{url_name}', detail=True, initkwargs={} ), ]
urls.py
from django.conf.urls import url, include from . import views # 路由组件,必须配合视图集使用 from rest_framework.routers import SimpleRouter router = SimpleRouter() # /books/image/(pk) 提交 form-data:用image携带图片 router.register('books/image', views.BookUpdateImageAPIView, 'book') urlpatterns = [ url('', include(router.urls)) ]
serializers.py
class BookUpdateImageModelSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = ['image']
views.py
# 上传文件 - 修改头像 - 修改海报 from rest_framework.viewsets import GenericViewSet from rest_framework import mixins class BookUpdateImageAPIView(GenericViewSet, mixins.UpdateModelMixin): queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookUpdateImageModelSerializer
Django的Auth组件采用的认证规则就是RBAC(基于角色的访问控制)
1)是否须要分表 答案:不须要 理由:先后台用户共存的项目,后台用户量都是不多;作人员管理的项目,基本上都是后台用户;先后台用户量都大的会分两个项目处理
2)用户权限六表是否须要断关联 答案:不须要 理由:前台用户占主导的项目,几乎需求只会和User一个表有关;后台用户占主导的项目,用户量不会太大
3)Django项目有没有必须自定义RBAC六表 答案:不须要 理由:auth组件功能十分强大且健全(验证密码,建立用户等各类功能);admin、xadmin、jwt、drf-jwt组件都是依赖auth组件的(自定义RBAC六表,插件都须要自定义,成本极高)
三基础表:
权限六表:
一、后台用户对各表操做,是后台项目完成的,咱们能够直接借助admin后台项目(Django自带的)
二、后期也可使用xadmin框架来作后台用户权限管理
三、前台用户的权限管理如何处理
定义一堆数据接口的视图类,不一样的登陆用户是否能访问这些视图类,能就表明有权限,不能就表明没有权限
前台用户权限用drf框架的三大认证
前台用户权限会基于 jwt 认证
models.py
from django.db import models # RBAC - Role-Based Access Control # Django的 Auth组件 采用的认证规则就是RBAC from django.contrib.auth.models import AbstractUser # 自定义 User 表 class User(AbstractUser): mobile = models.CharField(max_length=11, unique=True) def __str__(self): return self.username class Book(models.Model): name = models.CharField(max_length=64) def __str__(self): return self.name class Car(models.Model): name = models.CharField(max_length=64) def __str__(self): return self.name
settings.py
# 自定义User表,要配置 AUTH_USER_MODEL = 'api.User'
admin.py
from django.contrib import admin from . import models from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin # 自定义User表后,admin界面管理User类 class UserAdmin(DjangoUserAdmin): # 添加用户课操做字段 add_fieldsets = ( (None, { 'classes': ('wide',), 'fields': ('username', 'password1', 'password2', 'is_staff', 'mobile', 'groups', 'user_permissions'), }), ) # 展现用户呈现的字段 list_display = ('username', 'mobile', 'is_staff', 'is_active', 'is_superuser') admin.site.register(models.User, UserAdmin) admin.site.register(models.Book) admin.site.register(models.Car)