drf-- view family

drf view family

Preparatory

The total route 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}),
]

Base table: 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

Model layer 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

Serializer 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  

Base view (views)

Mainly through the view class APIView, which requires its own logic to achieve, you need to write their own interfaces

Sub routing 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()),
]

View layer 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)

View tools (as mixins)

  1. RetrieveModelMixin: Retrieve method implements to get an object
  2. ListModelMixin: List method enables to obtain multiple objects
  3. CreateModelMixin: Create a method to achieve the target increase
  4. UpdateModelMixin: Update method to achieve a single overall update, partial_udate to achieve a single partial update
  5. DestroyModelMixin: Destory method to achieve a single deleted

General view of tool used in conjunction with generics

Tools view (generics)

GenericAPIView

GenericAPIView, The family is the base class for generics, mainly help us qureysetand serializer_classpackaged in a property, the following three ways:

  • get_qureyset():Get more objects
  • get_object():获取一个对象
  • get_serializer(*args, **kwargs):Get the object serialized

GenericAPIViewSubclasses are

It inherits mixinsthe function of a plurality of classes and GenericAPIViewbase classes

The class name Implement an interface
CreateAPIView Tenzin (post)
ListAPIView To take on more (get)
RetrieveAPIView Monosubstituted (GET)
DestroyAPIView Single delete (delete)
UpdateAPIView Single topical (Patch) and overall (PUT) modified
ListCreateAPIView To take on more (get) and an acceleration of (post)
RetrieveUpdateAPIView Monosubstituted (get), a single topical (Patch) and overall (PUT) modified
RetrieveDestroyAPIView Single take (get) and a single deletion (delete)
RetrieveUpdateDestroyAPIView Monosubstituted (get), a single topical (Patch) and overall (PUT) and a single deletion modification (Delete)

Sub routing 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()),
]

View layer 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

Set view (viewsets)

ViewSetMixin: View set of tools, rewrite as_view method, performed the requested mode to the mapping method of the view class

For example: .as_view({'get': 'retrieve', 'delete': 'remove_obj'})to indicate when the request method to get the time, retrieve function will be called when the request method to delete the time, remove_obj function will be called

GenericViewSet: Set of views and models related to the class interface - can inherit from mixins that function, you can also customize function

ViewSet: Nothing to do with the model class or model class instead of the standard interfaces - are generally custom features

Sub routing 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'
    })),
]

View layer 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, '删除失败')

Guess you like

Origin www.cnblogs.com/Hades123/p/11488667.html