一、單查、羣查、單增、單總體改、單局部改均可以直接使用繼承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)