zoukankan      html  css  js  c++  java
  • drf--视图家族

    drf 视图家族

    前期准备

    总路由 urls.py

    from django.contib import admin
    from django.views import serve
    from django.conf import settings
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^api/', include('api.urls')),
        url(r'^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}),
    ]
    

    基表:utils/models.py

    from django.db import models
    
    class BaseModel(models.Model):
        is_delete = models.BooleanField(default=False)
        create_time = models.DateTimeField(auto_now_add=True, null=True)
        
        class Meta:
            # 抽象表, 不会完成数据库迁移
            abstract = True
    

    模型层 api/models.py

    from django.db import models
    from utils.models import BaseModel
    
    class Book(BaseModel):
        name = models.CharField(max_length=64)
        price = models.DecimalField(max_digits=6, decimal_places=2)
        img = models.ImageField(upload_to='icon', default='icon/default.png')
        publish = models.ForeignKey(to='Publish',
                                    null=True,
                                    related_name='books',
                                    db_constraint=False,
                                    on_delete=models.DO_NOTHING
                                    )
        authors = models.ManyToManyField(to='Author',
                                         related_name='authors',
                                         db_constraint=False
    
        @property
        def publish_info(self):
            return {'name': self.publish.name, 'address': self.publish.address}
        
        @property
        def author_info(self):
            author_list = []
            
            for author in self.authors.all():
                detail = AuthorDetail.objects.filter(author_id=self.author.id)
                author_list.append({
                    'name': author.name,
                    'age': author.age,
                    'mobile': '未知' if not detail else author.detail.mobile
                })
                
            return author_list
            
    
        class Meta:
            db_table = "books"
            verbose_name = '书籍'
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.name
    
    
    class Author(BaseModel):
        name = models.CharField(max_length=64)
        age = models.IntegerField()
    
    	@property
        def mobile(self):
            return self.detail.mobile
        
        class Meta:
            db_table = 'author'
            verbose_name = '作者'
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.name
    
    
    class AuthorDetail(BaseModel):
        mobile = models.CharField(max_length=11)
        author = models.OneToOneField(to='Author',
                                      null=True,
                                      related_name='detail',
                                      db_constraint=False,
                                      on_delete=models.CASCADE
                                      )
        class Meta:
            db_table = 'detail'
            verbose_name = '作者详情'
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return f"{self.author.name}的详情"
    
    
    class Publish(BaseModel):
        name = models.CharField(max_length=64)
        address = models.CharField(max_length=128)
    
        class Meta:
            db_table = 'publish'
            verbose_name = '出版社'
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.name
    

    序列化器 api/serializers.py

    from rest_framework import serializers
    from . import models
    
    class BookListSerializer(serializers.ListSerializer):
        def update(self, instance, validated_data):
            for ind, obj in enumerate(instance):
                for attr, value in validated_data[ind].items():
                    if hasattr(obj, attr):
                        set(obj, attr, value)   
                obj.save()
            return instance
    
    class BookV2ModelSerializer(serializers.ModelSerializer):
        re_name = serializers.CharField(
            min_length=3, 
            required=True, 
            write_only=True,  # 只参与反序列化
            error_messages={
                'min_length': '太短了',
                'required': '不能为空'
            }
        )
        
        class Meta:
            model = models.Book
            fields = ('name', 're_name', 'price', 'img', 'publish', 'publish_info', 'authors', 'authors_info')
            list_serializer_class = BookListSerializer
             extra_kwargs = {
                'name':{
                    'min_length': 3,
                    'error_messages': {
                        'min_length': '太短了',
                        'required': '不能为空'
                    }
                },
                # 有默认值的字段会默认required为False,在反序列化中如果不传值不会进行校验,但是如果传值就会进行校验
                'publish':{
                    'required': True,
                    'write_only': True,
                    'error_messages':{
                        'required': '不能为空'
                    }
                },
                'authors':{
                    'required': True,
                    'write_only': True,
                    'error_messages':{
                        'required': '不能为空'
                    }
                },
            }
                
            # 自定义校验规则
            # 局部钩子
            def validate_name(self, value):
                if 'sb' in value:
                    raise serializers.ValidationError('书名包含敏感词汇')
                return value
            
            # 全局钩子
            def validate(self, attr):
                name = attr.get('name')
                re_name = attr.get('re_name')
                publish = attr.get('publish')
                if name != re_name:
                    raise serializers.ValidationError(
                        {'re_name': '两次书名不一致'}
                    )
                    
                # 通过逻辑控制联合唯一
                if models.Book.objects.filter(name=name, publish=publish):
                    raise serializers.ValidationError(
                        {'book': '书籍已存在'}
                    )   
                return attr  
    

    基本视图(views)

    主要就是通过视图类APIView,里面的逻辑都需要自己去实现,需要自己写接口

    子路由 api/urls.py

    from django.conf.urls import url
    from . import views
    urlpatterns = [
        url(r'^books/$', views.BookAPIView.as_view()),
        url(r'^books/(?P<pk>.*)/$', views.BookAPIView.as_view()),
    ]
    

    视图层 api/views.py

    from rest_framework import views
    from . import models, serializers
    from utils.response import APIResponse
    
    class BookAPIView(views.APIView):
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            # 单取
            if pk:
                book_obj = models.Book.objects.filter(is_delete=False, pk=pk).first()
                if not pk:
                    return APIResponse(1, 'pk有误')
                book_ser = serializers.BookV2ModelSerializer(book_obj)
                return APIResponse(0, 'ok', results=book_ser.data)
    
            # 群取
            book_obj_list = models.Book.objects.filter(is_delete=False).all()
            if not book_obj_list:
                return APIResponse(1, '没有数据')
            book_ser = serializers.BookV2ModelSerializer(book_obj_list, many=True)
            return APIResponse(0, 'ok', results=book_ser.data)
    
        # 增加
       def post(self, request, *args, **kwargs):
            # 把单增也转换为群增
            request_data = request.data
            if isinstance(request_data, dict):
                data = [request_data, ]
            elif isinstance(request, list):
                data = request_data
            else:
                return APIView(1, '数据格式有误')
            
            book_ser = serializers.BookV2ModelSerializer(data=data, many=True)
            if book_ser.is_valid():
                book_obj_list = book_ser.save()
                results = serializers.BookV2ModelSerializer(book_obj_list, many=True).data
                return APIResponse(0, 'ok', results=results)
            else:
                return APIResponse(1, '添加失败', results=book_ser.errors)
    

    视图工具类(mixins)

    1. RetrieveModelMixin:retrieve方法实现了获取一个对象
    2. ListModelMixin:list方法实现了获取多个对象
    3. CreateModelMixin:create方法实现了增加一个对象
    4. UpdateModelMixin:update方法实现了单整体更新,partial_udate实现了单局部更新
    5. DestroyModelMixin:destory方法实现了单独删除

    一般结合generics工具视图使用

    工具视图(generics)

    GenericAPIView

    GenericAPIView,是generics家族的基类,主要帮我们把qureysetserializer_class封装成了属性,提供了以下三种方法:

    • get_qureyset():获取多个对象
    • get_object():获取一个对象
    • get_serializer(*args, **kwargs):获取序列化后的对象

    GenericAPIView的子类们

    继承了mixins中多个功能类和GenericAPIView基类

    类名 实现接口
    CreateAPIView 单增(post)
    ListAPIView 多取(get)
    RetrieveAPIView 单取(get)
    DestroyAPIView 单删(delete)
    UpdateAPIView 单局部(patch)及整体(put)修改
    ListCreateAPIView 多取(get)和多增(post)
    RetrieveUpdateAPIView 单取(get),单局部(patch)及整体(put)修改
    RetrieveDestroyAPIView 单取(get)和单删(delete)
    RetrieveUpdateDestroyAPIView 单取(get),单局部(patch)及整体(put)修改和单删(delete)

    子路由 api/urls.py

    from django.conf.urls import url
    from . import views
    urlpatterns = [
        # generics
        url(r'^v1/books/$', views.BookGenericAPIView.as_view()),
        url(r'^v1/books/(?P<pk>.*)/$', views.BookGenericAPIView.as_view()),
    	
        # mixins + generics
        url(r'^v2/books/$', views.BookMixinsGenericAPIView.as_view()),
        url(r'^v2/books/(?P<pk>.*)/$', views.BookMixinsGenericAPIView.as_view()),
    	
        # 系统整合mixins、generics
        url(r'^v3/books/$', views.BookRetrieveUpdateAPIView.as_view()),
        url(r'^v3/books/(?P<pk>.*)/$', views.BookRetrieveUpdateAPIView.as_view()),
    ]
    

    视图层 api/views.py

    from rest_framework import generics, mixins
    from . import models, serializers
    from utils.response import APIResponse
    
    # v1 generics - 视图基类
    class BookGenericAPIView(generics.GenericAPIView):
        queryset = models.Book.objects.filter(is_delete=False).order_by('-id')
        serializer_class = serializers.BookModelSerializer
    
        def get(self, request, *args, **kwargs):
            if 'pk' in kwargs:
                book_obj = self.get_object()
                book_ser = self.get_serializer(book_obj)
                return APIResponse(0, 'ok', results=book_ser.data)
            book_query = self.get_queryset()
            book_ser = self.get_serializer(book_query, many=True)
            return APIResponse(0, 'ok', results=book_ser.data)
    
        def post(self, request, *args, **kwargs):
            book_ser = self.get_serializer(data=request.data)
            book_ser.is_valid(raise_exception=True)
            book_obj = book_ser.save()
            return APIResponse(0, 'ok', results=self.get_serializer(book_obj).data)
    
    # v2 mixins工具集 + generics视图基类
    class BookMixinsGenericAPIView(mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
        queryset = models.Book.objects.filter(is_delete=False).order_by('-id')
        serializer_class = serializers.BookModelSerializer
        def get(self, request, *args, **kwargs):
            if 'pk' in kwargs:
                response = self.retrieve(request, *args, **kwargs)
            else:
                response = self.list(request, *args, **kwargs)
            return APIResponse(0, 'ok', results=response.data)
    
        def post(self, request, *args, **kwargs):
            response = self.create(request, *args, **kwargs)
            return APIResponse(0, 'ok', results=response.data)
    
    # v3 视图基类子类 - 工具视图类
    class BookRetrieveUpdateAPIView(generics.RetrieveUpdateAPIView):
        queryset = models.Book.objects.filter(is_delete=False).order_by('-id')
        serializer_class = serializers.BookModelSerializer
    
    

    视图集(viewsets)

    ViewSetMixin:视图集工具,重写了as_view方法, 完成了请求方式到视图类中的方法的映射

    例如:.as_view({'get': 'retrieve', 'delete': 'remove_obj'}), 表示当请求方式为get的时候,则会调用retrieve函数,当请求方式为delete的时候,则会调用remove_obj函数

    GenericViewSet:与模型类有关的接口视图集 - 可以从mixins那继承功能,也可以自定义功能

    ViewSet:与模型类无关或不是标准模型类接口 - 一般都是自定义功能

    子路由 api/urls.py

    from django.conf.urls import url
    from . import views
    urlpatterns = [
        url(r'^v4/books/$', views.BookGenericViewSet.as_view({
            'get': 'list',
            'post': 'create'
        })),
        url(r'^v4/books/(?P<pk>.*)/$', views.BookGenericViewSet.as_view({
            'get': 'retrieve',
            'put': 'update',
            'patch': 'partial_update',
            'delete': 'remove_book'
        })),
    ]
    

    视图层 api/views.py

    from rest_framework import mixins, viewsets
    from . import models, serializers
    from utils.response import APIResponse
    
    class BookGenericViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin, viewsets.GenericViewSet):
        queryset = models.Book.objects.filter(is_delete=False).order_by('-id')
        serializer_class = serializers.BookModelSerializer
    
        def remove_book(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            try:
                book_obj = models.Book.objects.get(is_delete=False, pk=pk)
                book_obj.is_delete = True
                book_obj.save()
                return APIResponse(0, '删除成功')
            except:
                return APIResponse(1, '删除失败')
    
  • 相关阅读:
    Spring中的事务传播行为与隔离级别
    redis分布式共享锁模拟抢单的实现
    synchronized关键字修饰非静态方法与静态方法的区别
    docker安装Tensorflow并使用jupyter notebook
    python 图像处理(4):图像的绘制
    python 图像处理(3):图像数据类型及颜色空间转换
    python 图像处理 (2):图像像素的访问与裁剪
    python 读取图像的几种方法
    python 图像处理:图像的读取、显示与保存
    NLP 正向、逆向 分词
  • 原文地址:https://www.cnblogs.com/Hades123/p/11488667.html
Copyright © 2011-2022 走看看