天天看点

Zhong__DRF笔记

时间:2021.02.22

环境:Python3.9

目的:使用DRF开发web应用常见的场景和用法知识点

说明:

作者:Zhong QQ交流群:121160124 欢迎加入!

settings.py

"""
Django settings for Django3_Test project.

Generated by 'django-admin startproject' using Django 3.0.7.

For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""
import datetime
import os
import sys
import time
import environ
from logging.handlers import BaseRotatingHandler, RotatingFileHandler, TimedRotatingFileHandler

from celery.schedules import crontab
from kombu import Queue
from configurations import Configuration  # pip install django-configurations
from configurations import importer
from django.conf import settings

importer.install()

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 导入apps路径
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))

# 配置从.env文件读取配置信息
env = environ.Env(DEBUG=(bool, True))  # set casting, default value

# 定义配置文件settings.py根目录ROOT_PATH和.env文件路径ENV_PATH
ROOT_PATH = environ.Path(__file__) - 1
ENV_PATH = str(ROOT_PATH.path('.env'))

"""调用此配置接口
import environ
from settings import ENV_PATH
env = environ.Env()
env.read_env(env_file=ENV_PATH)
"""

# 设置从.env文件读取配置信息
READ_DOT_ENV_FILE = env.bool("DJANGO_READ_DOT_ENV_FILE", default=True)
if READ_DOT_ENV_FILE:
    # reading .env file  OS environment variables take precedence over variables from .env
    environ.Env.read_env()

class BaseConfig(Configuration):

    # Quick-start development settings - unsuitable for production
    # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/

    # SECURITY WARNING: keep the secret key used in production secret!
    # Raises django's ImproperlyConfigured exception if SECRET_KEY not in os.environ
    SECRET_KEY = env('SECRET_KEY')
    # SECURITY WARNING: don't run with debug turned on in production!
    # False if not in os.environ
    DEBUG = env('DEBUG')

    ALLOWED_HOSTS = ["*"]

    # Application definition

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',

        'rest_framework',  # drf
        'django_filters',  # 过滤
        'corsheaders',
        'django_celery_results',
        'django_celery_beat',

        'users',
        'celery_test.apps.CeleryTestConfig',
        'drf.apps.DrfConfig',
    ]

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'corsheaders.middleware.CorsMiddleware',
        'django.middleware.common.CommonMiddleware',
        # 'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',

        "middlewares.time_consuming.TimeConsuming",  # 执行时间中间件

    ]

    ROOT_URLCONF = 'Django3_Test.urls'

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')],
            'APP_DIRS': True,
            'OPTIONS': {
                # ... some options here ...
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]


    WSGI_APPLICATION = 'Django3_Test.wsgi.application'
    # ASGI_APPLICATION = 'Django3_Test.asgi.application'

    # Database
    # https://docs.djangoproject.com/en/3.0/ref/settings/#databases

    # 配置数据库连接
    DATABASES = {
        'default': env.db()
    }

  

    # Password validation
    # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators

    AUTH_PASSWORD_VALIDATORS = [
        {
            'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
        },
    ]

    # Internationalization
    # https://docs.djangoproject.com/en/3.0/topics/i18n/

    LANGUAGE_CODE = 'zh-hans'
    TIME_ZONE = 'Asia/Shanghai'
    USE_I18N = True  # 语言  如: admin管理站点中文显示
    USE_L10N = True  # 数据和时间格式  友好的显示格式
    USE_TZ = False  # 启用时区  数据库存储以及前台显示都是UTC的时间  不启用则为本地时间



    # Static files (CSS, JavaScript, Images)
    # https://docs.djangoproject.com/en/3.0/howto/static-files/

    LOGGING = {
        "version": 1,  # log level
        "disable_existing_loggers": False,
        # 定义日志格式
        "formatters": {  # log format
            "standard": {
                # "format日志格式": [asctime时间] [threadName线程名称] [levelname日志级别]                  [filename文件名称第几行]     [module模块和funcName方法名称] : 记录的具体日志
                "format": "[%(asctime)s] [%(threadName)s:%(thread)d] [%(name)s:%(levelname)s(%(lineno)d)] [%(filename)s:%(lineno)d] [%(module)s:%(funcName)s]:%(message)s"
            }
        },
        # 定义过滤
        "filters": {
            "require_debugEMAIL_BACKEND_true": {
                "()": "django.utils.log.RequireDebugTrue",
            }
        },
        # 定义处理日志的方式
        "handlers": {
            # 默认记录所有日志
            "default": {
                "level": "INFO",
                "class": "logging.handlers.RotatingFileHandler",
                "formatter": "standard",
                "filename": os.path.join(BASE_DIR, "logs/app_info.log"),  # log path and name
                # "maxBytes": 1024 * 1024 * 100,
                "backupCount": 5,
                "encoding": "utf8",  # file encoding
            },
            "console": {
                "level": "DEBUG",
                "class": "logging.StreamHandler",  # inherit  from logging.handle class
                "formatter": "standard",  # use standard format
            },
            "app_info": {
                "level": "INFO",
                "class": "logging.handlers.RotatingFileHandler",
                "formatter": "standard",
                "filename": os.path.join(BASE_DIR, "logs/app_info.log"),  # log path and name
                "maxBytes": 1024 * 1024 * 100,
                "backupCount": 5,
                "encoding": "utf8",  # file encoding
            },
        },
        # 配置使用哪些handlers来处理日志  自定义调用日志时可以logging.getLogger('django').info("详细的日志信息")使用
        "loggers": {
            "django.db.backends": {
                "handlers": ["console"],
                "level": "INFO",
                "propagate": False,
            },
            "django.security.DisallowedHost": {
                "handlers": ["app_info"],
                "level": "ERROR",
                "propagate": False,
            },
            "django": {
                "handlers": ["console", "default"],
                "level": "INFO",
                "propagate": False,  # 日志向上层传递 如log文件记录和控制台输出 默认1(True)
            },
            "application": {
                "handlers": ["app_info"],
                "level": "INFO",
                "propagate": False,  # 日志向上层传递 如log文件记录和控制台输出 默认1(True)
            },
            "database": {
                "handlers": [],
                "level": "INFO",
                "propagate": False,
            },
        }
    }

    # 执行python manage.py collectstatic生成rest_framework文件  在项目配置目录urls中添加  urlpatterns += staticfiles_urlpatterns()生效
    STATIC_URL = '/static/'
    STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]
    # STATIC_ROOT = os.path.join(BASE_DIR, 'static')  # 执行 python manage.py collectstatic 会用到

    # Any global settings for a REST framework API are kept in a single configuration dictionary named REST_FRAMEWORK.
    REST_FRAMEWORK = {
        # 默认认证类
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'rest_framework_simplejwt.authentication.JWTAuthentication',
            'rest_framework.authentication.SessionAuthentication',
            'rest_framework.authentication.BasicAuthentication',
        ],

        # 默认权限级别 AllowAny 允许所有的访问 一般设置为 IsAuthenticated 允许已认证用户
        'DEFAULT_PERMISSION_CLASSES': (
           # 'rest_framework.permissions.AllowAny',
           'rest_framework.permissions.IsAuthenticated',
           # 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
        ),

        # 过滤器 指定过滤、排序等
        'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend', 'rest_framework.filters.OrderingFilter'),

        # 全局分页类 每页10条数据
        # 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
        'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
        'PAGE_SIZE': 10,

        # 限流 可以对接口访问的频次进行限制,以减轻服务器压力。
        'DEFAULT_THROTTLE_CLASSES': (
            'rest_framework.throttling.AnonRateThrottle', # 限制所有匿名未认证用户,使用IP区分用户
            'rest_framework.throttling.UserRateThrottle', # 限制认证用户,使用User id 来区分
            'rest_framework.throttling.ScopedRateThrottle', # 限制用户对于每个视图的访问频次,使用ip或user id  可在视图中调用DEFAULT_THROTTLE_RATES中定义的属性
        ),
        # 可以使用second, minute, hour 或day来指明周期
        'DEFAULT_THROTTLE_RATES': {
            'anon': '20/day',
            'user': '1000/day',
            # 配合ScopedRateThrottle在视图使用
            'book_info_model_view_set': '10/day'
        },

        # coreapi接口文档的配置
        'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema'

    }

    SIMPLE_JWT = {
        'ACCESS_TOKEN_LIFETIME': datetime.timedelta(days=88),
        'REFRESH_TOKEN_LIFETIME': datetime.timedelta(days=30),
        'ROTATE_REFRESH_TOKENS': False,
        'BLACKLIST_AFTER_ROTATION': True,

        'ALGORITHM': 'HS256',
        'SIGNING_KEY': SECRET_KEY,
        'VERIFYING_KEY': None,
        'AUDIENCE': None,
        'ISSUER': None,

        'AUTH_HEADER_TYPES': ('Bearer',),
        'USER_ID_FIELD': 'id',
        'USER_ID_CLAIM': 'user_id',

        # 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
        # 'TOKEN_TYPE_CLAIM': 'token_type',

        'JTI_CLAIM': 'jti',

        'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
        'SLIDING_TOKEN_LIFETIME': datetime.timedelta(minutes=5),
        'SLIDING_TOKEN_REFRESH_LIFETIME': datetime.timedelta(days=1),
    }

    # AUTHENTICATION_BACKENDS = (
    # "django.contrib.auth.backends.ModelBackend",
    # )

    # CORS
    CORS_ORIGIN_ALLOW_ALL = True
    CORS_ALLOW_CREDENTIALS = True  # 允许携带cookie

    AUTH_USER_MODEL = 'users.UserInfo'

    SWAGGER_SETTINGS = {
        'LOGIN_URL': '/admin/login',
        'LOGOUT_URL': '/admin/logout',
        'PERSIST_AUTH': True,
        'REFETCH_SCHEMA_WITH_AUTH': True,
        'REFETCH_SCHEMA_ON_LOGOUT': True,

        'DEFAULT_INFO': 'DjangoDrfTest.urls.swagger_info',  # 这里注意,更改DjangoDrfTest

        'SECURITY_DEFINITIONS': {
            'Basic': {
                'type': 'basic'
            },
            'Bearer': {
                'type': 'apiKey',
                'name': 'authorization',
                'in': 'header'
            },
            'Query': {
                'type': 'apiKey',
                'name': 'auth',
                'in': 'query'
            }
        }
    }


class LocalConfig(BaseConfig):
    ALLOWED_HOSTS = ["*"]
    DEBUG = env.str("LocalConfig_DEBUG", True)
           

models.py

from django.db import models

# Create your models here.

#定义图书模型类BookInfo
class BookInfo(models.Model):
    booktitle = models.CharField(max_length=20, verbose_name='名称')
    bookpub_date = models.DateField(verbose_name='发布日期')
    bookread = models.IntegerField(default=0, verbose_name='阅读量')
    bookcomment = models.IntegerField(default=0, verbose_name='评论量')
    is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')

    class Meta:
        db_table = 'tb_books'  # 指明数据库表名
        verbose_name_plural = verbose_name = '图书'  # 在admin站点中显示的名称和显示的复数名称
        ordering = ['id']

    def __str__(self):
        """定义每个数据对象的显示信息"""
        return self.booktitle

#定义英雄模型类HeroInfo
class HeroInfo(models.Model):
    GENDER_CHOICES = (
        (0, 'male'),
        (1, 'female')
    )
    heroname = models.CharField(max_length=20, verbose_name='名称')
    herogender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性别')
    herocomment = models.CharField(max_length=200, null=True, verbose_name='描述信息')
    is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')

    herobook = models.ForeignKey(BookInfo, related_name='heros', on_delete=models.CASCADE, verbose_name='图书')  # 外键

    class Meta:
        db_table = 'tb_heros'
        verbose_name_plural = verbose_name = '英雄'

    def __str__(self):
        return self.heroname
           

serilizers.py

from rest_framework import serializers
from drf.models import BookInfo, HeroInfo


class BookHeroInfoModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = HeroInfo
        fields = ["heroname"]

#1,定义书籍模型类序列化器
class BookInfoModelSerializer(serializers.ModelSerializer):

    # PrimaryKeyRelatedField此字段将被序列化为关联对象的主键  包含read_only = True参数时,该字段将不能用作反序列化使用
    # heros = serializers.PrimaryKeyRelatedField(label='图书', read_only=True, many=True)

    # 返回关联对象的主键
    # heros = serializers.PrimaryKeyRelatedField(label='图书', queryset=HeroInfo.objects.all(), many=True)

    # 返回HeroInfoModelSerializer中指定的字段 __all__为所有字段 可反序列化 同时保存book和关联的hero信息 需重写create()方法
    heros = BookHeroInfoModelSerializer(many=True)  # 官网示例的写法
    # 参数如下:
    #     {
    #         "heros": [{"heroname": "宝玉"}, {"heroname": "黛玉"}],
    #         "booktitle": "红楼梦中人",
    #         "bookpub_date": "2008-08-08",
    #         "bookread": 20000,
    #         "bookcomment": 18000,
    #         "is_delete": false
    #     }

    # 元类
    class Meta:
        model = BookInfo
        fields = "__all__"
        extra_kwargs = {
            'bookread': {'min_value': 0},
            'bookcomment': {'min_value': 0}
        }

    # 自定义保存方法 官网示例的写法
    def create(self, validated_data):
        heros = validated_data.pop("heros")  # pop()默认删除可迭代对象中的最后一项并返回所删除的值 pop(key or index)删除指定的元素
        book_obj = BookInfo.objects.create(**validated_data)
        for hero in heros:
            HeroInfo.objects.create(herobook=book_obj, **hero)  # 简写

        return book_obj

    # 自定义更新方法
    def update(self, instance, validated_data):
        # hero_info = validated_data.pop('heros')  # hero的数据操作应在hero的序列化器中定义

        # 更新book信息
        instance.booktitle = validated_data.get('booktitle', instance.booktitle)
        instance.bookpub_date = validated_data.get('bookpub_date', instance.bookpub_date)
        instance.bookread = validated_data.get('bookread', instance.bookread)
        instance.bookcomment = validated_data.get('bookcomment', instance.bookcomment)
        instance.save()

        # # 更新英雄信息
        # HeroInfo.objects.filter(herobook=instance).delete()  # 一般不在更新book的时候更新hero 对hero的操作请在有关hero的主视图里操作
        # for hero in hero_info:
        #     HeroInfo.objects.update_or_create(herobook=instance, **hero)

        return instance


class HeroBookInfoModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = BookInfo
        fields = ["id", "booktitle"]

# 英雄模型序列化器
class HeroInfoModelSerializer(serializers.ModelSerializer):

    # 序列化使用 包含read_only=True参数时,该字段将不能用作反序列化使用 返回关联对象的主键
    # herobook = serializers.PrimaryKeyRelatedField(label='图书', read_only=True)
    # 序列化返回数据:
    #     {
    #         "id": 2,
    #         "herobook": 1,
    #         "heroname": "黄蓉",
    #         "herogender": "女",
    #         "herocomment": "打狗棍法",
    #         "is_delete": false
    #     }

    # 反序列化使用 包含queryset参数时,将被用作反序列化时参数校验使用 返回关联对象的主键
    herobook = serializers.PrimaryKeyRelatedField(label='图书', queryset=BookInfo.objects.all())
    # 序列化返回数据:
    #     {
    #         "id": 2,
    #         "herobook": 1,
    #         "heroname": "黄蓉",
    #         "herogender": "女",
    #         "herocomment": "打狗棍法",
    #         "is_delete": false
    #     }

    # 反序列化参数如下:
    #     {
    #         "heroname": "神雕",
    #         "herogender": 1,
    #         "herocomment": "阿刁",
    #         "is_delete": false,
    #         "herobook": 1
    #     }

    # 序列化使用 此字段将被序列化为关联对象的字符串表示方式(即__str__方法的返回值)
    # herobook = serializers.StringRelatedField(label='图书')

    # 反序列化使用 需要传递booktitle值
    # herobook = serializers.SlugRelatedField(label='图书', slug_field='booktitle', queryset=BookInfo.objects.all())

    # 序列化使用
    # herobook = HeroBookInfoModelSerializer(read_only=True)

    class Meta:
        model = HeroInfo
        fields = "__all__"


    # 对序列化字段内容做额外的操作处理
    def to_representation(self, instance):
        """
        序列化前最后一步 对序列化字段内容做额外的操作处理
        :param instance:
        :return:
        """
        data = super().to_representation(instance)
        try:
            herogender = data['herogender']
            if herogender == 0:
                data['herogender'] = "女"
            elif herogender == 1:
                data['herogender'] = "男"
        except:
            return data
        return data

    # 对反序列化字段内容做额外的操作处理
    def to_internal_value(self, data):
        """
        反序列化第一步,拿到的是前端提交过来的原始QueryDict
        如有些字段不需要用户传入,自己这里处理,添加字段
        """
        if data['herogender'] == "男":
            data['herogender'] = 1
        elif data['herogender'] == "女":
            data['herogender'] = 0
        return super(HeroInfoModelSerializer, self).to_internal_value(data)

"""
如果想对日期字段做输出处理  可参照如下:
    只读字段包含在API输出中,但在创建或更新操作期间不需要包含在输入中
    created_at = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', read_only=True)
    updated_at = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', read_only=True)
"""







           

views.py 

"""APIView初级视图"""""

from django import http
from django.http import JsonResponse
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from drf.models import BookInfo
from drf.serializer import BookInfoModelSerializer

class BookAPIView(APIView):

    def get(self, request):
        """
        View获取数据方式:
            GET:
                request.GET
            POST:
                request.POST
                request.body

        APIView获取数据方式
            GET:
                reqeust.query_params
            POST:
                request.data

        :param request:
        :return:
        """

        # 获取APIView中的get参数
        print(request.query_params)  # <QueryDict: {'args1': ['1'], 'args2': ['2']}>
        print(request.query_params['args1'])  # 1

        return Response([{"name": "huangrong"}, {"age": 14}], status=status.HTTP_404_NOT_FOUND)

    def post(self, request):
        # 获取APIView中的post的参数
        print(request.data)  # {'args1': 1, 'args2': 2}
        print(request.data['args1'])  # 1

        # 返回字符串
        # return http.HttpResponse("ok", status=status.HTTP_201_CREATED)

        # 返回headers字段
        # response = http.HttpResponse()
        # response['it'] = 'IPython'
        # return response

        # 返回headers字段和字符串
        # response = http.HttpResponse('good python')
        # response.status_code = 201
        # response['it'] = 'Python'
        # return response

        # 返回Json数据
        # return JsonResponse({"msg": "ok", "data": "you are good"})

        # 返回Response数据
        return Response({"msg": "ok", "data": "Response"})

    def delete(self, request):
        print(request.data)

        return Response("ok", status=status.HTTP_204_NO_CONTENT)

class BookListAPIView(APIView):

    def get(self, request):
        # 1,查询所有的书籍
        books = BookInfo.objects.all()

        # 2,将对象列表转成字典列表
        serializr = BookInfoModelSerializer(instance=books, many=True)

        # 3,返回响应
        return Response(serializr.data)

    def post(self, request):
        # 1,获取参数
        data_dict = request.data

        # 2,创建序列化器
        serializer = BookInfoModelSerializer(data=data_dict)

        # 3,校验,入库
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 4,返回响应
        return Response(serializer.data, status=status.HTTP_201_CREATED)


# 3,序列化器和APIView实现详情、更新和删除视图
class BookDetailAPIView(APIView):
    # permission_classes =
    # authentication_classes =
    # throttle_classes =

    def get(self, request, book_id):
        # 1,获取书籍
        book = BookInfo.objects.get(id=book_id)

        # 2,创建序列化器对象
        serializer = BookInfoModelSerializer(instance=book)

        # 4,返回响应
        return Response(serializer.data, status=status.HTTP_200_OK)

    def put(self, request, book_id):
        # 1,获取数据,获取对象
        data_dict = request.data
        book = BookInfo.objects.get(id=book_id)

        # 2,创建序列化器对象
        serializer = BookInfoModelSerializer(instance=book, data=data_dict)

        # 3,校验,入库
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 4,返回响应
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def delete(self, request, book_id):
        # 1,删除书籍
        BookInfo.objects.get(id=book_id).delete()

        # 2,返回响应
        return Response(status=status.HTTP_204_NO_CONTENT)


"""
APIView初级视图总结:
    说明:
        APIView是REST framework提供的所有视图的基类,继承自Django的View父类。
    支持定义的属性:
            authentication_classes 列表或元祖,身份认证类
            permissoin_classes 列表或元祖,权限检查类
            throttle_classes 列表或元祖,流量控制类
    请求:
        获取get参数:request.query_params
        获取post/put/patch/delete参数:request.data
    响应:
        可以使用APIView提供的Response返回响应的数据
        Response几乎支持任何格式的符合标准的内容如Json、字符串、列表等
    get:
        BookInfoModelSerializer(instance=book)  # 获取单条数据(详情)
        BookInfoModelSerializer(instance=books,many=True)  # 获取多条数据(列表)
    post:
        BookInfoModelSerializer(data=data_dict)
    put/patch:
        BookInfoModelSerializer(instance=book,data=data_dict)
    delete:
        BookInfo.objects.get(id=book_id).delete()
"""

"""GenericAPIView高级视图"""
from rest_framework.generics import GenericAPIView
from rest_framework import status
from rest_framework.response import Response
from drf.models import BookInfo
from drf.serializer import BookInfoModelSerializer


# 使用二级视图GenericAPIView实现列表和创建视图
class BookListGenericAPIView(GenericAPIView):
    # 提供列表视图、详情视图通用的属性
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer

    def get(self, request):
        # 1,查询所有的书籍
        # books = self.queryset
        books = self.get_queryset()

        # 2,将对象列表转成字典列表
        # serializr = BookInfoModelSerializer(instance=books,many=True)
        # serializr = self.serializer_class(instance=books,many=True)
        # serializr = self.get_serializer_class()(instance=books,many=True)
        serializr = self.get_serializer(instance=books, many=True)

        # 3,返回响应
        return Response(serializr.data)

    def post(self, request):
        # 1,获取参数
        data_dict = request.data

        # 2,创建序列化器
        # serializer = BookInfoModelSerializer(data=data_dict)
        serializer = self.get_serializer(data=data_dict)

        # 3,校验,入库
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 4,返回响应
        return Response(serializer.data, status=status.HTTP_201_CREATED)


# 使用二级视图GenericAPIView实现详情、删除和更新视图
class BookDetailGenericAPIView(GenericAPIView):
    # 提供列表视图、详情视图通用的属性
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer

    # 详情页视图使用
    # lookup_field = "id"
    lookup_url_kwarg = "book_id"

    def get(self, request, book_id):
        # 1,获取书籍
        # book = BookInfo.objects.get(id=book_id)
        book = self.get_object()  # 根据id到queryset中取出书籍对象

        # 2,创建序列化器对象
        serializer = self.get_serializer(instance=book)

        # 4,返回响应
        return Response(serializer.data, status=status.HTTP_200_OK)

    def put(self, request, book_id):
        # 1,获取数据,获取对象
        data_dict = request.data
        book = self.get_object()

        # 2,创建序列化器对象
        serializer = self.get_serializer(instance=book, data=data_dict, partial=True)

        # 3,校验,入库
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 4,返回响应
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def delete(self, request, book_id):
        # 1,删除书籍
        self.get_object().delete()

        # 2,返回响应
        return Response(status=status.HTTP_204_NO_CONTENT)


from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, \
    DestroyModelMixin
from rest_framework.pagination import PageNumberPagination
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter, SearchFilter


# 自定义分页类
class StandardPageNumberPagination(PageNumberPagination):
    page_size = 50  # 每页数目
    page_query_param = "page"  # 前端发送的页数关键字名,默认为"page"
    page_size_query_param = "page_size"  # 前端发送的每页数目关键字名,默认为None
    max_page_size = 20000  # 前端最多能设置的每页数量

    # 重写分页类返回数据
    def get_paginated_response(self, data):
        return Response(OrderedDict([
            ('drf魅力', 'This is it !!! '),
            ('count', self.page.paginator.count),
            ('next', self.get_next_link()),
            ('previous', self.get_previous_link()),
            ('results', data)
        ]))


# Mixin和二级视图GenericAPIView实现列表视图
class BookListMixinGenericAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
    # 提供公共的属性
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer

    # 列表视图使用
    # pagination_class = None  # 关闭全局定义的分页
    pagination_class = StandardPageNumberPagination  # 指定局部自定义分页控制类 优先级高于全局

    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]  # 指定局部过滤、排序后端 优先级高于全局
    # filter_fields = ('booktitle', 'bookread')  # 局部过滤指定字段 精确查询
    filterset_fields = ['booktitle', 'bookread']  # 局部过滤指定字段 精确查询 优先级 > filter_fields
    search_fields = ['booktitle', 'bookcomment']  # 局部过滤指定字段 模糊查询 查询字段应为字符串类型 此处bookcomment虽然可以 但是建议置为精确查询
    ordering_fields = ('id', 'bookread', 'bookpub_date')  # 局部排序指定字段

    def get(self, request):
        return self.list(request)

    def post(self, request):
        return self.create(request)


# Mixin和二级视图GenericAPIView实现详情视图
class BookDetailMixinGenericAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    # 1,提供通用属性
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer
    # lookup_field = "id"
    lookup_url_kwarg = "book_id"

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

    def put(self, request, book_id):
        return self.update(request, partial=True)

    def delete(self, request, book_id):
        return self.destroy(request)


"""
GenericAPIView高级视图总结:
    说明:
        继承自APIVIew,增加了对于列表视图和详情视图可能用到的通用支持方法。通常使用时,可搭配一个或多个Mixin扩展类。
    支持定义的属性:
        列表视图与详情视图通用:
            queryset 列表视图的查询集
            serializer_class 视图使用的序列化器
        列表视图使用(需要结合Mixin类使用):
            pagination_class 局部指定分页控制类
                可选分页器
                    PageNumberPagination  前端访问网址形式:GET  127.0.0.1/books/?page=1&page_size=10
                        可以在子类中定义的属性:
                            page_size 每页数目
                            page_query_param 前端发送的页数关键字名,默认为"page"
                            page_size_query_param 前端发送的每页数目关键字名,默认为None
                            max_page_size 前端最多能设置的每页数量
                    LimitOffsetPagination  前端访问网址形式:GET http://api.example.org/books/?limit=100&offset=400
                        可以在子类中定义的属性:
                            default_limit 默认限制,默认值与PAGE_SIZE设置一直
                            limit_query_param limit参数名,默认'limit'
                            offset_query_param offset参数名,默认'offset'
                            max_limit 最大limit限制,默认None
                        from rest_framework.pagination import LimitOffsetPagination
                        class BookListView(ListAPIView):
                            ... ...
                            pagination_class = LimitOffsetPagination
                自定义返回数据:
                    重写get_paginated_response()方法
                注意点:
                    如果未在模型中指定ordering 会有提示Pagination may yield inconsistent results with an unordered object_list: ... ... 
                    此时在model里class Meta属性中定义ordering即可 如:ordering = ['id']
            filter_backends 局部指定过滤控制后端DjangoFilterBackend、排序控制后端OrderingFilter等
                精确查询 以下两种方法都支持使用 另外还有SearchFilter 支持模糊过滤 字段应为CharField或者TextField 如:search_fields = ['username', 'email']
                    filter_fields = ('booktitle', 'bookread')  # 指定过滤字段
                    filterset_fields  = ['booktitle']  # 指定过滤字段 优先级高于filter_fields  两者使用其一即可
        详情页视图使用:
            lookup_field 查询单一数据库对象时使用的条件字段,默认为'pk' 可设置为id 不可设置其它值
            lookup_url_kwarg 查询单一数据时URL中的参数关键字名称,默认与look_field相同 可设置其它值
    提供的方法:
        列表视图与详情视图通用:
            get_queryset(self) 返回视图使用的查询集,是列表视图与详情视图获取数据的基础,默认返回queryset属性,可以重写
            get_serializer_class(self) 返回序列化器类,默认返回serializer_class,可以重写
            get_serializer(self, args, *kwargs) 返回序列化器对象,被其他视图或扩展类使用,如果我们在视图中想要获取序列化器对象,可以直接调用此方法
                注意,在提供序列化器对象的时候,REST framework会向对象的context属性补充三个数据:request、format、view,这三个数据对象可以在定义序列化器时使用。
        详情视图使用:
            get_object(self) 返回详情视图所需的模型类数据对象,默认使用lookup_field参数来过滤queryset。 在试图中可以调用该方法获取详情信息的模型类对象
                若详情访问的模型类对象不存在,会返回404。
                该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。
    GenericAPIView视图:
        get:
            # 列表视图
            def get(self,request):
                books = self.get_queryset()
                serializr = self.get_serializer(instance=books, many=True)
                return Response(serializr.data)
            # 详情视图
            def get(self,request,book_id):
                book = self.get_object()
                serializer = self.get_serializer(instance=book)
                return Response(serializer.data, status=status.HTTP_200_OK)
        post:
            def post(self,request):
                data_dict = request.data
                serializer = self.get_serializer(data=data_dict)
                serializer.is_valid(raise_exception=True)
                serializer.save()
                return Response(serializer.data, status=status.HTTP_201_CREATED)
        put/patch:
            def put(self,request,book_id):
                data_dict = request.data
                book = self.get_object()
                serializer = self.get_serializer(instance=book, data=data_dict, partial=True)  # partial=True允许部分更新
                serializer.is_valid(raise_exception=True)
                serializer.save()
                return Response(serializer.data,status=status.HTTP_201_CREATED)
        delete:
            def delete(self,request,book_id):
                self.get_object().delete()
                return Response(status=status.HTTP_204_NO_CONTENT)
        注意点:
            GenericAPIView未提供分页和过滤功能 需结合Mixin类使用才能生效 重写Mixin类提供的get()方法
    GenericAPIView结合Mixin类视图:
        get:
            # 列表视图
            def get(self,request):
                return self.list(request)
            # 详情视图
            def get(self, request, book_id):
                return self.retrieve(request)
        post:
            def post(self,request):
                return self.create(request)
        put/patch:
            def put(self, request, book_id):
                return self.update(request, partial=True)  # partial=True允许部分更新
        delete:
            def delete(self, request, book_id):
                return self.destroy(request)
        注意点:
            需要重写对应的方法 返回对应Mixin的方法
Mixin:
    特点: 
        1, mixin类提供用于提供基本视图行为(列表视图, 详情视图)的操作
        2, 配合高级视图GenericAPIView使用的
    类名称             提供方法           功能
ListModelMixin        list          查询所有的数据
CreateModelMixin      create        创建单个对象
RetrieveModelMixin    retrieve      获取单个对象
UpdateModelMixin      update        更新单个对象
DestroyModelMixin     destroy       删除单个对象
"""

"""GenericAPIView扩展之超级视图"""

from rest_framework.throttling import AnonRateThrottle, UserRateThrottle
from rest_framework.generics import ListAPIView, CreateAPIView, ListCreateAPIView
from rest_framework.generics import RetrieveAPIView, UpdateAPIView, DestroyAPIView, RetrieveUpdateDestroyAPIView

# class BookListThirdView(ListAPIView,CreateAPIView):  简化为如下:
class BookListThirdView(ListCreateAPIView):
    # 提供通用属性
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer
    throttle_classes = (UserRateThrottle,)

    # 列表视图使用
    # pagination_class = None  # 关闭全局定义的分页
    pagination_class = StandardPageNumberPagination  # 指定局部自定义分页控制类 优先级高于全局

    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]  # 指定局部过滤、排序后端 优先级高于全局
    # filter_fields = ('booktitle', 'bookread')  # 局部过滤指定字段 精确查询
    filterset_fields = ['booktitle', 'bookread']  # 局部过滤指定字段 精确查询 优先级 > filter_fields
    search_fields = ['booktitle', 'bookcomment']  # 局部过滤指定字段 模糊查询 查询字段应为字符串类型 此处bookcomment虽然可以 但是建议置为精确查询
    ordering_fields = ('id', 'bookread', 'bookpub_date')  # 局部排序指定字段

# class BookDetailThirdView(RetrieveAPIView,UpdateAPIView,DestroyAPIView):  简化为如下:
class BookDetailThirdView(RetrieveUpdateDestroyAPIView):
    # 提供通用属性
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer
    throttle_classes = (AnonRateThrottle,)

    # 详情页视图使用
    lookup_field = "id"  # 默认为pk


"""
GenericAPIView扩展之超级视图总结:
    说明:
        如果没有大量的自定义的行为  可使用通用视图(超级视图)来快速实现CURD行为
    支持定义的属性:
        列表视图与详情视图通用:
            同GenericAPIView + Mixin
        列表视图使用:
            同GenericAPIView + Mixin
        详情页视图使用:
            同GenericAPIView + Mixin
    提供的方法:
        列表视图与详情视图通用:
        详情视图使用:
    GenericAPIView扩展视图:
        get:ListAPIView、RetireveAPIView、RetrieveUpdateAPIView、RetrieveUpdateDestoryAPIView
        post:CreateAPIView
        put/patch:UpdateAPIView、RetrieveUpdateAPIView、RetrieveUpdateDestoryAPIView
        delete:DestoryAPIView、RetrieveUpdateDestoryAPIView
        注意点:
            高度封装方法和属性 一般不需要重写
常见的子类视图:
        类名称                             父类                 提供方法                    作用
    CreateAPIView                   GenericAPIView,            post                  创建单个对象
                                    CreateModelMixin
                                    
    ListAPIView                     GenericAPIView,             get                  查询所有的数据
                                    ListModelMixin
    
    RetrieveAPIView                 GenericAPIView,             get                   获取单个对象
                                    RetrieveModelMixin 
                                    
    DestroyAPIView                  GenericAPIView,            delete                 删除单个对象
                                    DestroyModelMixin
                                    
    UpdateAPIView                   GenericAPIView,             put                   更新单个对象
                                    UpdateModelMixin
    RetrieveUpdateAPIView           GenericAPIView,         get、put、patch          获取、更新单个对象
                                    RetrieveModelMixin,
                                    UpdateModelMixin     
    RetrieveUpdateDestoryAPIView    GenericAPIView,       get、put、patch、delete   获取、更新、删除单个对象
                                    RetrieveModelMixin,
                                    UpdateModelMixin,
                                    DestoryModelMixin
    特点: 
        高度封装 简单易用 快速高效
"""

"""
视图集ViewSet
使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:
    list() 提供一组数据
    retrieve() 提供单个数据
    create() 创建数据
    update() 保存数据
    destory() 删除数据
常用视图集父类:
    ViewSet
        继承自APIView,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。
        在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。
    GenericViewSet
        继承自GenericAPIView,作用也与GenericAPIVIew类似,提供了get_object、get_queryset等方法便于列表视图与详情信息视图的开发。
    ModelViewSet
        继承自GenericAPIVIew,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。
    ReadOnlyModelViewSet
        继承自GenericAPIVIew,同时包括了ListModelMixin、RetrieveModelMixin。
对应图如下:
      类名称                   父类                         作用
     ViewSet               APIView                    可以做路由映射
                          ViewSetMixin
                          
   GenericViewSet        GenericAPIView      可以做路由映射,可以使用三个属性,三个方法
                          ViewSetMixin
                                 
    ModelViewSet          GenericAPIView     所有的增删改查功能,可以使用三个属性,三个方法
      (读写)               5个mixin类
    
 ReadOnlyModelViewSet    GenericAPIView      获取单个,所有数据,可以使用三个属性,三个方法
       (只读)          RetrieveModelMixin
                         ListModelMixin
"""

# 使用viewset实现获取所有和单个
from django.shortcuts import get_object_or_404
from drf.serializer import BookInfoModelSerializer
from rest_framework import viewsets


class BooksViewSet(viewsets.ViewSet):
    """
    A simple ViewSet for listing or retrieving books.
    """

    def list(self, request):
        queryset = BookInfo.objects.all()
        serializer = BookInfoModelSerializer(instance=queryset, many=True)
        return Response(serializer.data)

    def create(self, request):
        serializer = BookInfoModelSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        queryset = BookInfo.objects.all()
        book = get_object_or_404(queryset, pk=pk)
        serializer = BookInfoModelSerializer(instance=book)
        return Response(serializer.data)


# 13,使用ReadOnlyModelViewSet实现获取单个和所有
from rest_framework.viewsets import ReadOnlyModelViewSet


class BooksReadOnlyModelViewSet(ReadOnlyModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer


# 14,ModelViewSet实现列表视图,详情视图功能
from rest_framework.viewsets import ModelViewSet


class BookModelViewSet(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer


from collections import OrderedDict
from rest_framework.decorators import action


# 视图集通过action装饰器配合url映射实现自定义方法
class BookInfoModelViewSet(ModelViewSet):
    """
    list:
        获取所有数据

    create:
        创建单个对象
    """

    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer
    throttle_scope = 'book_info_model_view_set'

    # 1,局部认证
    # authentication_classes = [SessionAuthentication]

    # 2,局部权限
    # permission_classes = [AllowAny]

    # 3,局部限流
    # throttle_classes = [AnonRateThrottle]

    # 4,可选限流
    # throttle_scope = 'downloads'

    # 5,局部分页
    # pagination_class = LimitOffsetPagination # ?limit=100 或者 ?offset=400&limit=100
    # pagination_class = PageNumberPagination # ?page=4

    # 6,自定义分页对象

    # 7,局部过滤
    # filter_backends = [DjangoFilterBackend]
    # filterset_fields = ['id', 'btitle',"is_delete"]

    # 8,局部排序
    # filter_backends = [filters.OrderingFilter] # 导包路径: from rest_framework import filters
    # ordering_fields = ['id', 'btitle','bread'] #查询格式: ?ordering=-bread,id

    # 1,获取阅读量大于20的书籍
    @action(methods=['GET'], detail=False)  # 生成路由规则: 前缀/方法名/
    def bookread_gt20(self, request):
        # 1,获取指定书籍
        books = BookInfo.objects.filter(bookread__gt=20)

        # 2,创建序列化器对象
        serializer = self.get_serializer(instance=books, many=True)

        # 3,返回响应
        return Response(serializer.data)

    # 2,修改书籍编号为1的, 阅读量为99
    @action(methods=["PUT"], detail=True)  # 生成路由规则: 前缀/{pk}/方法名/
    def update_book_bookread(self, request, pk):
        # 1,获取参数
        book = self.get_object()
        data = request.data

        # 2,创建序列化器
        serializer = self.get_serializer(instance=book, data=data, partial=True)

        # 3,校验,入库
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 4,返回响应
        return Response(serializer.data, status=201)


"""
视图集ViewSet总结
ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。
视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上。如:
class BookInfoViewSet(viewsets.ViewSet):

    def list(self, request):
        ...

    def retrieve(self, request, pk=None):
        ...
在设置路由时,我们可以如下操作:
urlpatterns = [
    url(r'^books/$', BookInfoViewSet.as_view({'get':'list'}),
    url(r'^books/(?P<pk>\d+)/$', BookInfoViewSet.as_view({'get': 'retrieve'})
]
action装饰器
    views.py
        @action(methods=['GET'],detail=False) #生成路由规则: 前缀/方法名/
        def bookread_gt20(self,request):
            books = BookInfo.objects.filter(bookread__gt=20)
            serializer = self.get_serializer(instance=books,many=True)
            return Response(serializer.data)
    urls.py
        path('books/readgt20/',views.BookInfoModelViewSet.as_view({"get":"bookread_gt20"}))  # 通过url里的as_view()方法映射请求路径到views中的指定方法
    注意点:
        detail=True  # or False  detail为False 表示不需要处理具体的BookInfo对象  detail为True,表示要处理具体与pk主键对应的BookInfo对象
使用rest_framework.routers提供的路由对象实现视图集路由:
    from rest_framework.routers import SimpleRouter,DefaultRouter
    router = SimpleRouter()  # or DefaultRouter() 比之SimpleRouter()多出一些类似于导航路由的路由
    router.register('books',views.BookInfoModelViewSet,basename="Books")
    urlpatterns += router.urls
"""

"""
DRF补充:
    DRF提供的功能包括(不限于)以下:
        认证
        权限
        限流
        过滤
        排序
        分页
        异常处理
        自动生成接口文档
    对序列化字段内容做额外的操作处理:
        to_representation(self, instance)
    对反序列化字段内容做额外的操作处理:
        to_internal_value(self, data)
"""

from drf.serializer import HeroInfoModelSerializer
from drf.models import HeroInfo


class HeroInfoList(ListCreateAPIView):
    queryset = HeroInfo.objects.all()
    serializer_class = HeroInfoModelSerializer

    # def perform_create(self, serializer):
    #     print(serializer)
    #     serializer.save(owner=self.request.user)


class HeroInfoDetail(RetrieveUpdateDestroyAPIView):
    queryset = HeroInfo.objects.all()
    serializer_class = HeroInfoModelSerializer


"""
DRF总结:
    两个基类:
        APIView
            支持定义的属性:
                authentication_classes 列表或元祖,身份认证类
                permissoin_classes 列表或元祖,权限检查类
                throttle_classes 列表或元祖,流量控制类
        GenericAPIView
            支持定义的属性:
                authentication_classes 列表或元祖,身份认证类
                permissoin_classes 列表或元祖,权限检查类
                throttle_classes 列表或元祖,流量控制类
                列表视图与详情视图通用:
                    queryset 列表视图的查询集
                    serializer_class 视图使用的序列化器
                列表视图使用:
                    pagination_class 分页控制类
                    filter_backends 过滤控制后端
                详情页视图使用:
                    lookup_field 查询单一数据库对象时使用的条件字段,默认为'pk'
                    lookup_url_kwarg 查询单一数据时URL中的参数关键字名称,默认与look_field相同
            提供的方法:
                列表视图与详情视图通用:
                    get_queryset(self)
                    get_serializer_class(self)
                    get_serializer(self, args, *kwargs)
                详情视图使用:
                    get_object(self)
    五个扩展类:
        ListModelMixin
            提供list(request, *args, **kwargs)方法
        CreateModelMixin
            提供create(request, *args, **kwargs)方法
        RetrieveModelMixin
            提供retrieve(request, *args, **kwargs)方法
        UpdateModelMixin
            提供update(request, *args, **kwargs)方法
            提供partial_update(request, *args, **kwargs)方法
        DestroyModelMixin
            提供destroy(request, *args, **kwargs)方法
    几个可用子类视图:
        CreateAPIView
        ListAPIView
        RetireveAPIView
        DestoryAPIView
        UpdateAPIView
        RetrieveUpdateAPIView
        RetrieveUpdateDestoryAPIView
    GenericAPIView需要搭配Mixin类 一些工具类如pagination_class、filter_backends才生效
"""

           

urls.py

from django.urls import path
from drf import views

app_name = "drf"

urlpatterns = [
    # APIView
    path('books/apiview/', views.BookAPIView.as_view(), name='book_api_view'),  # APIView视图
    path('books/', views.BookListAPIView.as_view(), name='booklist_api_view'),  # APIView列表和创建视图
    # Django2.0语法 APIView详情、删除和更新视图
    # url('^books/(?P<book_id>\d+)/$', views.BookDetailAPIView.as_view(), name='bookdetail_api_view'),
    # Django3.0语法 APIView详情、删除和更新视图
    path('books/<int:book_id>/', views.BookDetailAPIView.as_view(), name='bookdetail_api_view'),

    # GenericAPIView
    path('generic_apiview_books/', views.BookListGenericAPIView.as_view(), name='BookListGenericAPIView'),  # GenericAPIView列表和创建视图
    path('generic_apiview_books/<int:book_id>/', views.BookDetailGenericAPIView.as_view(), name='BookDetailGenericAPIView'),  # GenericAPIView详情、删除和更新视图
    # GenericAPIView + Minxi
    path('mixin_generic_apiview_books/', views.BookListMixinGenericAPIView.as_view(), name='BookListMixinGenericAPIView'),  # 列表视图
    path('mixin_generic_apiview_books/<int:book_id>/', views.BookDetailMixinGenericAPIView.as_view(), name='BookDetailMixinGenericAPIView'),  # 详情视图

    # GenericAPIView扩展视图
    path('super_apiview/', views.BookListThirdView.as_view(), name='BookListThirdView'),  # 列表视图
    path('super_apiview/<int:id>/', views.BookDetailThirdView.as_view(), name='BookDetailThirdView'),  # 详情视图

    # 视图集ViewSet
    path('books_viewset/',views.BooksViewSet.as_view({'get': 'list', 'post': 'create'})),
    path('books_viewset/<int:pk>/',views.BooksViewSet.as_view({'get': 'retrieve'})),

    path('readonly_viewset/', views.BooksReadOnlyModelViewSet.as_view({'get': 'list'})),
    path('readonly_viewset/<int:pk>/', views.BooksReadOnlyModelViewSet.as_view({'get': 'retrieve'})),

    path('model_viewset/', views.BookModelViewSet.as_view({'get': 'list',"post":"create"})),
    path('model_viewset/<int:pk>/', views.BookModelViewSet.as_view({'get': 'retrieve','put': 'update','delete': 'destroy'})),

    path('books_info/viewset/',views.BookInfoModelViewSet.as_view({"get": "list","post": "create"})),
    path('books_info/viewset/<int:pk>/',views.BookInfoModelViewSet.as_view({"get": "retrieve","put": "update","delete": "destroy"})),

    path('books_info/bookread/',views.BookInfoModelViewSet.as_view({"get": "bookread_gt20"})),
    path('books_info/bookread/<int:pk>/',views.BookInfoModelViewSet.as_view({"put": "update_book_bookread"})),

    # 英雄
    path('heros/',views.HeroInfoList.as_view(), name='HeroInfoList'),
    path('heros/<int:pk>/',views.HeroInfoDetail.as_view(), name='HeroInfoDetail'),
]

# 使用SimpleRouter or DefaultRouter实现视图集路由
from rest_framework.routers import SimpleRouter, DefaultRouter
#1,创建路由对象
router = SimpleRouter()  # or DefaultRouter() 比之SimpleRouter()多出一些类似于导航路由的路由

#2,注册视图集
router.register('books', views.BookInfoModelViewSet,basename="viewset")
urlpatterns += router.urls
# print(urlpatterns)
"""
[
<URLPattern '^books/$' [name='viewset-list']>, 
<URLPattern '^books/bookread_gt20/$' [name='viewset-bookread-gt20']>, 
<URLPattern '^books/(?P<pk>[^/.]+)/$' [name='viewset-detail']>, 
<URLPattern '^books/(?P<pk>[^/.]+)/update_book_bookread/$' [name='viewset-update-book-bookread']>
]
"""




           

关注微信公众号:

Zhong__DRF笔记
Zhong__DRF笔记

感谢支持!