使用routers自动生成路由的路由器设计原则,类视图设计原则,序列化器类的设计原则

urls.py文件内容

# from django.urls import path, re_path, include
# from . import views
#
# urlpatterns = [
#     path('projects/<int:pk>/', views.ProjectDetailView.as_view()),
#     path('projects/', views.ProjectView.as_view()),
# ]
#
# from django.urls import path, re_path, include
# from . import views
# app_name = 'projects'
# urlpatterns = [
#     path('projects/<int:pk>/', views.ProjectViewSet.as_view({
#         'get': 'retrieve',  # 单查
#         'put': 'update',    # 单个更新
#         'delete': 'destroy',    # 单个删除
#     })),
#     path('projects/', views.ProjectViewSet.as_view({
#         'get': 'list',  # 多查,查询集合
#         'post': 'create',   # 创建,反序列化入库
#     })),
#     path('projects/<int:pk>/name_detail/', views.ProjectViewSet.as_view({
#         'get': 'name_detail',   # 查询指定项目的名称详情
#     })),
#     path('projects/names/', views.ProjectViewSet.as_view({
#         'get': 'names',     # 查询项目的所有名称集合
#     })),
# ]

# from django.urls import path, re_path, include
# from . import views
# urlpatterns = [
#     path('projects/<int:pk>/', views.ProjectViewSet.as_view({
#         'get': 'retrieve',  # 单查
#         'put': 'update',    # 单个更新
#         'delete': 'destroy' # 单个删除
#     })),
#     path('projects/', views.ProjectViewSet.as_view({
#         # 群查
#         'get': 'list',
#         # 创建
#         'post': 'create',
#     })),
#     path('projects/<int:pk>/name_detail/', views.ProjectViewSet.as_view({
#         # 查看单个项目的名称详情
#         'get': 'name_detail',
#     })),
#     path('projects/names/', views.ProjectViewSet.as_view({
#         # 群查所有的项目名称
#         'get': 'names',
#     })),
# ]

# from django.urls import path, re_path, include
# from . import views
#
# urlpatterns = [
#     path('projects/<int:pk>/', views.ProjectViewSet6.as_view({
#         'get': 'retrieve',
#         'put': 'update',
#         'delete': 'destroy'
#     })),
#     path('projects/', views.ProjectViewSet6.as_view({
#         'get': 'list',
#         'post': 'create'
#     })),
#     path('projects/<int:pk>/name_details/', views.ProjectViewSet6.as_view({
#         'get': 'name_details',
#     })),
#     path('projects/names/', views.ProjectViewSet6.as_view({
#         'get': 'names',
#     }))
# ]
# 需求:实现项目表的单查、单个更新、单个删除、多查、群增、单查PK的name详情、群查所有项目的名称信息
from django.urls import path, re_path, include
from . import views

# urlpatterns = [
#     path('projects/<int:pk>/', views.ProjectViewSet7.as_view({
#         'get': 'retrieve',
#         'put': 'update',
#         'delete': 'destroy',
#     })),
#     path('projects/', views.ProjectViewSet7.as_view({
#         'post': 'create',
#         'get': 'list',
#     })),
#     path('projects/<int:pk>/name_detail/', views.ProjectViewSet7.as_view({
#         'get': 'name_detail',
#     })),
#     path('projects/names_list/', views.ProjectViewSet7.as_view({
#         'get': 'names',
#     }))
# ]


"""
# 路由器设计:自动生成路由
1.admin/
2.^projects/$ [name='proje-list']
3.^projects/nameslist/$ [name='proje-nameslist']
4.^projects/(?P<pk>[^/.]+)/$ [name='proje-detail']
5.^projects/(?P<pk>[^/.]+)/details/$ [name='proje-details']
"""
from rest_framework import routers
app_name = 'projects'
router = routers.SimpleRouter()
# router = routers.DefaultRouter()
router.register(r'projects', views.ProjectViewSet7, basename='proje')
urlpatterns = [

]

urlpatterns += router.urls


models.py文件内容:
from django.db import models
from utils.base_model import BaseModel


# Create your models here.
"""
1.模型类必须继承Model或者Model的子类,
2.一个ORM模型类就对应了一个数据库中的一张表
3.在ORM模型类中定义类属性,并且类属性必须是Field的子类,与数据表中的字段对应
4.CharField与mysql中的varchar对应,并且必须得指定max_length参数,指定当前字段的最大长度
5.IntegerField类与mysql中的int对应,都是整形
6.ORM模型类会自动创建一个名为id的自增主键(非空且唯一),为int类型
7.生成迁移脚本
    a.python manage.py makemigrations 子应用名称
    b.如果不指定子应用名称,那么会将所有子应用包括内置的子应用根据models.py文件中的字段内容生成迁移脚本
8.生成迁移脚本,并不会创建表,只有执行迁移脚本之后,才会创建表
    a.python manage.py migrate 子应用名称
    b.如果不指定子应用名称,那么会执行所有子应用(包括内置)的migrations包中的迁移脚本
9.生成表的名称默认为子应用名_模型类名小写
10.打印迁移脚本的SQL语句,python manage.py sqlmigrate 子应用名称   迁移脚本名(不包括后缀的.py,用前面的几个字母就可以)
----------------------------------------------------------------------------------------------------------
a.如果ORM模型类中某个字段指定了primary_key=True, 那么ORM框架就不会自动生成名称为id的自增主键
b.会把制定了primary_key=True的字段作为主键
c.创建的ORM模型类中字段默认primary_key=False,为非主键字段
d.verbose_name主要用于提供字段的人类可读名称,改善字段的显示效果
e.help_text则用于提供字段的额外说明或者帮助信息,增加字段的可理解性
    总的来说,这两个字段都是为了提高模型字段在管理后台和表单中的可用性和友好性。
    verbose_name关注于如何命名字段,而help_text关注于如何解释字段
f.使用unique=True,为当前字段指定唯一约束,默认创建的ORM模型类字段unique=False,为False表示可以重复
g.使用null=True,表示数据库中可以为null,指定当前字段在数据库中是否可以存储NULL值,默认该字段在数据库中必须有一个值
h.使用default=True,为当前字段指定默认值,指定默认值以后,前端创建数据时,如果不指定该字段内容,那么会自动将默认值作为当前字段的值。
i.使用blank=True, 指定前端在创建数据时,可以不用传递该字段,表单验证中,表单可以不填写内容,
    如果blank=False, 则该字段在表单验证时必须要有一个值。
j.DateTimeField、DateField字段添加auto_now_add和auto_now参数
    1.auto_now_add=True 指定在创建该记录时,会自动将当前创建的时间作为该字段的值,后续不会发生变更
    2.auto_now=True 在每次更新记录时,会自动将当前更新的时间作为最新的值,每次变更都会自动修改
    3.auto_now_add和auto_now不能同时指定

"""
class Kefan(BaseModel):
    name = models.CharField(max_length=50, verbose_name='项目名称', help_text='请输入项目名称')
    leader = models.CharField(max_length=50, verbose_name='项目负责人', help_text='请输入项目负责人')
    is_execute = models.BooleanField(default=False, verbose_name='是否执行项目', help_text='请输入是否执行项目')
    desc = models.TextField(verbose_name='项目简介', help_text='请输入项目简介', null=True, blank=True)
    """
    null=True, 指定当前字段在数据库中是否可以存储NULL值,默认该字段在数据库中必须有一个值。
    blank=True, blank空白的,指定前端在创建数据时,可以为空,
    blank=False, 指定前端在创建数据时,不能为空。
    """
    class Meta:
        db_table = 'tb_kefan'
        verbose_name = '科范项目表'
        verbose_name_plural = verbose_name


serializers.py文件内容:
# from rest_framework import serializers
# from . import models
#
#
# def validate_project_name(value):
#     if '项目' not in value:
#         raise serializers.ValidationError('项目名称中必须包含<项目>关键词')
#
#
# class ProjectModelSerializer(serializers.ModelSerializer):
#     """
#     序列化器类和模型类的关系?
#     1.这两个类高度相似
#     2.当模型类中字段非常多时,定义序列化器类相当麻烦
#     3.可以定义模型序列化器,来自动将模型类中的字段生成序列化器中的字段
#         必须继承serializers.ModelSerializer父类
#         必须在Meta内部类中,使用fields指定模型类中哪些字段需要生成序列化器字段
#         必须在Meta内部类中,使用model类属性关联一个模型类
#         如果指定fields='__all__', 那么会将模型类中的所有字段生成序列化器字段
#         在生成的字段中,会将主键id设置为IntegerField类型,同时会自动指定read_only=True
#         会将DateTimeField类型中有添加auto_now_add或者auto_now参数,会自动指定read_only=True
#         会将unique=True的字段,自动生成validators=UniqueValidator唯一约束
#         如果只需要将模型类中某些字段生成序列化器字段,可以将这些字段组成元组或者列表,传递给fields
#         可以在模型序列化器类中定义模型类中的字段,会覆盖自动生成的字段
#         fields类属性,如果指定的说元组类型,那么必须包含所有的序列化器字段,
#         如果fields为__all__或者exclude那么无需指定模型类外的字段
#         模型序列化器类自带create和update方法,一般无需重写
#         可以在Meta内部类中的extra_kwargs类属性中对模型类中的自动生成的字段进行修改,将模型类字段名作为key,把具体要修改的参数作为字典的值
#     4.不同方式定义的序列化器对象的区别
#         1.如果在创建序列化器对象时,仅仅只传递instance参数,那么当前只会进行序列化输出操作,不可能进行反序列化输入操作
#             不可以调用序列化器对象的save方法
#         2.如果在创建序列化器对象时,仅仅只传递data参数,那么在调用is_valid方法后会进行反序列化输入操作,
#             同时在调用save方法时,会自动调用序列化器对象的create方法,用于数据的创建操作,会把create方法返回的数据作为序列化输出的数据源
#         3.如果在创建序列化器对象时,仅仅只传递data参数,调用is_valid方法对数据进行校验之后,直接调用serializer.data属性,未调用save方法,
#             会把校验通过的数据validated_data作为序列化输出的数据源,如果校验通过的数据中有相应的数据,同时该字段需要输出,那么输出的数据中才会有该字段
#         4.如果在创建序列化器对象时,同时传递instance和data参数,调用is_valid方法,对数据进行校验,那么在调用save方法时,
#             会自动调用序列化器对象的update方法,用于数据的更新操作,会把update方法返回的数据作为序列化输出的数据源。
#     """
#     # 需求1. 需要定义一些在模型类中没有的字段,仅仅只进行反序列化输入操作,例如:确认密码
#     xxx = serializers.CharField(write_only=True)
#     # 需求2. 需要定义一些在模型类中没有的字段,仅仅只进行序列化输出操作,例如:token的值
#     token = serializers.CharField(read_only=True)
#
#     class Meta:
#         model = models.Project
#         fields = ['id', 'name', 'leader', 'is_execute', 'xxx', 'token']
#         extra_kwargs = {
#             'name': {
#                 'min_length': 2,
#                 'label': '新的label',
#                 'validators': [validate_project_name]
#             }
#         }
#
#     def validate(self, attrs: dict):
#         var = attrs.get('xxx')
#         attrs.pop('xxx')
#         return attrs
#
#     def create(self, validated_data: dict):
#         instance = super().create(validated_data)
#         instance.token = 'xxxx dddd ffff gggg'
#         return instance
#
#
# class ProjectModelSerializer1(serializers.ModelSerializer):
#     class Meta:
#         model = models.Project
#         fields = '__all__'
#
#
# class ProjectModelSerializer2(serializers.ModelSerializer):
#     class Meta:
#         model = models.Project
#         fields = ['id', 'name', 'leader', 'desc']

# from rest_framework import serializers
# from . import models
#
#
# def validate_project_name(value):
#     if '项目' not in value:
#         raise serializers.ValidationError('项目名称中必须包含<项目>关键词')
#
#
# class ProjectModelSerializer(serializers.ModelSerializer):
#     # confirm_password字段进行反序列化输入
#     confirm_password = serializers.CharField(write_only=True)
#     password = serializers.CharField(write_only=True)
#     # token字段进行序列化输出
#     token = serializers.CharField(read_only=True)
#
#     class Meta:
#         model = models.Project
#         fields = '__all__'
#
#     def validate(self, attrs: dict) -> dict:
#         # 反序列化输入的字段中删除confirm_password字段
#         var = attrs.get('confirm_password')
#         # 逻辑1,对confirm_password进行校验和初始密码是否一致
#         if var != attrs['password']:
#             raise serializers.ValidationError('用户输入的确认密码和原始密码不一致')
#         # 逻辑2,删除确认密码,不让该字段进入到数据库中
#         attrs.pop('confirm_password')
#         return attrs
#
#     def create(self, validated_data):
#         # validated_data 是序列化器校验通过的数据
#         instance = super().create(validated_data)
#         instance.token = 'Token Ludundun XXX'
#         return instance
#
#
# class ProjectModelSerializer1(serializers.ModelSerializer):
#     class Meta:
#         model = models.Project
#         fields = '__all__'
#
#
# class ProjectModelSerializer2(serializers.ModelSerializer):
#     class Meta:
#         model = models.Project
#         fields = ['id', 'name', 'leader']

from rest_framework import serializers

from interfaces.models import Interfaces
from . import models


def validate_project_name(value):
    if '项目' not in value:
        raise serializers.ValidationError('项目名称中必须包含<项目>关键词')


class ProjectModelSerializer(serializers.ModelSerializer):
    # confirm_password字段进行反序列化输入
    confirm_password = serializers.CharField(write_only=True)
    password = serializers.CharField(write_only=True)
    # token字段进行序列化输出
    token = serializers.CharField(read_only=True)

    class Meta:
        model = models.Project
        fields = '__all__'

    def validate(self, attrs: dict):
        # 反序列化输入的字段中删除confirm_password字段
        var = attrs.get('confirm_password')
        # 逻辑1,对confirm_password进行校验和初始密码是否一致
        if var != attrs['password']:
            raise serializers.ValidationError('用户输入的确认密码和原始密码不一致')
        # 逻辑2,删除确认密码,不让该字段进入到数据库中
        attrs.pop('confirm_password')
        return attrs

    def create(self, validated_data):
        # validated_data 是序列化器校验通过的数据
        instance = super().create(validated_data)
        instance.token = 'Token Ludundun xxxxxx'
        return instance


class ProjectModelSerializer2(serializers.ModelSerializer):
    class Meta:
        model = models.Project
        fields = ['id', 'name', 'leader']


class InterfaceModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Interfaces
        fields = ['id', 'name', 'create_time']


class ProjectModelSerializer1(serializers.ModelSerializer):
    interfaces = InterfaceModelSerializer(read_only=True, many=True)  # 设置read_only=True只支持序列化输出

    class Meta:
        model = models.Project
        fields = '__all__'

views.py视图文件内容:

from rest_framework.generics import GenericAPIView
from rest_framework.request import Request
from rest_framework import filters
from rest_framework import permissions
from rest_framework import mixins
from rest_framework import generics
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import status
from .models import Project
from rest_framework.decorators import action
from . import serializers
# from .filters import ProjectFilter
from utils.pagination import PageNumberPagination

"""

# 源码中mixins.py文件中的Mixin拓展类
获取列表数据:ListModelMixin扩展类,list action方法,get
创建数据:CreateModelMixin扩展类,create action方法,post
获取详情数据:RetrieveModelMixin扩展类,retrieve action方法,get
更新数据:UpdateModelMixin扩展类,update action方法,完整更新,partial_update action方法,部分更新,put、patch
删除数据:DestroyModelMixin扩展类,destroy action方法,delete

# 源码generics.py文件中的APIView具体的通用视图
获取列表数据:ListAPIView, 继承ListModelMixin、GenericAPIView
创建数据:CreateAPIView, 继承CreateModelMixin、GenericAPIView
获取详情数据:RetrieveAPIView, 继承CreateModelMixin、GenericAPIView
更新数据:UpdateAPIView, 继承UpdateModelMixin、GenericAPIView
删除数据:DestroyAPIView, 继承DestroyModelMixin、GenericAPIView

# 源码viewsets.py文件中的ModelViewSet视图集, GenericViewSet继承了GenericAPIView和ViewSetMixin,相当于把上面做了一个整合
class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
    A viewset that provides default `create()`, `retrieve()`, `update()`,
    `partial_update()`, `destroy()` and `list()` actions.

# 源码generics.py文件中的APIView具体的混合通用视图
获取列表数据、创建数据:ListCreateAPIView
获取数据详情、更新数据:RetrieveUpdateAPIView
获取数据详情、删除数据:RetrieveDestroyAPIView
获取数据详情、更新数据、删除数据:RetrieveUpdateDestroyAPIView

# 视图集
1.如果需要实现在定义路由条目时,请求方法与要调用的action方法进行一一对应,必须得继承ViewSetMixin
2.ViewSet继承了ViewSetMixin、APIView,具备请求方法与要调用的action方法进行一一对应功能,以及认证授权限流功能,
    GenericAPIView提供了get_object()、get_queryset()、get_serializer()等方法
3.GenericViewSet继承了ViewSetMixin、GenericAPIView,具备请求方法与要调用的action方法进行一一对应功能,以及支持Mixin扩展类
4.ReadOnlyModelViewSet继承了RetrieveModelMixin、ListModelMixin、GenericViewSet,提供了两个读取数据的接口
5.ModelViewSet继承了CreateModelMixin、RetrieveModelMixin、UpdateModelMixin、
    DestroyModelMixin、ListModelMixin、GenericViewSet,提供了6个接口。
6.ViewSetMixin类提供了请求方法与要调用的action方法进行一一对应功能,在定义路由条目时,在as_view()方法中支持接收字典数据,
    把请求方法名称字符串作为key, 把具体要调用的action方法名字符串作为值。


drf中的自动生成路由:
1.自动生成路由条目,默默仅仅只会生成通用的action,自定义的action默认不会生成
2.需要使用action装饰器,from rest_framework.decorators import action装饰自定义的action方法,那么才支持自动生成路由条目,
    》第一个参数为methods指定当前action支持的请求方法,为列表类型,将当前已支持的action方法作为元素retrieve、update、create、destroy、list、partrail_update
    》如果不进行设置,默认methods=['get']
    》第二个参数必须是detail关键字参数,指定是否需要接收主键ID,其实顾名思义就是是否获取详情信息
        detail为False,无需接收主键id;detail为True,需要接收主键ID。
    》url_path指定生成路由条目时路径名称,默认当前action方法名称
    》url_name指定生成的路由条目名称后缀,默认为当前action方法名称
3.生成路由条目的操作方式
from rest_framework import routers
router = routers.SimpleRouter()
# router = routers.DefaultRouter()
router.register(r'projects', views.ProjectViewSet7, basename='proje')
    a.定义SimpleRouter路由器对象
    b.调用路由器对象的register方法,对路由进行注册
        》第一个参数需要设置r'路由前缀'
        》第二个参数需要指定视图集类引用,不能调用as_view()方法
        》basename参数指定生成的路由条目名称前缀,如果不指定,那么默认生成的路由条目名称前缀为第一个参数指定的值
    c.使用路由器对象.urls属性,能获取自动生成的路由条目

类视图的设计原则(有则用父类,无则自定义,半有半无就重写父类)
这句话啥意思呢,就是继承父类,父类中有的方法,就直接用父类的就行,如果父类也没有该方法,就需要自己自定义该方法了,
或者父类中有这个相关的方法,但是不够全面,那就需要你自己再重新写一些父类中的这个方法进行完善了
1.如果父类有提供相应的资源,Mixin扩展类、具体通用的视图,并且能完全满足需求,就直接使用父类提供的
2.如果父类提供的资源仅仅只是部分不满足需求,重写父类的实现
3.如果父类提供的资源完全不满足需求,直接自定义
4.按需要选择父类
5.默认情况下,直接使用ModelViewSet

序列化器类的设计原则:
1.如果操作的是模型数据,一定使用ModelSerializer,生成的字段不满足需求,可修改
2.如果操作的是普通对象,那么才使用Serializer
3.复杂的查询逻辑,一般把其他序列化器类作为序列化器的字段进行使用,如下所示,进行序列化输出时,会把InterfaceModelSerializer的fields信息,
作为ProjectModelSerializer1序列化器类序列化的字段内容输出到前端:
{
class InterfaceModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = Interfaces
        fields = ['id', 'name', 'create_time']


class ProjectModelSerializer1(serializers.ModelSerializer):
    interfaces = InterfaceSerializer(read_only=True, many=True)

    class Meta:
        model = models.Project
        fields = '__all__'

}


"""


class ProjectDetailView(generics.RetrieveUpdateDestroyAPIView):
    # 支持单查、更新、删除数据
    serializer_class = serializers.ProjectModelSerializer2
    queryset = Project.objects.all()


class ProjectView(generics.ListCreateAPIView):
    serializer_class = serializers.ProjectModelSerializer2
    queryset = Project.objects.all()
    # 搜索、过滤、分页、排序
    search_fields = ['name', 'leader', 'desc', 'interfaces__name']
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    # filterset_class = ProjectFilter
    pagination_class = PageNumberPagination
    ordering_fields = ['name', 'id', 'leader']


class ProjectViewSet(viewsets.ModelViewSet):
    serializer_class = serializers.ProjectModelSerializer2
    queryset = Project.objects.all()
    search_fields = ['name', 'leader', 'desc', 'interfaces__name']
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    pagination_class = PageNumberPagination
    ordering_fields = ['name', 'id', 'leader']

    def name_detail(self, request, *args, **kwargs):
        instance = self.get_object()
        return Response({
            'id': instance.id,
            'name': instance.name
        })

    def names(self, request, *args, **kwargs):
        queryset = self.get_queryset()
        names = [obj.name for obj in queryset]
        return Response(data=names, status=status.HTTP_200_OK)


class ProjectViewSet1(viewsets.ModelViewSet):
    serializer_class = serializers.ProjectModelSerializer2
    queryset = Project.objects.all()
    search_fields = ['name', 'leader', 'desc', 'interfaces__name']
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    # filterset_class = ProjectFilter
    pagination_class = PageNumberPagination
    ordering_fields = ['name', 'id', 'leader']

    def name_detail(self, request, *args, **kwargs):
        instance = self.get_object()
        return Response({
            'id': instance.id,
            'name': instance.name
        })

    def names(self, request, *args, **kwargs):
        queryset = self.get_queryset()
        data = [obj.name for obj in queryset]
        return Response(data)


class ProjectViewSet2(viewsets.ModelViewSet):
    serializer_class = serializers.ProjectModelSerializer2
    queryset = Project.objects.all()
    search_fields = ['name', 'leader', 'desc', 'interfaces__name']
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    pagination_class = PageNumberPagination
    ordering_fields = ['name', 'id', 'leader']

    def name_detail(self, request, *args, **kwargs):
        instance = self.get_object()
        return Response({
            'id': instance.id,
            'name': instance.name
        })

    def names(self, request, *args, **kwargs):
        queryset = self.get_queryset()
        data = [obj.name for obj in queryset]
        return Response(data)


class ProjectViewSet3(viewsets.ModelViewSet):
    serializer_class = serializers.ProjectModelSerializer2
    queryset = Project.objects.all()
    search_fields = ['name', 'leader']
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    pagination_class = PageNumberPagination
    ordering_fields = ['name', 'id', 'leader']

    def name_detail(self, request, *args, **kwargs):
        instance = self.get_queryset()
        return Response({
            'id': instance.id,
            'name': instance.name
        })

    def names(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        data = [obj.name for obj in queryset]
        return Response(data)


from rest_framework import viewsets
from .models import Project


class ProjectViewSet6(viewsets.ModelViewSet):
    serializer_class = serializers.ProjectModelSerializer
    queryset = Project.objects.all()
    search_fields = ['name', 'leader']
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    pagination_class = PageNumberPagination
    ordering_fields = ['name', 'id', 'leader']

    def name_detail(self, request, *args, **kwargs):
        instance = self.get_object()
        return Response({
            'id': instance.id,
            'name': instance.name
        })

    def names(self, request, *args, **kwargs):
        queryset = self.get_queryset()
        names = [obj.name for obj in queryset]
        return Response(names)


class ProjectViewSet7(viewsets.ModelViewSet):
    serializer_class = serializers.ProjectModelSerializer
    # queryset = Project.objects.all().order_by('id')     # 设置默认id排序
    queryset = Project.objects.all()
    search_fields = ['name', 'leader']
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    pagination_class = PageNumberPagination
    ordering_fields = ['name', 'id', 'leader']

    # 在settings.py文件中'ORDERING_PARAM': 'ordering'是给drf框架的排序引擎设置的参数,
    # ordering_fields允许用户指定排序字段'name', 'id', 'leader'
    # 这个是相关的请求方法示例,http:/localhost/projects/?page=2&page_size=3&ordering=-id
    """
    使用router自动生成路由条目,对于非默认的action不能生成路由,之能对默认的action生成路由条目(retrieve、update、destroy、list、create、partrial_update)
    非默认的action,例如下面的name_detail和names,需要添加action装饰器进行装饰,装饰完以后,才能实现自动添加到路由中,
    @action(methods=['get'], detail=True, url_path='details', url_name='details')
        1.装饰器中method不是必传参数,method必须是列表,
    默认是get,可以为其添加多个方法,get、post等都支持。
        2.detail是必传参数,detail=True,表示获取的是详情信息,url中需要传PK信息,相当于单查;
    detail=False,url中不需要传PK信息,相当于群查。
        3.url_path参数默认值是被装饰的函数名称,表示路径中用到的是该函数的名称,也可以修改为其他值
        4.url_name参数使用的值是自动生成的路由路径最后面proje后的值,默认可以不设置该参数。
        http://localhost:8000/projects/(?P<pk>[^/.]+)/details/$ [name='proje-details']
        router.register(r'projects', views.ProjectViewSet7, basename='proje')
        自动路由器设置的basename='proje'参数,会映射到上面的url路径[name='proje-details']最后面的参数中。
    
    """
    @action(methods=['get'], detail=True, url_path='details', url_name='details')
    # 设置action信息以后,请求的url如下所示
    # http://localhost:8000/projects/(?P<pk>[^/.]+)/details/$ [name='proje-details']
    def name_detail(self, request, *args, **kwargs):
        instance = self.get_object()
        return Response({
            'id': instance.id,
            'name': instance.name
        })

    @action(methods=['get'], detail=False, url_path='nameslist', url_name='nameslist')
    # 设置action信息以后,请求的url如下所示
    # http://localhost:8000/projects/nameslist/$ [name='proje-nameslist']
    def names(self, request, *args, **kwargs):
        # queryset = self.get_queryset()
        # 1.如果设置的是self.get_queryset()获取的查询集,就不支持上面的过滤和排序功能
        # http://localhost/projects/names_list/?search=11&ordering=id 进行请求时,后面的排序和过滤不起作用

        queryset = self.filter_queryset(self.get_queryset())
        # 2.如果设置的是self.filter_queryset(self.get_queryset())调用filter_queryset进行过滤,获取的查询集,
        # http://localhost/projects/names_list/?search=11&ordering=id 就支持设置的过滤和排序功能
        names = [obj.name for obj in queryset]
        return Response(names)


# 设置该视图类不支持删除方法
class ProjectViewSet8(mixins.ListModelMixin,
                     mixins.CreateModelMixin,
                     mixins.RetrieveModelMixin,
                     mixins.UpdateModelMixin,
                     viewsets.GenericViewSet):
    serializer_class = serializers.ProjectModelSerializer
    queryset = Project.objects.all()
    search_fields = ['name', 'leader', 'desc', 'interfaces__name']
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    pagination_class = PageNumberPagination
    ordering_fields = ['name', 'id', 'leader']
    # 设置访问权限
    permission_classes = [permissions.IsAuthenticated]
    # permissions.IsAdminUser
    # permissions.IsAuthenticatedOrReadOnly

    # def retrieve(self, request, *args, **kwargs):
    #     instance = self.get_object()
    #     serializer = self.get_serializer(instance=instance)
    #     return Response(serializer.data, status=status.HTTP_200_OK)
    #
    # def update(self, request, *args, **kwargs):
    #     serializer = self.get_serializer(data=request.data, instance=self.get_object())
    #     serializer.is_valid(raise_exception=True)
    #     serializer.save()
    #     return Response(serializer.data, status=status.HTTP_201_CREATED)
    #
    # def destory(self, request, *args, **kwargs):
    #     instance = self.get_object()
    #     instance.delete()
    #     return Response(None, status=status.HTTP_204_NO_CONTENT)
    #
    # 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(instance=page, many=True)
    #         return self.get_paginated_response(serializer.data)
    #
    #     serializer = self.get_serializer(instance=queryset, many=True)
    #     return Response(data=serializer.data, status=status.HTTP_200_OK)
    #
    # def create(self, request, *args, **kwargs):
    #     serializer = self.get_serializer(data=request.data)
    #     serializer.is_valid(raise_exception=True)
    #     serializer.save()
    #     return Response(data=serializer.data, status=status.HTTP_201_CREATED)

    @action(methods=['get'], detail=True, url_path='names', url_name='names')
    def name_detail(self, request, *args, **kwargs):
        instance = self.get_object()
        return Response({
            'id': instance.id,
            'name': instance.name
        })

    @action(detail=False, url_path='names', url_name='names')
    def names(self, request, *args, **kwargs):
        # 第一次改造
        # 1.过滤
        # queryset = self.filter_queryset(self.get_queryset())
        # queryset = self.get_queryset()
        # 2.序列化输出
        # data = [ obj.name for obj in queryset]
        # return Response(data)
        # serializer = self.get_serializer(instance=queryset, many=True)
        # return Response(serializer.data)

        # 第二次改造
        # return self.list(request, *args, **kwargs)

        # 第四次改造
        response: Response = self.list(request, *args, **kwargs)
        data_lst = [d.get('name') for d in response.data]
        response.data = data_lst
        return response

    # 第三次改造
    def paginate_queryset(self, queryset):
        if self.action == 'names':
            return None
        else:
            return super().paginate_queryset(queryset)

    def get_serializer_class(self):
        if self.action == 'names':
            return serializers.ProjectNameListModelSerializer
        else:
            return super().get_serializer_class()

    def filter_queryset(self, queryset):
        if self.action == 'names':
            return queryset
        else:
            return super().filter_queryset(queryset)









posted @ 2025-11-22 20:50  大海一个人听  阅读(0)  评论(0)    收藏  举报