Day 24 DRF view set

Day 24 DRF view set

One, DRF-ModelSerializer many-to-many data creation

models.py

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    author = models.ManyToManyField(to='Author', null=True)  # 多对多关系
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)  # 外键关系


class Publish(models.Model):
    name = models.CharField(max_length=32)
    address = models.CharField(max_length=64)


class Author(models.Model):
    name = models.CharField(max_length=32)
    salary = models.IntegerField()
    phone = models.CharField(max_length=11)

serializer.py

class Author(serializers.ModelSerializer):
    class Meta:
        # 关联
        model = models.Author
        # 选取需要显示的字段
        fields = '__all__'


class Publish(serializers.ModelSerializer):
    class Meta:
        model = models.Publish
        fields = ['name', 'address']


class BookModel(serializers.ModelSerializer):
    author1 = Author(read_only=True)
    publish = Publish()  # 外键这样能够读出来但是不能存 
    # 存
    # publish1 = Publish(read_only=True)
    
    class Meta:
        model = models.Book  # 表模型 与之关联
        fields = '__all__'

image-20201106162231549

But it won’t work

No read_only = True

class BookModel(serializers.ModelSerializer):
    author = Author()
    publish = Publish()

This will not work, because the two fields correspond to table objects,

When get, because the original author corresponds to the relationship , it has become a table object (overwritten). Publish is the same, so the data cannot be found.

image-20201106163137040

By default, when post is to be stored in the complete object , which is a dictionary

image-20201106163002535

This problem is due to -many relationship is very special, he is a middle of the table of the original corresponding table relationships into table object can not find the corresponding data fields, so error, here we have reserved the original table relationships (author fields)

If we want to cross-table queries need to redefine a field name (author1), and set read_onlyproperties so that drf by ModelSerializerlooking for fields corresponding to the content, if not set will with their (author)conflict, which is separate read and write , in charge of their own write_only, Then you can read and write normally!

Two, view base class (2)

Django REST framwork provides the main role of views

  • Control the execution of the serializer (check, save, convert data)
  • Control database query

The biggest difference between the two is GenericAPIView继承APIView类的,在拥有APIView所有特性外,还提供了链接Model类与Serializer类的接口

1. APIView

It is the base class of all views provided by REST framework, inheriting native Django View

From the previous process, we know that he inherits the as_view method of the parent class, executes his own dispath, and then returns the REST framework Responseobject. Of course, many things have happened!

APIView still uses conventional class view definition methods to implement get(), post() or other request methods.

2.GenericAPIView

Inherited from APIVIew, it mainly adds methods for operating serializers and database queries. Its role is to provide method support for the execution of the following Mixin extension classes. Usually, it can be used with one or more Mixin extension classes.

2.1 Support defined attributes

  • List view and detail view are common
    • queryset list view query set
    • serializer_class The serializer used by the view
  • List view usage
    • pagination_class paging control class
    • filter_bankends filter control backend
  • Details page view usage
    • lookup_field The condition field used when querying a single database object, the default is "pk"
    • lookup_url_kwarg The name of the parameter keyword in the URL when querying a single data, the default is the same as look_field

2.2 Methods provided

  • List view and detail view
    • get_queryset() The query set used by the return view is the basis for the list view and the detail view to obtain data. The queryset attribute is returned by default, which can be overridden
    • get_serializer_class() Return the serializer object, which is used by other views or extended classes. If we want to get the serializer object in the view, we can call this method directly
    • get_serializer() Return the serializer object, which is used by other views or extended classes. If we want to get the serializer object in the view, we can call this method directly.
    • get_object() Return a model object required by the detail view, the lookup_field parameter is used by default to filter the queryset

Let's try GenericAPIView

serializer.py Same as above

views.py

from rest_framework.generics import GenericAPIView
from rest_framework.response import Response

class Book(GenericAPIView):
    # 因为是queryset对象 可以自调用 加不加all()不重要,源码中默认加了 all()
    queryset = models.Book.objects
    serializer_class = serializer.BookModel
    
    def get(self, request, *args, **kwargs):
        books = self.get_queryset()
        ser = self.get_serializer(books, many=True)
        return Response(ser.data)
    
    def post(self, request, *args, **kwargs):
        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)

Let's send a get request and get the data we needimage-20201106194512105

Let's study the source code

image-20201106202345992

Operation of checking, modifying and deleting a single record

urls.py
url(r'^bookinfo/(?P<pk>\d+)', views.BookInfo.as_view()),
views.py

The overall logic is similar to our previous APIView, with a slight change in method

class BookInfo(GenericAPIView):
    queryset = models.Book.objects
    serializer_class = serializer.BookModel
    
    def get(self,request,*args, **kwargs):
        book = self.get_object()
        ser = self.get_serializer(book)
        return Response(ser.data)
    
    def patch(self,request,*args, **kwargs):
        book = self.get_object()
        ser = self.get_serializer(book, data = request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return  Response('保存失败!')
        
    def delete(self,request,*args, **kwargs):
        book = self.get_object().delete()
        return Response('删除成功!')

Only test the modification method this time

image-20201106203733877

Source code analysis

image-20201106210552150

Three, view extension class (5)

Provides several back-end views (deleted, modified, and checked data resources) to achieve the processing flow. If the views that need to be written belong to these five types, the views can reuse the code by inheriting the corresponding extension classes, reducing the code written by themselves the amount.

These five extension classes need to be matchedGenericAPIViewThe parent class, because the implementation of the five extended classes need to call the GenericAPIView providedSerializerversusDatabase queryMethods.

1. ListModelMixin

The list view extension class provides list(request, *args, **kwargs)methods to quickly implement the list view and return a 200 status code. The Mixin's list method performs datafilterwithPagination

Source code:

Copyclass ListModelMixin(object):
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        # 过滤
        queryset = self.filter_queryset(self.get_queryset())
        # 分页
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        # 序列化 自己覆盖GenericAPIView的queryset和serializer
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

Give a chestnut

class Book(ListModelMixin, CreateModelMixin, GenericAPIView):
    
    queryset = models.Book.objects
    serializer_class = serializer.BookModel
    
    def get(self, request, *args, **kwargs):
        # 调用继承的ListModelMixin的list方法并返回
        return self.list(request, *args, **kwargs)

2.CreateModelMixin

Create a view extension class, provide a create(request, *args, **kwargs)method to quickly create a resource view, and successfully return a 201 status code.

If the serializer fails to verify the data sent by the front end, it returns a 400 error.

Source code:

Copyclass CreateModelMixin(object):
    """
    Create a model instance.
    """
    def create(self, request, *args, **kwargs):
        # 获取序列化器
        serializer = self.get_serializer(data=request.data)
        # 验证
        serializer.is_valid(raise_exception=True)
        # 保存
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def perform_create(self, serializer):
        serializer.save()

    def get_success_headers(self, data):
        try:
            return {
    
    'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {
    
    }

3. RetrieveModelMixin

The detail view extension class provides retrieve(request, *args, **kwargs)methods to quickly return an existing data object.

If it exists, return 200, otherwise return 404.

Source code:

Copyclass RetrieveModelMixin(object):
    """
    Retrieve a model instance.
    """
    def retrieve(self, request, *args, **kwargs):
        # 获取对象,会检查对象的权限
        instance = self.get_object()
        # 序列化
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

For example:

Copyclass BookDetailView(RetrieveModelMixin, GenericAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer

    def get(self, request, pk):
        return self.retrieve(request)

4.UpdateModelMixin

The update view extension class provides update(request, *args, **kwargs)methods to quickly update an existing data object.

At the same time, it also provides partial_update(request, *args, **kwargs)methods to implement partial updates.

Successfully returns 200. When the serializer fails to verify the data, it returns 400 error.

Source code:

Copyclass UpdateModelMixin(object):
    """
    Update a model instance.
    """
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {
    
    }

        return Response(serializer.data)

    def perform_update(self, serializer):
        serializer.save()

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)

5.DestroyModelMixin

Delete the view extension class and provide destroy(request, *args, **kwargs)methods to quickly delete an existing data object.

Return 204 if successful, and return 404 if it does not exist

Source code:

Copyclass DestroyModelMixin(object):
    """
    Destroy a model instance.
    """
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        instance.delete()

But this still has limitations, we still have to write two view classes, configure two routes

class Book(ListModelMixin, CreateModelMixin, GenericAPIView):
    queryset = models.Book.objects
    serializer_class = serializer.BookModel
    
    def get(self, request, *args, **kwargs):
        # 调用继承的ListModelMixin的list方法并返回
        return self.list(request, *args, **kwargs)
    
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)


class BookInfo(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericAPIView):
    queryset = models.Book.objects
    serializer_class = serializer.BookModel
    
    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)
    
    def patch(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)
    
    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

Is there a better way?

some!

Four, sub-category view (9)

1.CreateAPIView

Provide post method

Inherited from: GenericAPIView, CreateModelMixin

2.ListAPIView

Provide get method

Inherited from: GenericAPIView, ListModelMixin

3.RetrieveAPIView

Provide get method

Inherited from: GenericAPIView, RetrieveModelMixin

4.DestoryAPIView

Provide delete method

Inherited from: GenericAPIView, DestoryModelMixin

5.UpdateAPIView

Provide put and patch methods

Inherited from: GenericAPIView, UpdateModelMixin

6.RetrieveUpdateAPIView

Provide get, put, patch methods

Inherited from: GenericAPIView, RetrieveModelMixin, UpdateModelMixin

7.RetrieveUpdateDestoryAPIView

Provide get, put, patch, delete methods

Inherited from: GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestoryModelMixin

8. ListCreateAPIView: inherited

Get all, post method is added

Inherited from: ListModelMixin, CreateModelMixin, GenericAPIVie

9.RetrieveDestroyAPIView

There is a get method to get one, the delete method to delete

Inherited from: RetrieveModelMixin, DestroyModelMixin, GenericAPIView

Instructions

class Book(ListCreateAPIView, RetrieveDestroyAPIView, ):
    # 根据多继承python3的广度优先,他会从左到右依次匹配相关的方法,进而执行
    queryset = models.Book.objects
    serializer_class = serializer.BookModel

One thing to note is that there is no conflict between single-record query and multi-record query, because they use different interfaces!

So is there a way to not even write an excuse?

Five, view set

Guess you like

Origin blog.csdn.net/A1L__/article/details/109541009