Django REST framework 是用于构建Web API 的强大而灵活的工具包。本质上DRF是django的一个app(startproject)

   DRF中文文档:http://www.sinodocs.cn/

   安装:安装在想用的Python解释器下,例如:在终端cd到/python/lib/site-packages,然后执行 pip install djangorestframework

DRF的一些组件:

     1 APIView (所有的功能都是基于APIView的)*****
     2 解析器组件 *****
     3 序列化组件 *****

     4 视图组件

     5 认证组件 *****
     6 权限组件 *****
     7 频率组件
     8 url注册器组件
     9 响应器组件
     10 分页器组件

     11 filter:过滤、查找、排序

1.APIView

views.py(导入APIView模块,继承APIView)

from rest_framework.views import APIView
class BookView(APIView):
    def get(self, request):
        pass
    def post(self, request):
        pass
    

                
urls.py(没变化)

from django.urls import path, include, re_path
from classbasedview import views

urlpatterns = [
        re_path('login/$', views.LoginView.as_view()),
    ]
APIView的使用
1. 启动django:Python manage.py runserver 127.0.0.1:8000
2. 加载settings:
    2.1 加载models.py
    2.2 加载views.py
    2.3 加载urls.py
            2.3.1 re_path('BookView/$', views.BookView.as_view()), 开始执行as_view()方法
            2.3.2 urls.py加载完毕,url和视图函数之间的绑定关系已经建立好了
3. 等待用户请求
4. 接收到用户请求:127.0.0.0:8000/books/
5. 开始查找url和视图函数之间的绑定关系,根据用户请求的url找到对应的视图函数
6. 开始执行视图函数view(request)
7. 开始执行self.dispatch()
8. 将view函数的返回结果返回给客户端浏览器
APIView执行流程
                class View:
                    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

                    def __init__(self, **kwargs):

                        for key, value in kwargs.items():
                            setattr(self, key, value)

                    @classonlymethod
                    def as_view(cls, **initkwargs):
                        def view(request, *args, **kwargs):
                            # 实例化一个对象,BookView的实例对象
                            self = cls(**initkwargs)
                            # self表示BookView的实例化对象
                            # 把原始的request请求对象赋值给self.request
                            self.request = request
                            self.args = args
                            self.kwargs = kwargs
                            # view函数的返回结果就是self.dispatch()
                            return self.dispatch(request, *args, **kwargs)
                        # 此时的cls是BookView
                        view.view_class = cls
                        view.view_initkwargs = initkwargs

                        return view

                class APIView(View):
                    @classmethod
                    def as_view(cls, **initkwargs):
                        # cls是BookView

                        view = super(APIView, cls).as_view(**initkwargs) # View:view
                        view.cls = cls
                        view.initkwargs = initkwargs

                        # 返回一个view函数
                        return csrf_exempt(view)
                    
                    def dispatch(self, request, *args, **kwargs):
                        try:
                            
                            if request.method.lower() in self.http_method_names:
                                handler = getattr(self,request.method.lower(),
                                                  self.http_method_not_allowed)
                            else:
                                handler = self.http_method_not_allowed

                            response = handler(request, *args, **kwargs)

                        except Exception as exc:
                            response = self.handle_exception(exc)

                        return self.response

                class BookView(APIView):
                    def get(self, request):
                        pass
                        
                    def post(self, request):
                        pass

                1. 启动django:Python manage.py runserver 127.0.0.1:8000
                2. 加载settings:
                    2.1 加载models.py
                    2.2 加载views.py
                    2.3 加载urls.py
                        2.3.1 re_path('BookView/$', views.BookView.as_view()), 开始执行as_view()方法
                        2.3.2 urls.py加载完毕,url和视图函数之间的绑定关系已经建立好了
                3. 等待用户请求
                4. 接收到用户请求:127.0.0.0:8000/books/
                5. 开始查找url和视图函数之间的绑定关系,根据用户请求的url找到对应的视图函数
                6. 开始执行视图函数view(request)
                7. 开始执行self.dispatch()
                8. 将view函数的返回结果返回给客户端浏览器
APIView 源码剖析

 

2.解析器组件

views.py(导入并继承APIView,使用解析后的数据request.data)

from rest_framework.views import APIView
class BookView(APIView):
    def get(self, request):
        pass
    def post(self, request):
        origin_data = request.data
        ...
        return HttpResponse({})

                    
urls.py(无变化)

from django.urls import path, include, re_path
from classbasedview import views

urlpatterns = [
        re_path('login/$', views.LoginView.as_view()),
    ]
解析器组件的使用
class LoginView(APIView):
    def get(self, request):
            pass
        
    def post(self, request):
        request.data  # 新的request对象 @property
        return


class APIView(View):
    @classmethod
    def as_view(cls, **initkwargs):
        pass
        super(APIView, cls).as_view(**initkwargs)
        
    def initialize_request(self, request, *args, **kwargs):
    
        from rest_framework.request import Request

        return Request(
            request,  # 原生request对象
            parsers=self.get_parsers(), #
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
            
    def dispatch(self):
        pass
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        
    def get_parsers(self):
    
        return [parser() for parser in self.parser_classes]
    
    
1. views.LoginView.as_view()
2. LoginView里面没有as_view方法,到父类APIView去找
3. 执行View里面的as_view()方法,返回view函数
     def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            return self.dispatch(request, *args, **kwargs)
4. url和视图函数之间的绑定关系建立完毕  { "login": view},等待用户请求
5. 接收到用户请求:login,到建立好的绑定关系里面执行对应的视图函数:view(request)
6. 视图函数的执行结果是什么就返回给用户什么:self.dispatch(), self.dispatch()的执行结果是什么,就返回给用户什么
7. 此时的self代表的是LoginView的实例化对象
8. 开始找dispatch方法,self里面没有,LoginView里面也没有,在APIView里面有
9. 开始执行APIView里面的dispatch
10. 最后找到http方法(GET,POST,PUT,DELETE),根据请求类型查找(request.method.lower())
11. 开始执行找到的方法(GET),self.get(), self此时代表LoginView的实例化对象
    11.1 假设接收到的是POST请求, 执行request.data
    11.2 根据分析,所有的解析工作都在request.data里面实现,且data是一个方法(被@property装饰后的)
    11.2 开始执行request.data
        @property
        def data(self):
            if not _hasattr(self, '_full_data'):
                self._load_data_and_files()
            return self._full_data
    11.3 执行self._load_data_and_files
    11.4 执行self._data, self._files = self._parse()
    11.5 parser = self.negotiator.select_parser(self, self.parsers)
        11.5.1 开始找self.parsers
        11.5.2 self.get_parses()
                [ parse() for parse in self.parser_classes ]
            11.5.2.1 parser_classes = api_settings.DEFAULT_PARSER_CLASSES
            11.5.2.2 from rest_framework import api_settings
            11.5.2.3 api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)
                    
            11.5.2.4 class APISettings():pass
            11.5.2.5 找不到DEFAULT_PARSER_CLASSES,__getattr__
                'DEFAULT_PARSER_CLASSES': (
                'rest_framework.parsers.JSONParser',
                'rest_framework.parsers.FormParser',
                'rest_framework.parsers.MultiPartParser'
            ),
            11.5.2.6 首先找程序的settings
            11.5.2.7 然后找rest_framework的settings
        11.5.3 
        
    11.6 self._data就是我们想要的数据
    11.7 DRF将self._data = data
    11.8 request.data

12. 在LoginView里面找到了对应的方法,执行该方法,最后返回给用户

    - DRF的所有功能都是在as_view()和dispatch里面重写的
    - 而解析器组件在dispatch方法里面重写了,具体是在重新封装的Request对象里面


class ParseJson():
    pass

def ParseForm():
    def parse(self, request):
        """csrfmiddlewaretoken=ef2GXp26EM0VZfpBxoQaAKcYtGqoc3wTQqtv9RwqCsa2dE7vJ02qf74aSycxMm0Z&user=&password="""
        data = request.body.decode('utf-8')
        data.split('&')
        return data
        
        
def select_parse(request, ParseJson, ParseForm):
    return
解析器组件的源码流程
                1. 启动django:Python manage.py runserver 127.0.0.1:8000
                2. 加载settings:
                    2.1 加载models.py
                    2.2 加载views.py
                    2.3 加载urls.py
                        2.3.1 re_path('BookView/$', views.BookView.as_view()), 开始执行as_view()方法
                        2.3.2 urls.py加载完毕,url和视图函数之间的绑定关系已经建立好了
                3. 等待用户请求
                4. 接收到用户请求:127.0.0.0:8000/books/ POST
                5. 开始self.post()
                    5.1 request.data触发解析操作
                    5.2 获取返回值
                6. 将view函数的返回结果返回给客户端浏览器
        
                class View:
                    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

                    def __init__(self, **kwargs):

                        for key, value in kwargs.items():
                            setattr(self, key, value)

                    @classonlymethod
                    def as_view(cls, **initkwargs):
                        def view(request, *args, **kwargs):
                            # 实例化一个对象,BookView的实例对象
                            self = cls(**initkwargs)
                            # self表示BookView的实例化对象
                            # 把原始的request请求对象赋值给self.request
                            self.request = request
                            self.args = args
                            self.kwargs = kwargs
                            # view函数的返回结果就是self.dispatch()
                            return self.dispatch(request, *args, **kwargs)
                        # 此时的cls是BookView
                        view.view_class = cls
                        view.view_initkwargs = initkwargs

                        return view
                        
                class Request(object):
                    def __init__(self, request, parsers=None, authenticators=None,
                                 negotiator=None, parser_context=None):
                        self._request = request
                        self.parsers = parsers or ()  # self.get_parsers()的执行结果
                        
                    # 触发解析操作
                    @property
                    def data(self):
                        if not _hasattr(self, '_full_data'):
                            self._load_data_and_files()
                        return self._full_data
                        
                    def _load_data_and_files(self):
                        """
                        Parses the request content into `self.data`.
                        """
                        if not _hasattr(self, '_data'):
                            # 开始执行self._parse()
                            self._data, self._files = self._parse()  # parsed_data
                            if self._files:
                                self._full_data = self._data.copy()
                                self._full_data.update(self._files)
                            else:
                                self._full_data = self._data

                            # if a form media type, copy data & files refs to the underlying
                            # http request so that closable objects are handled appropriately.
                            if is_form_media_type(self.content_type):
                                self._request._post = self.POST
                                self._request._files = self.FILES
                                
                    def _parse(self):
                        """
                        Parse the request content, returning a two-tuple of (data, files)

                        May raise an `UnsupportedMediaType`, or `ParseError` exception.
                        """
                        media_type = self.content_type

                        parser = self.negotiator.select_parser(self, self.parsers)

                        if not parser:
                            raise exceptions.UnsupportedMediaType(media_type)

                        try:
                            parsed = parser.parse(stream, media_type, self.parser_context)
                        except Exception:
                            # If we get an exception during parsing, fill in empty data and
                            # re-raise.  Ensures we don't simply repeat the error when
                            # attempting to render the browsable renderer response, or when
                            # logging the request or similar.
                            self._data = QueryDict('', encoding=self._request._encoding)
                            self._files = MultiValueDict()
                            self._full_data = self._data
                            raise

                        # Parser classes may return the raw data, or a
                        # DataAndFiles object.  Unpack the result as required.
                        try:
                            return (parsed.data, parsed.files)
                        except AttributeError:
                            empty_files = MultiValueDict()
                            return (parsed, empty_files)
                                

                class APIView(View):
                    from rest_framework.settings import api_settings

                    parser_classes = api_settings.DEFAULT_PARSER_CLASSES
                    
                    @classmethod
                    def as_view(cls, **initkwargs):
                        # cls是BookView

                        view = super(APIView, cls).as_view(**initkwargs) # View:view
                        view.cls = cls
                        view.initkwargs = initkwargs

                        # 返回一个view函数
                        return csrf_exempt(view)
                    
                    def initialize_request(self, request, *args, **kwargs):
                        from rest_framework.request import Request

                        return Request(
                            request,
                            parsers=self.get_parsers(),
                        )
                        
                    def get_parsers(self):
                        # [<class 'rest_framework.parsers.JSONParser'>, 
                        # <class 'rest_framework.parsers.FormParser'>, 
                        # <class 'rest_framework.parsers.MultiPartParser'>]
                        return [parser() for parser in self.parser_classes]
                    
                    def dispatch(self, request, *args, **kwargs):
                        # 初始化request,将原来的request对象传递给初始化函数
                        request = self.initialize_request(request, *args, **kwargs)
                        self.request = request
                        try:
                            if request.method.lower() in self.http_method_names:
                                handler = getattr(self,request.method.lower(),
                                                  self.http_method_not_allowed)
                            else:
                                handler = self.http_method_not_allowed

                            response = handler(request, *args, **kwargs)

                        except Exception as exc:
                            response = self.handle_exception(exc)

                        return self.response

                class BookView(APIView):
                    def get(self, request):
                        pass
                        
                    def post(self, request):
                        parsed_data = request.data
DRF解析器源码剖析

 

3.序列化组件(serializers)的使用及接口设计

                GET       127.0.0.1:8000/books/     # 获取所有数据,返回值: [{}, {}]
                GET       127.0.0.1:8000/books/{id} # 获取一条数据,返回值:{}
                POST      127.0.0.1:8000/books/     # 新增一条数据,返回值:{}
                PUT       127.0.0.1:8000/books/{id} # 修改数据,返回值:{}
                DELETE    127.0.0.1:8000/books/{id} # 删除数据,返回空
接口类型 示例
             get接口使用序列化
                    - 导入模块:from rest_framework import serializers
                    - 建立一个序列化类
                        class BookSerializer(serializers.Serializer):
                            # 字段可以自定义
                            nid = serializers.CharField(max_length=10)
                            title = serializers.CharField(max_length=20)
                            publish_name = serializers.CharField(read_only=True, source="publish.name")
                            authors_list = serializers.SerializerMethodField()
                            
                            def get_authors_list(self, book_obj):
                                pass
                    - 获取queryset
                        origin_data = Book.objects.all()
                    - 开始序列化
                        serialized_data = BookSerializer(origin_data, many=True)
                    - 获取序列化后的数据,返回给客户端
                        return Response(serialized_data.data)
通过序列化组件进行get接口设计 流程
models.py


from django.db import models

class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    def __str__(self):
        return self.name


class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()

    def __str__(self):
        return self.name


class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    # 外键字段
    publish = models.ForeignKey(to="Publish", related_name="book", related_query_name="book_query", on_delete=models.CASCADE)
    # 多对多字段
    authors = models.ManyToManyField(to="Author")









urls.py


from django.urls import re_path
from serializer import views

urlpatterns = [
    re_path(r'books/$', views.BookView.as_view()),
]








app_serializers.py


from rest_framework import serializers

from .models import Book

# 第二步, 创建一个序列化类,字段类型不一定要跟models的字段一致
class BookSerializer(serializers.Serializer):
    # nid = serializers.CharField(max_length=32)
    title = serializers.CharField(max_length=128)
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    publish = serializers.CharField()
    # 外键字段, 显示__str__方法的返回值
    publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name')
    publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city')
    # authors = serializers.CharField(max_length=32) # book_obj.authors.all()

    # 多对多字段需要自己手动获取数据,SerializerMethodField()
    authors_list = serializers.SerializerMethodField()

    def get_authors_list(self, book_obj):
        author_list = list()

        for author in book_obj.authors.all():
            author_list.append(author.name)

        return author_list









views.py


# 第一步,导入模块
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import (
    Book,
    Publish,
    Author,
)
from .app_serializers import BookSerializer

class BookView(APIView):
    def get(self, request):
        # 第三步,获取queryset
        origin_data = Book.objects.all()

        # 第四步,开始序列化
        serialized_data = BookSerializer(origin_data, many=True)

        return Response(serialized_data.data)
通过序列化组件进行get接口设计 示例

 

post接口 使用序列化 流程
                    - 导入模块:from rest_framework import serializers
                    - 建立一个序列化类
                                              问题:
                           1. serializers.Serializer无法插入数据,只能自己实现create
                           2. 字段太多,不能自动序列化
                                               所以使用serializers.ModelSerializer

                        class BookSerializer(serializers.ModelSerializer):
                            字段可以自定义
                            
                    - 获取客户端请求数据
                    - 开始序列化
                        serialized_data = BookSerializer(origin_data, many=True)
                    - 写入数据库
                    - 获取序列化后的数据,返回给客户端
                        return Response(serialized_data.data)    
通过序列化组件进行post接口设计 流程
models.py


from django.db import models

class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    def __str__(self):
        return self.name


class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()

    def __str__(self):
        return self.name


class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    # 外键字段
    publish = models.ForeignKey(to="Publish", related_name="book", related_query_name="book_query", on_delete=models.CASCADE)
    # 多对多字段
    authors = models.ManyToManyField(to="Author")












urls.py


from django.urls import re_path
from serializer import views

urlpatterns = [
    re_path(r'books/$', views.BookView.as_view()),
]











app_serializers.py

# 导入模块
from rest_framework import serializers

from .models import Book

"""
# 创建一个序列化类,字段类型不一定要跟models的字段一致
class BookSerializer(serializers.Serializer):
    # nid = serializers.CharField(max_length=32)
    title = serializers.CharField(max_length=128)
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    publish = serializers.CharField()
    # 外键字段, 显示__str__方法的返回值
    publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name')
    publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city')
    # authors = serializers.CharField(max_length=32) # book_obj.authors.all()

    # 多对多字段需要自己手动获取数据,SerializerMethodField()
    authors_list = serializers.SerializerMethodField()

    def get_authors_list(self, book_obj):
        author_list = list()

        for author in book_obj.authors.all():
            author_list.append(author.name)

        return author_list

    def create(self, validated_data):
        # {'title': 'Python666', 'price': Decimal('66.00'), 'publish': '2'}
        validated_data['publish_id'] = validated_data.pop('publish')
        book = Book.objects.create(**validated_data)

        return book
"""

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book

        fields = ('title',
                  'price',
                  'publish',
                  'authors',
                  'author_list',
                  'publish_name',
                  'publish_city'
                  )
        extra_kwargs = {
            'publish': {'write_only': True},
            'authors': {'write_only': True}
        }

    publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name')
    publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city')

    author_list = serializers.SerializerMethodField()

    def get_author_list(self, book_obj):
        # 拿到queryset开始循环 [{}, {}, {}, {}]
        authors = list()

        for author in book_obj.authors.all():
            authors.append(author.name)

        return authors











views.py


from rest_framework.views import APIView
from rest_framework.response import Response
from .models import (
    Book,
    Publish,
    Author,
)
from .app_serializers import BookSerializer

class BookView(APIView):
    def post(self, request):

        verified_data = BookSerializer(data=request.data)

        if verified_data.is_valid():
            book = verified_data.save()
            authors = Author.objects.filter(nid__in=request.data['authors'])
            book.authors.add(*authors)
            return Response(verified_data.data)
        else:
            return Response(verified_data.errors)
通过序列化组件进行post接口设计 示例

 

            - get单条数据接口设计
                1. 定义url
                2. 获取数据对象
                3. 开始序列化:serialized_data = BookSerializer(book_obj, many=False)
                4. 返回数据:serialized_data.data
            - delete
            - put
                1. 定义url
                2. 获取数据对象
                      book_obj = Book.objects.get(pk=1)
                3. 开始序列化(验证数据,save())
                      verified_data = BookSerializer(instance=book_obj, many=False)
                4. 验证成功写入数据库,验证失败返回错误
                      verified_data.is_valid()
通过序列化组件进行get,update,put单条数据接口设计 流程
models.py(同上)





app_serializers.py(同上)





urls.py


from django.urls import re_path
from serializer import views

urlpatterns = [
    re_path(r'books/(?P<pk>\d+)/$', views.BookFilterView.as_view()),

]








views.py


from rest_framework.views import APIView
from rest_framework.response import Response
from .models import (
    Book,
    Publish,
    Author,
)
from .app_serializers import BookSerializer

class BookFilterView(APIView):
    def get(self, request, nid):
        book_obj = Book.objects.get(pk=nid)

        serialized_data = BookSerializer(book_obj, many=False)

        return Response(serialized_data.data)

    def put(self, request, nid):
        book_obj = Book.objects.get(pk=nid)

        verified_data = BookSerializer(data=request.data, instance=book_obj)

        if verified_data.is_valid():
            verified_data.save()
            return Response(verified_data.data)
        else:
            return Response(verified_data.errors)

    def delete(self, request, nid):
        book_obj = Book.objects.get(pk=nid).delete()

        return Response()
通过序列化组件进行get,update,put单条数据接口设计 示例

 

models.py(同上)
app_serializers.py(同上)




urls.py

from django.urls import re_path
from serializer import views

urlpatterns = [
    re_path(r'books/$', views.BookView.as_view()),
    re_path(r'books/(?P<pk>\d+)/$', views.BookFilterView.as_view()),

]







views.py


from rest_framework.mixins import (
    ListModelMixin,
    CreateModelMixin,
    DestroyModelMixin,
    UpdateModelMixin,
    RetrieveModelMixin
)
from rest_framework.generics import GenericAPIView

from .models import (
    Book,
    Publish,
    Author,
)
from .app_serializers import BookSerializer


class BookView(ListModelMixin, CreateModelMixin, GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)


class BookFilterView(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, *args, **kwargs):
        # print(self.kwargs) {'pk': '1'}
        return self.retrieve(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)
通过序列化组件进行get,post,单条数据get,put,delete 接口设计(使用视图组件的mixin进行接口逻辑优化) 示例
models.py(同上)
app_serializers.py(同上)







urls.py

from django.urls import re_path
from serializer import views

urlpatterns = [
    re_path(r'books/$', views.BookView.as_view()),
    re_path(r'books/(?P<pk>\d+)/$', views.BookFilterView.as_view()),
]








views.py

from rest_framework import generics

from .models import (
    Book,
    Publish,
    Author,
)
from .app_serializers import BookSerializer

class BookView(generics.ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer


class BookFilterView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
通过序列化组件进行get,post,单条数据get,put,delete 接口设计(使用视图组件的view进行接口逻辑优化) 示例
models.py(同上)
app_serializers.py(同上)





urls.py

from django.urls import re_path
from serializer import views

urlpatterns = [
    re_path(r'books/$', views.BookView.as_view({
        'get': 'list',
        'post': 'create'
    })),
    re_path(r'books/(?P<pk>\d+)/$', views.BookView.as_view({
        'get': 'retrieve',
        'put': 'update',
        'delete': 'destroy'
    }))
]







views.py

from rest_framework.viewsets import ModelViewSet
from .models import (
    Book,
    Publish,
    Author,
)
from .app_serializers import BookSerializer

class BookView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
通过序列化组件进行get,post,单条数据get,put,delete 接口设计(使用视图组件的viewset进行接口逻辑优化) 示例

 

4.视图组件(mixin,genericview,viewset)

  视图组件是用来优化接口逻辑的

(1) 使用视图组件的mixin进行接口逻辑优化

            - 导入mixin
                from rest_framework.mixinx import (
                    ListModelMix,
                    CreateModelMixin,
                    DestroyModelMixin,
                    UpdateModelMixin,
                    RetrieveModelMixin
                )
                from rest_framework.generics import GenericAPIView

            - 定义序列化类
            Class BookSerializer(serializers.ModelSerializer):
                  class Meta:
                      Book
                      fields = ()
                      extra_kwargs = {"field_name": {"write_only": True}}
            
            - 导入序列化类
            from .app_serializers import BookSerializer
                
            - 定义视图类
            class BookView(ListModelMix, CreateModelMixin, GenericAPIView):
                # queryset和serializer_class是固定的写法
                queryset = Book.objects.all()
                serializer_class = BookSerializer
              
                def get():
                    return self.list()
                
                def post():
                    return self.create()
                    
            class BookFilterView(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView):
                queryset = Book.objects.all()
                serializer_class = BookSerializer
                
                def get():
                    return self.retrieve()
                    
                def delete():
                    return self.destroy()
                    
                def put():
                    return self.update()
                  
            注意:单条数据操作的url是这样的:re_path(r'books/(?P<pk>\d+)/$, views.BookFilterView.as_view())
使用视图组件的mixin进行接口逻辑优化 流程
models.py(同上)
app_serializers.py(同上)




urls.py

from django.urls import re_path
from serializer import views

urlpatterns = [
    re_path(r'books/$', views.BookView.as_view()),
    re_path(r'books/(?P<pk>\d+)/$', views.BookFilterView.as_view()),

]







views.py


from rest_framework.mixins import (
    ListModelMixin,
    CreateModelMixin,
    DestroyModelMixin,
    UpdateModelMixin,
    RetrieveModelMixin
)
from rest_framework.generics import GenericAPIView

from .models import (
    Book,
    Publish,
    Author,
)
from .app_serializers import BookSerializer


class BookView(ListModelMixin, CreateModelMixin, GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)


class BookFilterView(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, *args, **kwargs):
        # print(self.kwargs) {'pk': '1'}
        return self.retrieve(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)
使用视图组件的mixin进行接口逻辑优化 示例

 

(2) 使用视图组件的view进行接口逻辑优化

            - 导入模块
                from rest_framework import generics
                
            - 写视图类
                class BookView(generics.ListCreateAPIView)
                    queryset = Book.objects.all()
                    serializer_class = BookSerializer
                    
                class BookFilterView(generics.RetrieveUpdateDestroyAPIView):
                        queryset = Book.objects.all()
                    serializer_class = BookSerializer
使用视图组件的view进行接口逻辑优化 流程
models.py(同上)
app_serializers.py(同上)







urls.py

from django.urls import re_path
from serializer import views

urlpatterns = [
    re_path(r'books/$', views.BookView.as_view()),
    re_path(r'books/(?P<pk>\d+)/$', views.BookFilterView.as_view()),
]








views.py

from rest_framework import generics

from .models import (
    Book,
    Publish,
    Author,
)
from .app_serializers import BookSerializer

class BookView(generics.ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer


class BookFilterView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
使用视图组件的view进行接口逻辑优化 示例

 

(3) 使用视图组件的viewset进行接口逻辑优化

            - 导入模块
                from rest_framework.viewsets import ModelViewSet
            
            - 设计url
                re_path(r'books/$, views.BookView.as_view({
                    'get': 'list',
                    'post': 'create'
                })),
                re_path(r'books/(?P<pk>\d+)/$', views.BookView.as_view({
                    'get': 'retrieve',
                    'delete': 'destroy',
                    'put': 'update'
                }))
                
            - 设计视图类
                class BookView(ModelViewSet):
                    queryset = Book.objects.all()
                    serializer_class = BookSerializer
使用视图组件的viewset进行接口逻辑优化 流程
models.py(同上)
app_serializers.py(同上)





urls.py

from django.urls import re_path
from serializer import views

urlpatterns = [
    re_path(r'books/$', views.BookView.as_view({
        'get': 'list',
        'post': 'create'
    })),
    re_path(r'books/(?P<pk>\d+)/$', views.BookView.as_view({
        'get': 'retrieve',
        'put': 'update',
        'delete': 'destroy'
    }))
]







views.py

from rest_framework.viewsets import ModelViewSet
from .models import (
    Book,
    Publish,
    Author,
)
from .app_serializers import BookSerializer

class BookView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
使用视图组件的viewset进行接口逻辑优化 示例

 

from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response

from api.models import *
from api.utils.serializer import (
    CourseSerializer,
    CourseDetailSerializer,
    CourseCategorySerializer
)
from api.utils.auth import LoginAuth
from api.utils.filter import CourseFilter


class CourseView(ModelViewSet):
    authentication_classes = [LoginAuth]
    queryset = Course.objects.all()
    serializer_class = CourseSerializer

    filter_backends = [CourseFilter, ]

    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)

        serializer = self.get_serializer(queryset, many=True)

        return Response({"code": 0, "data": serializer.data})


class CourseDetailView(ModelViewSet):
    authentication_classes = [LoginAuth]
    queryset = CourseDetail.objects.all()
    serializer_class = CourseDetailSerializer


class CourseCategoryView(ModelViewSet):
    queryset = CourseCategory.objects.all()
    serializer_class = CourseCategorySerializer

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        serializer = self.get_serializer(queryset, many=True)
        return Response({"error_no": 0, "data": serializer.data})
使用ModelViewSet也可以自定义一些返回值 示例

 

5.认证组件(token) 

        1 使用方式介绍
            - 定义一个认证类
                class UserAuth():
                       def authenticate_header(self, request):
                        pass
                    
                    def authenticate(self, request):
                        pass
            
            - 在需要认证的数据接口里面指定认证类
                class BookView(ModelViewSet):
                    authentication_classes = [UserAuth]
                        queryset = Book.objects.all()
                    serializer_class = BookSerializer
        
        2 源码剖析
            - self.dispatch() # self BookView的实例化对象
            - self.initial() # self BookView的实例化对象
                - self.perform_authentication()  # self BookView的实例化对象
                    - request.user    # self Request的实例化对象
                        - self._authenticate() # self Request的实例化对象
                        self.user = xxx
认证组件使用方式及源码剖析
app_serializers.py(同上)





models.py(多加了一张UserToken表,与User表一对一)


from django.db import models

class User(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
    user_type_entry = (
        (1, 'Delux'),
        (2, 'SVIP'),
        (3, 'VVIP')
    )
    user_type = models.IntegerField(choices=user_type_entry)


class UserToken(models.Model):
    user = models.OneToOneField('User', on_delete=models.CASCADE)
    token = models.CharField(max_length=128)


class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    def __str__(self):
        return self.name


class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()

    def __str__(self):
        return self.name


class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    # 外键字段
    publish = models.ForeignKey(to="Publish", related_name="book", related_query_name="book_query", on_delete=models.CASCADE)
    # 多对多字段
    authors = models.ManyToManyField(to="Author")













urls.py


from django.urls import re_path
from serializer import views

urlpatterns = [
    re_path(r'books/$', views.BookView.as_view({
        'get': 'list',
        'post': 'create'
    })),
    re_path(r'books/(?P<pk>\d+)/$', views.BookView.as_view({
        'get': 'retrieve',
        'put': 'update',
        'delete': 'destroy'
    })),
    re_path(r'user/$', views.UserView.as_view()),
]









utils/get_token.py(获取随机token数值)


import uuid

def generate_token():
    random_str = str(uuid.uuid4()).replace('-', '')

    return random_str









authentication_classes.py(认证类)


from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import APIException

from .models import UserToken


# 第一步:定义认证类
class UserAuth(BaseAuthentication):

    # 所有的认证逻辑都在authenticate
    def authenticate(self, request):
        user_token = request.query_params.get("token")
        try:
            token = UserToken.objects.get(token=user_token)
            # 后面权限会用到以下两值(其实此处可返回任意两值)
            return token.user, token.token
        except Exception:
            raise APIException("没有认证")













views.py


from django.http import JsonResponse
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from .models import (
    Book,
    Publish,
    Author,
    User,
    UserToken
)
from .app_serializers import BookSerializer
from .utils import get_token
from .authentication_classes import UserAuth


class BookView(ModelViewSet):
    # 第二步:指定认证类
    authentication_classes = [UserAuth]
    queryset = Book.objects.all()
    serializer_class = BookSerializer


class UserView(APIView):
    def post(self, request):
        # 定义返回消息体
        response = dict()
        # 定义需要的用户信息
        fields = {"username", "password"}
        # 定义一个用户信息字典
        user_info = dict()

        if fields.issubset(set(request.data.keys())):
            # username = request.data.get("username")
            # password = request.data.get("password")
            for key in fields:
                user_info[key] = request.data[key]

        user_instance = User.objects.filter(**user_info).first()

        if user_instance is not None:
            access_token = get_token.generate_token()
            UserToken.objects.update_or_create(user=user_instance, defaults={
                'token': access_token
            })

            response["status_code"] = 200
            response["status_message"] = "登录成功"
            response["access_token"] = access_token
            response["user_role"] = user_instance.get_user_type_display()
        else:
            response["status_code"] = 201
            response["status_message"] = "登录失败,用户名或密码错误"

        return JsonResponse(response)
给指定的数据接口做认证 示例
全局认证需在settings.py中加上以下代码:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'serializer.authentication_classes.UserAuth',
    )
}






models.py(同上)


app_serializers.py(同上)


urls.py(同上)


utils/get_token.py(同上)


authentication_classes.py(同上)






views.py


from django.http import JsonResponse
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet

from .models import (
    Book,
    Publish,
    Author,
    User,
    UserToken
)
from .app_serializers import BookSerializer
from .utils import get_token
from .authentication_classes import UserAuth


class BookView(ModelViewSet):
    # 全局认证这里无需再指定认证类,因为在settings中已指定全局认证类
    # authentication_classes = [UserAuth]
    queryset = Book.objects.all()
    serializer_class = BookSerializer


class UserView(APIView):
    def post(self, request):
        # 定义返回消息体
        response = dict()
        # 定义需要的用户信息
        fields = {"username", "password"}
        # 定义一个用户信息字典
        user_info = dict()

        if fields.issubset(set(request.data.keys())):
            # username = request.data.get("username")
            # password = request.data.get("password")
            for key in fields:
                user_info[key] = request.data[key]

        user_instance = User.objects.filter(**user_info).first()

        if user_instance is not None:
            access_token = get_token.generate_token()
            UserToken.objects.update_or_create(user=user_instance, defaults={
                'token': access_token
            })

            response["status_code"] = 200
            response["status_message"] = "登录成功"
            response["access_token"] = access_token
            response["user_role"] = user_instance.get_user_type_display()
        else:
            response["status_code"] = 201
            response["status_message"] = "登录失败,用户名或密码错误"

        return JsonResponse(response)
全局认证 示例
  # 定义认证类
  class UserAuth(BaseAuthentication):

    # 所有的认证逻辑都在authenticate
    def authenticate(self, request):
      user_token = request.query_params.get("token")
      try:
        token = UserToken.objects.get(token=user_token)
        # 多个认证类时,只需在最后一个认证类中返回值即可
        return token.user, token.token
      except Exception:
        raise APIException("没有认证")

  # 指定认证类

  authentication_classes = [UserAuth,...]
注意:多个认证类时,只需在最后一个认证类中返回值即可

 

6.权限组件

          - 定义一个权限类
                class UserPerm():
                    def has_permission(self, request, view):
                        return None
            
          - 指定权限验证类
                class BookView(APIView):
                    authentication_classes = [UserAuth]
                    permission_classes = [UserPerm]

                    queryset = Book.objects.all()
                    serializer_class =  BookSerializer
权限组件 使用流程
models.py(同上)


app_serializers.py(同上)


urls.py(同上)


utils/get_token.py(获取随机token数值)(同上)


authentication_classes.py(认证类)(同上)








views.py


from django.http import JsonResponse
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet

from .models import (
    Book,
    Publish,
    Author,
    User,
    UserToken
)
from .app_serializers import BookSerializer
from .utils import get_token
from .authentication_classes import UserAuth

class UserPerm():
    message = "您没有查看该数据的权限!"

    def has_permission(self, request, view):
        if request.user.user_type == 3:
            return True
        return False


class BookView(ModelViewSet):
    # 指定认证类
    authentication_classes = [UserAuth]
    # 指定权限类
    permission_classes = [UserPerm]
    queryset = Book.objects.all()
    serializer_class = BookSerializer


class UserView(APIView):
    def post(self, request):
        # 定义返回消息体
        response = dict()
        # 定义需要的用户信息
        fields = {"username", "password"}
        # 定义一个用户信息字典
        user_info = dict()

        if fields.issubset(set(request.data.keys())):
            # username = request.data.get("username")
            # password = request.data.get("password")
            for key in fields:
                user_info[key] = request.data[key]

        user_instance = User.objects.filter(**user_info).first()

        if user_instance is not None:
            access_token = get_token.generate_token()
            UserToken.objects.update_or_create(user=user_instance, defaults={
                'token': access_token
            })

            response["status_code"] = 200
            response["status_message"] = "登录成功"
            response["access_token"] = access_token
            response["user_role"] = user_instance.get_user_type_display()
        else:
            response["status_code"] = 201
            response["status_message"] = "登录失败,用户名或密码错误"

        return JsonResponse(response)
权限组件 示例

 

7.频率组件

       -导入模块
          from rest_framework.throttling import SimpleRateThrottle

       -定义并继承SimpleRateThrottle
          class RateThrottle(SimpleRateThrottle):
              # 指定访问频率
              rate = '5/m'
     
              # 指定通过什么方式来区分用户
              def get_cache_key(self, request, view):
                   return self.get_ident(request)

       -指定频率类
          class BookView(APIView):
               throttle_classes = [RateThrottle]
局部 使用DRF的简单频率控制来控制用户访问频率
utils/app_throttles.py


from rest_framework.throttling import SimpleRateThrottle


class RateThrottle(SimpleRateThrottle):
    # 指定访问频率
    rate = "5/m"
 
    # 指定通过什么方式来区分用户
    def get_cache_key(self, request, view):
        return self.get_ident(request)









views.py


from rest_framework.viewsets import ModelViewSet
from .models import Book
from .app_serializers import BookSerializer
from .utils import app_throttles

class BookView(ModelViewSet):
    
    # authentication_classes = [UserAuth]
    # permission_classes = [UserPerm]

    # 指定频率类
    throttle_classes = [app_throttles.RateThrottle]
    queryset = Book.objects.all()
    serializer_class = BookSerializer
局部 使用DRF的简单频率控制来控制用户访问频率 示例

 

       -导入模块
          from rest_framework.throttling import SimpleRateThrottle

       -定义并继承SimpleRateThrottle
          class RateThrottle(SimpleRateThrottle):
              # 指定访问频率
              scope = 'visit_rate'
     
              # 指定通过什么方式来区分用户
              def get_cache_key(self, request, view):
                   return self.get_ident(request)    

       -在settings里指定频率类和访问频率
            REST_FRAMEWORK = {
                     "DEFAULT_THROTTLE_CLASSES": ('serializer.utils.app_throttles.RateThrottle',),
                     "DEFAULT_THROTTLE_RATES": {
                          "visit_rate": "5/m"
                     }
            }
全局 使用DRF的简单频率控制来控制用户访问频率
全局使用频率组件需要在settings里指定频率类和访问频率

REST_FRAMEWORK = {
         "DEFAULT_THROTTLE_CLASSES": ('serializer.utils.app_throttles.RateThrottle',),
         "DEFAULT_THROTTLE_RATES": {
                      "visit_rate": "5/m"
         }
}







utils/app_throttles.py


from rest_framework.throttling import SimpleRateThrottle


class RateThrottle(SimpleRateThrottle):
              # 指定访问频率
              scope = 'visit_rate'
     
              # 指定通过什么方式来区分用户
              def get_cache_key(self, request, view):
                   return self.get_ident(request)







views.py(不需要在views中指定频率类,因为在settings里已经配置了频率类和访问频率)
全局 使用DRF的简单频率控制来控制用户访问频率 示例

 

 8.url注册器组件

    -导入模块
        from django.urls import re_path, include
        from serializer import views
        from rest_framework import routers

    -生成一个注册器实例对象
        router = routers.DefaultRouter()

    -将需要自动生成url的接口注册
        router.register(r"books", views.BookView)

    -开始自动生成url
        urlpattern = [
             re_path('^', include(router.urls)),
        ]
url注册器组件的使用
urls.py


from django.urls import re_path, include
from serializer import views

from rest_framework import routers

router = routers.DefaultRouter()
router.register('books', views.BookView)

urlpatterns = [
    re_path('^', include(router.urls)),
]
url注册器组件的使用 示例

 

9.响应器组件

    -导入模块
        from rest_framework.views import APIView
        from rest_framework.renderers import JSONRender

    -指定返回类
        class BookView(APIView):
            render_classes = [JsonRender]
响应器组件的使用

 

10.分页器组件

 分页器组件的局部实现
    -导入模块
        from rest_framework.pagination import PageNumberPagination

    -自定义一个分页类并继承PageNumberPagination
        class MyPagination(PageNumberPagination):
            page_size = 2
            page_query_param = 'p'
            page_size_query_param = 'size'
            max_page_size = 5

    -实例化一个分页类对象
        paginater = MyPagination()

    -开始分页
        paged_books = paginater.paginate_queryset(books, request)

    -开始序列化
        serialized_books = BookSerializer(paged_books, many=True)

    -返回数据
        return Response(serialized_books.data)
局部 使用分页器组件
utils/app_paginates.py


from rest_framework.pagination import PageNumberPagination


class MyPagination(PageNumberPagination):
    page_size = 3
    page_query_param = 'page'
    page_size_query_param = 'size'
    max_page_size = 5










views.py


from rest_framework.viewsets import ModelViewSet

from .models import Book
from .app_serializers import BookSerializer
from .utils import app_paginates

class BookView(ModelViewSet):
    pagination_class = app_paginates.MyPagination
    queryset = Book.objects.all()
    serializer_class = BookSerializer
局部 使用分页器组件 示例

 

注:全局 使用分页器组件 需要在settings里配置如下代码:

REST_FRAMEWORK = {
    "PAGE_SIZE": 4
}




    -导入模块
        from rest_framework.pagination import PageNumberPagination

    -自定义一个分页类并继承PageNumberPagination
        class MyPagination(PageNumberPagination):
            # page_size = 2
            page_query_param = 'p'
            page_size_query_param = 'size'
            max_page_size = 5

    -实例化一个分页类对象
        paginater = MyPagination()

    -开始分页
        paged_books = paginater.paginate_queryset(books, request)

    -开始序列化
        serialized_books = BookSerializer(paged_books, many=True)

    -返回数据
        return Response(serialized_books.data)
全局 使用分页器组件
注意:在settings里配置如下代码:

REST_FRAMEWORK = {
      "PAGE_SIZE": 4
}





utils/app_paginates.py


from rest_framework.pagination import PageNumberPagination


class MyPagination(PageNumberPagination):
    page_query_param = 'page'
    page_size_query_param = 'size'
    max_page_size = 5










views.py


from rest_framework.viewsets import ModelViewSet
from .models import Book
from .app_serializers import BookSerializer
from .utils import app_paginates

class BookView(ModelViewSet):
    pagination_class = app_paginates.MyPagination
    queryset = Book.objects.all()
    serializer_class = BookSerializer
全局 使用分页器组件 示例

 

11.filter

字段过滤

utils/filter.py(自定义的过滤器)

from rest_framework.filters import BaseFilterBackend

class CourseFilter(BaseFilterBackend):
    """
    课程展示 过滤器
    """

    def filter_queryset(self, request, queryset, view):
        extra = {}
        # request.query_params等同于request.GET
        category_id = str(request.query_params.get("category_id"))

        # 如果分类ID不是数字或分类ID传输的为0
        if not category_id.isdigit() or category_id == "0":
            extra = extra
        else:
            extra.update({"course_category_id": category_id})
        return queryset.filter(**extra)











views/course.py

from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response

from api.models import Course
from api.utils.serializer import CourseSerializer
from api.utils.auth import LoginAuth
from api.utils.filter import CourseFilter


class CourseView(ModelViewSet):
    # authentication_classes = [LoginAuth]
    queryset = Course.objects.all()
    serializer_class = CourseSerializer

    filter_backends = [CourseFilter, ]

    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)

        serializer = self.get_serializer(queryset, many=True)

        return Response({"code": 0, "data": serializer.data})
filter过滤 示例

一般过滤可以重写get_queryset方法实现,这时候就可以去掉queryset这个属性了:

class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination

    # 覆写GenericAPIView下的该方法,以实现自己对query_set的返回加一些逻辑
    def get_queryset(self):
        # 获取url参数中传过来的"要查询的商品的价格阈值",如果没有传就设置为0
        price_min = self.request.query_params.get("price_min", 0)
        return Goods.objects.filter(shop_price__gt=price_min).order_by("shop_price")
View Code

现在就可以通过在url里指定参数price_min来实现对获取到的商品价格的过滤了。

注意在使用这种方法时,要在router.register里配置base_name,不然运行不了。

 

还可以使用django-filter,这个要把它注册为app,然后就能用了(因为这时候不需要重写get_queryset方法了,所以就需要把queryset这个属性拿回来)。然后可以自定义一个filters.py用来写自定义过滤规则的过滤器:

from django_filters import rest_framework as filters

from .models import Goods


class GoodsFilter(filters.FilterSet):
    """商品的过滤类"""
    # 区间查询,指定区间的最大最小值
    min_price = filters.NumberFilter(field_name="shop_price", lookup_expr='gte')
    max_price = filters.NumberFilter(field_name="shop_price", lookup_expr='lte')
    # 模糊查询,这里带i是忽略大小写
    name = filters.CharFilter(field_name="name", lookup_expr="icontains")

    class Meta:
        model = Goods
        fields = ['min_price', 'max_price', 'name']
View Code

然后在views.py的相关视图类里指定filter_class为这个自定义的过滤器类:

from .filters import GoodsFilter

class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination
    filter_backends = (DjangoFilterBackend,)
    queryset = Goods.objects.all()
    # filter_fields = ('name', 'shop_price')
    filter_class = GoodsFilter
View Code

在这个例子里配置完了之后,效果就是可以在url里指定min_price和max_price的值,来控制所返回的JSON中上shop_price值所在的区间,实现区间过滤;使用name实现模糊查询。

查找

要实现查找,只要在视图层配置filters.SearchFilter和search_fields=要查找的字段元组即可:

from rest_framework import filters

class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination
    filter_backends = (DjangoFilterBackend, filters.SearchFilter)
    queryset = Goods.objects.all()
    # filter_fields = ('name', 'shop_price')
    filter_class = GoodsFilter
    search_fields = ('name', 'goods_brief', 'goods_desc')
View Code

一些符号可以实现复杂的查找方式,比如以。。开头,全文搜索之类的。

排序

要实现排序,只要在视图层配置filters.OrderingFilter和ordering_fields=要排序的字段即可:

class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination
    filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
    queryset = Goods.objects.all()
    # filter_fields = ('name', 'shop_price')
    filter_class = GoodsFilter
    search_fields = ('name', 'goods_brief', 'goods_desc')
    ordering_fields = ('sold_num', 'add_time')
View Code

 

使用REST框架的一些原因:

  • Web浏览API对于开发人员来说是一个巨大的可用性。
  • 认证策略包括OAuth1a和OAuth2的包。
  • 支持ORM和非ORM数据源的序列化。
  • 如果你不需要更强大的功能,就可以使用常规的基于功能的视图。
  • 广泛的文档和良好的社区支持。
  • 包括Mozilla、Red Hat、Heroku和Eventbrite在内的国际知名公司使用和信任。

Funding

REST framework is a collaboratively(合作地) funded project(基金项目). If you use REST framework commercially we strongly encourage you to invest(投资) in its continued development(可持续发展) by signing up for a paid plan.(注册付费计划)

Every single sign-up helps us make REST framework long-term financially sustainable(财务上可持续发展)

Many thanks to all our wonderful sponsors(赞助商), and in particular to our premium backers(优质的支持者), RoverSentryStreamMachinalis, and Rollbar.

 

Requirements

REST framework requires the following:

  • Python (2.7, 3.2, 3.3, 3.4, 3.5, 3.6)
  • Django (1.10, 1.11, 2.0 alpha)

The following packages are optional:

以下软件包是可选的:

 

Installation

Install using pip, including any optional packages you want...

1
2
3
pip install djangorestframework
pip install markdown       # Markdown support for the browsable API.
pip install django-filter  # Filtering support

...or clone the project from github.

1
git clone git@github.com:encode/django-rest-framework.git

Add 'rest_framework' to your INSTALLED_APPS setting.(记得在setting文件里面添加rest_framework,当然,你还得先安装djangorestframework)

1
2
3
4
INSTALLED_APPS = (
    ...
    'rest_framework',
)

If you're intending to use the browsable API you'll probably also want to add REST framework's login and logout views. Add the following to your root urls.py file.

如果您打算使用可浏览的API,您可能还需要添加REST框架的登录和注销视图。将以下内容添加到您的根urls.py文件中。

1
2
3
4
urlpatterns = [
    ...
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]

Note that the URL path can be whatever you want, but you must include 'rest_framework.urls' with the 'rest_framework' namespace. You may leave out the namespace in Django 1.9+, and REST framework will set it for you.

请注意,URL路径可以是任何你想要的,但你必须包括'rest_framework.urls''rest_framework'命名空间。您可以在Django 1.9+中省略命名空间,REST框架将为您设置。

 

Quickstart

Can't wait to get started? The quickstart guide is the fastest way to get up and running, and building APIs with REST framework.

说了一堆,直接来个demo,快速上手,看看效果。官网请看:http://www.django-rest-framework.org/tutorial/quickstart/

 

首先肯定得先创建django程序啦,接着创建APP,这里我创建了一个quickstart的app。

Now sync your database for the first time:同步数据库

1
python manage.py migrate

创建超级用户用于登陆。We'll also create an initial user named admin with a password of password123. We'll authenticate as that user later in our example.

1
python manage.py createsuperuser

 

Serializers

首先我们要定义一些序列化程序。在quickstart这个APP下创建serializers文件,用于展示数据。

First up we're going to define some serializers. Let's create a new module named tutorial/quickstart/serializers.py that we'll use for our data representations.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from django.contrib.auth.models import User, Group
from rest_framework import serializers
 
 
class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('url''username''email''groups')
 
 
class GroupSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Group
        fields = ('url''name')

Notice that we're using hyperlinked relations in this case, with HyperlinkedModelSerializer. You can also use primary key and various other relationships, but hyperlinking is good RESTful design.

请注意,在这种情况下,我们正在使用超链接关系HyperlinkedModelSerializer。您还可以使用主键和各种其他关系,但超链接是好的RESTful设计。

 

Views

Right, we'd better write some views then. Open tutorial/quickstart/views.py and get typing. 写一些视图,查询数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from tutorial.quickstart.serializers import UserSerializer, GroupSerializer
 
 
class UserViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer
 
 
class GroupViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows groups to be viewed or edited.
    """
    queryset = Group.objects.all()
    serializer_class = GroupSerializer

Rather than write multiple views we're grouping together all the common behavior into classes called ViewSets.

We can easily break these down into individual views if we need to, but using viewsets keeps the view logic nicely organized as well as being very concise.

 

我们不是编写多个视图,而是将所有常见的行为组合到一个名为viewset的类中。

如果需要的话,我们可以很容易地将它们分解为单独的视图,但是使用viewset使视图逻辑组织得很好,并且非常简洁。

 

URLs

Okay, now let's wire up the API URLs. On to tutorial/urls.py...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from django.conf.urls import url, include
from rest_framework import routers
from tutorial.quickstart import views
<br>
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)
 
# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
    url(r'^', include(router.urls)),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]

Because we're using viewsets instead of views, we can automatically generate the URL conf for our API, by simply registering the viewsets with a router class.

我们可以通过简单地使用路由器类注册该视图来自动生成API的URL conf。

Again, if we need more control over the API URLs we can simply drop down to using regular class-based views, and writing the URL conf explicitly.

再次,如果我们需要对API URL的更多控制,我们可以简单地将其下拉到使用常规的基于类的视图,并明确地编写URL conf。

Finally, we're including default login and logout views for use with the browsable API. That's optional, but useful if your API requires authentication and you want to use the browsable API.

最后,我们将包括默认登录和注销视图,以便与可浏览的API一起使用。这是可选的,但如果您的API需要身份验证,并且您想要使用可浏览的API,那么这是非常有用的。

 

Settings

We'd also like to set a few global settings. We'd like to turn on pagination, and we want our API to only be accessible to admin users. The settings module will be in tutorial/settings.py

我们也想设置一些全局设置。我们想打开分页,我们希望我们的API只能由管理员使用

1
2
3
4
5
6
7
8
9
10
11
INSTALLED_APPS = (
    ...
    'rest_framework',
)
 
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAdminUser',
    ],
    'PAGE_SIZE'10
}

Okay, we're done.

 

效果图:

主界面,好像啥也没有……

用超级用户登陆后的界面。

有增删改查的功能。

 

快速了解REST framework组件

接下来了解下rest framework 的所有组件,并且得知它们是如何组合在一起的,这是非常值得去学习的。

  • 1 - Serialization 序列化
  • 2 - Requests & Responses 请求 & 响应
  • 3 - Class-based views 基于类的视图
  • 4 - Authentication & permissions 身份验证 & 权限
  • 5 - Relationships & hyperlinked APIs 
  • 6 - Viewsets & routers 视图和路由
  • 7 - Schemas & client libraries 模式和客户端库

Serialization 序列化

 这里不对普通的序列化作介绍。接下来使用 ModelSerializers model序列化让代码更少,更简洁。Django提供了form和modelform一样,REST框架包括了序列化器类和模型序列化器类。

例如 models 文件中有一个关于文章的表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Article(models.Model):
    """文章资讯"""
    title = models.CharField(max_length=255, unique=True, db_index=True, verbose_name="标题")
    source = models.ForeignKey("ArticleSource", verbose_name="来源")
    article_type_choices = ((0'资讯'), (1'视频'))
    article_type = models.SmallIntegerField(choices=article_type_choices, default=0)
    brief = models.TextField(max_length=512, verbose_name="摘要")
    head_img = models.CharField(max_length=255)
    content = models.TextField(verbose_name="文章正文")
    pub_date = models.DateTimeField(verbose_name="上架日期")
    offline_date = models.DateTimeField(verbose_name="下架日期")
    status_choices = ((0'在线'), (1'下线'))
    status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="状态")
    order = models.SmallIntegerField(default=0, verbose_name="权重", help_text="文章想置顶,可以把数字调大")
    comment_num = models.SmallIntegerField(default=0, verbose_name="评论数")
    agree_num = models.SmallIntegerField(default=0, verbose_name="点赞数")
    view_num = models.SmallIntegerField(default=0, verbose_name="观看数")
    collect_num = models.SmallIntegerField(default=0, verbose_name="收藏数")
 
    tags = models.ManyToManyField("Tags", blank=True, verbose_name="标签")
    date = models.DateTimeField(auto_now_add=True, verbose_name="创建日期")
 
    def __str__(self):
        return "%s-%s" % (self.source, self.title)

接下来,只需要写一个序列化器,便可以轻松对数据的进行获取,而且代码看起来特别简洁。

1
2
3
4
5
6
7
8
9
10
11
12
# 在 serilallzer.py 文件可以这样写
# 如果想使用哪个model进行序列化,照此类推即可
# fields 如果想要获取所有字段, 使用"__all__" 
# fields 如果只是想要获取一部分数据呢, 那么在 fields 中加入所序列化的model的字段即可
 
from rest_framework.serializers import ModelSerializer
 
 
class ArticleSerializer(ModelSerializer):
    class Meta:
        model = models.Article
        fields = ("id""title""article_type""content", ) or "__all__"
posted on 2019-11-10 09:59  始终不够啊  阅读(363)  评论(0编辑  收藏  举报