serializers.ModelSerializer进行序列化和反序列化时,只传递instance和只传递data以及同时传递instance和data参数作为序列化输出和反序列化输入的数据源

不同方式定义的序列化器对象的区别?
** 1.如果在创建序列化器对象时,仅仅只传递instance参数,那么当前只会进行序列化输出操作,不可能进行反序列化输入操作,**
** 不可以调用序列化器对象的save()的方法**
** 2.如果在创建序列化器对象时,仅仅只传递data参数,那么在调用is_valid()方法后会进行反序列化输入操作,**
** 同时在调用save方法时,会自动调用序列化器对象的create方法(用于数据的创建操作),会把create方法返回的数据作为**
** 序列化输出的数据源**
** 3.如果在创建序列化器对象时,仅仅只传递data参数,调用is_valid()方法,对数据进行校验之后,直接调用data属性(未调用save方法),**
** 会把校验通过的数据作为序列化输出的数据源,如果校验通过的数据中有相应的数据,同时该字段需要输出,那么输出的数据中才会有该字段**
** 4.如果在创建序列化器对象时,!!!同时传递instance和data参数!!!,调用is_valid()方法,对数据进行校验,那么在调用save方法时,**
** 会自动调用序列化器对象的update方法(用于数据的更新操作),会把update方法返回的数据作为序列化输出的数据源。**

urls.py 内容
from django.urls import path, re_path

from . import views
# from .views import ProjectView, index, detail
# 定义app_name的值,用于给路由添加命名空间
# 作用:当项目中有多个应用时,可以通过命名空间来区分不同应用中的路由
# 例如:当项目中有两个应用,分别为projects和interfaces,且两个应用中都有get_project视图函数
app_name = 'projects'

urlpatterns = [
    path('projects/<int:pk>/', views.ProjectDetailView.as_view()),
    path('projects/', views.ProjectView.as_view()),
]

models.py文件
from django.db import models

from utils.base_model import BaseModel


class People(models.Model):
    """
    1、必须继承Model或者Model子类
    2、一个ORM模型类就对应了一个数据库中的一张表
    3、在ORM模型类中定义类属性,并且类属性必须是Field的子类,与数据表中的字段对应
    4、CharField类与mysql中的varchar对应,并且必须得指定max_length参数(指定当前字段的最大字节数)
    5、IntegerField类与mysql中integer对应为整型
    6、ORM模型类会自动创建一个名为id的自增主键(非空、唯一),且为integer类型
    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”)
    """
    username1 = models.CharField(max_length=20)
    age = models.IntegerField()
    gender = models.BooleanField(default=True)


class Project(BaseModel):
    # a.如果ORM模型类中某个字段指定了primary_key=True,那么ORM框架就不会自动生成名称为id的自增主键
    # b.会把指定了primary_key=True的字段作为主键
    # c.创建的ORM模型类中字段默认primary_key=False,为非主键字段
    # d.verbose_name和help_text指定当前字段的描述信息,一般在api接口文档平台、后台管理站点、前端渲染的表单中会显示
    # 区别
    # verbose_name主要用于提供字段的人类可读名称,改善字段的显示效果。
    # help_text则用于提供字段的额外说明或帮助信息,增加字段的可理解性。
    # 总的来说,这两个参数都是为了提高模型字段在管理后台和表单中的可用性和友好性。
    # verbose_name关注于如何命名字段,而help_text关注于如何解释字段。
    # id = models.IntegerField(primary_key=True, verbose_name="id主键", help_text='为id主键字段')
    # e.使用unique=True为当前字段指定唯一约束,默认创建的ORM模型类字段unique=False(可重复)
    name = models.CharField(verbose_name='项目名称', help_text='输入项目名称', unique=True,
                            max_length=50)
    # f.使用null=True,指定当前字段在数据库中是否可以存储NULL值,默认该字段在数据库中必须有一个值
    leader = models.CharField(verbose_name='项目负责人', help_text='输入项目负责人',
                              max_length=20, null=True)
    # g.使用default=True,为当前字段指定默认值,指定默认值之后,前端创建数据时,如果不指定该字段,那么会自动将默认值作为当前字段的值
    is_execute = models.BooleanField(verbose_name='是否启动项目', help_text='请选择是否启动项目',
                                     default=True)
    # h.使用blank=True,指定前端在创建数据时,可以不用传递该字段(在后面序列化器类中使用),
    # 指定字段在表单验证时是否可以为空,如果blank=True,则该字段在表单验证时允许为空
    # 如果blank=False(默认值),则该字段在表单验证时必须有一个值
    desc = models.TextField(verbose_name='项目描述', help_text='输入项目描述',
                            null=True, blank=True)

    # i.可以为DateTimeField、DateField字段添加auto_now_add、auto_now参数
    #   》auto_now_add=True指定在创建该记录时,会自动将当前创建的时间作为该字段的值,后续不会变更
    #   》auto_now=True在每次更新该记录时,会自动将当前更新的时间作为该字段的值,后续只要更新了该记录,都会自动修改
    #   》auto_now_add和auto_now不能同时指定
    # create_time = models.DateTimeField(verbose_name='创建时间', help_text='这是创建时间,会自动设置',
    #                                    auto_now_add=True)
    # update_time = models.DateTimeField(verbose_name='修改时间', help_text='这是修改时间,每次数据改变时会自动更新',
    #                                    auto_now=True)

    class Meta:
        db_table = 'tb_projects'
        verbose_name = '项目表'
        verbose_name_plural = '项目表'
        ordering = ['id']
        # ordering = ['-id', 'name', '?leader']
        # ordering = ['-leader', 'name']

    def __str__(self):
        return f'Project<id={self.id}, name={self.name}, leader={self.leader}>'

serializers.py文件
from rest_framework import serializers, validators
from . import models
from interfaces.models import Interfaces


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


class InterfaceXXX(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField()
    projects = serializers.StringRelatedField()


class ProjectSerializer(serializers.Serializer):
    """
    为什么需要使用序列化器类?
    1.可以实现序列化输出操作
    2.可以实现反序列化输入操作
    3.数据校验操作
    4.数据库操作

    如何定义序列化器类?
    1.一般在子应用中创建serializers.py文件,用于定义序列化器类
    2.必须继承Serializer类或者Serializer的子类
    3.序列化输出的参数名要与创建的序列化器字段(序列化器类中的类属性)名称保持一致
    4.序列化输出的参数类型要与创建的序列化器字段(序列化器类中的类属性)类型保持一致
    5.序列化器字段必须为Field子类
    6.序列化器字段类型种类?
        a.IntegerField  -> int
        b.CharField     -> str
        c.BooleanField  -> bool

    如何使用序列化器类实现序列化输出操作?
    1.先创建序列化器对象
    2.在创建序列化器对象时,使用instance传递参数
    3.序列化操作的对象有四种?
        a.模型对象             -- 无需传递many关键字参数
        b.普通对象             -- 无需传递many关键字参数
        c.查询集               -- 必须传递many=True
        d.嵌套普通对象的列表   -- 必须传递many=True
    4.使用创建序列化器对象.data属性获取序列化之后的数据(字典或者嵌套字典的列表)

    定义的序列化器字段以及常用参数?
    1.默认定义的序列化器字段,都会进行序列化输出
    2.定义的序列化器字段名称和类型必须与模型类中的字段名或者普通对象的属性名保持一致
    3.公共的参数
        a.label、help_text与ORM模型类中的verbose_name、help_text参数一致
        b.如果当前字段仅仅只需反序列化输入,可以设置write_only=True
        c.如果当前字段仅仅只需序列化输出,可以设置read_only=True
        d.required指定某个字段是否为必传字段,默认required=True,默认定义的字段为必传字段
        e.如果required=False,那么该字段为可选参数,如果前端未传递,那么序列化输出时不会输出,如果前端有传递,那么序列化输出时会输出
        f.如果同时设置required=False和write_only=True,那么write_only=True参数会被忽略
        g.如果同时设置required=False和read_only=True,那么read_only=True参数会被忽略
        h.default给某个字段指定默认值
        i.如果给某个字段指定了默认值,那么前端未传递该字段,会把该字段作为输入值,如果指定了该字段,那么会使用该字段作为输入值
        j.某个字段不同同时指定default=True, required=True
        k.allow_null指定某个字段是否允许传递null值,默认不允许传递null值,如果指定了allow_null=True,那么允许该值传递null
        l.error_messages可以定制字段的具体错误提示信息,该参数必须传递字典类型,将具体校验规则名称作为key,把报错提示字符串作为value
        m.validators参数指定自定义校验规则(校验器),为列表类型
        n.可以使用DRF提供的UniqueValidator对字段是否唯一性进行校验,queryset参数为所有模型对象的查询集,message指定校验失败的错误提示信息
        o.可以在序列化器类外定义校验函数,作为validators参数值列表中的元素(使用校验函数名)
        p.定义校验函数,必须接受一个参数(待校验的值),如果校验不通过,必须得抛出serializers.ValidationError异常,
            可以指定具体的报错字符串作为ValidationError参数,如果校验通过,无需返回
        q.某个字段的校验顺序:
            当前字段的类型 ->
            当前字段的所有校验规则项进行校验
            (字段的所有校验关键字参数、validators参数列表中的所有校验规则一般都会被校验)
            -> 单字段校验方法
        r.可以在类里面对单字段进行校验
            》单字段校验的方法名称必须为validate_该字段名称
            》仅仅只有当定义的字段上所有校验规则通过的情况下,才会在类里面调用对单字段进行校验的方法

    4.CharField类型字段
        a.默认该字段不允许传递空字符串
        b.可以指定allow_blank=True,那么允许该字段传递空字符串
        c.max_length指定最大长度字节数,min_length指定最小字节长度
        d.如果前端传递该字段值为str, int, float,会自动转化为字符串类型(不会对类型进行校验),如果传递其他类型,会校验失败(invalid)
        e.trim_whitespace参数默认为True,会自动清空左右两侧的空格

    5.IntegerField类型字段
        a.max_value参数指定最大值
        c.min_value参数指定最小值

    6.DateTimeField类型字段
        a.format指定格式化字符串

    如何使用序列化器类实现反序列化输入操作?
    1.在创建序列化器对象时,使用data传递待校验的参数(需要接收json转化为字典之后的数据)
    2.传递给data的参数,必须为待校验的字典数据
    3.必须得调用序列化器对象.is_valid()方法,才会开始对数据进行校验
    4.仅仅只有调用is_valid()方法之后,才能通过序列化器对象.errors属性获取校验的结果(一般字典类型)
        仅仅只有调用is_valid()方法之后,才能通过序列化器对象.validated_data属性获取校验通过的数据(一般字典类型)
    5.默认定义的序列化器字段,都会进行反序列化输入(前端都必须得传递),也会进行序列化输出操作
        read_only = False
        write_only = False
    6.往往把前后向后端发起请求的过程称为写(write),也称为反序列化输入
    7.往往把后端向前端响应数据的过程称为读(read),也称为序列化输出
    8.如果当前字段仅仅只需反序列化输入,可以设置write_only=True
    9.如果当前字段仅仅只需序列化输出,可以设置read_only=True
    10.可以在调用序列化器对象.is_valid()方法时,指定raise_exception=True,那么校验不通过时,会抛出异常,否则不会抛出异常
    11.如果未调用序列化器对象.is_valid()方法,那么是不会开始校验的,
        所以不能调用序列化器对象的errors属性(获取错误提示字典信息)、data属性(序列化输出的数据)、validated_data属性(获取校验通过的数据)

    # read -> 输出
    # write -> 输入

    在做接口测试时:
        a.不传用户名(required)
        b.用户名传null值(allow_null)
        c.用户名传''空字符串(allow_blank)

    关联字段序列化?
    1.如果需要获取关联表的数据,需要定义RelatedField类型的字段
    2.字段名称有要求
        》如果是父表获取从表的数据,那么关联字段的名称默认为从表模型类名小写_set
        》如果在定义从表模型类外键字段时,指定了related_name参数,那么related_name参数值与关联字段的名称一致
    3.如果关联字段为PrimaryKeyRelatedField,那么操作的关联表的主键id
        》如果需要进行反序列化输入(对数据进行校验),那么必须指定queryset参数,为关联表的查询集对象
        》如果不需要进行反序列化输入,那么必须指定read_only=True
        》如果关联字段的数据有多条,那么必须指定many=True
    4.如果关联字段为StringRelatedField,那么会将关联模型类中定义的__str__方法返回值作为输出内容
        》StringRelatedField默认指定了read_only=True
        》如果关联字段的数据有多条,那么必须指定many=True
    5.如果关联字段为SlugRelatedField,那么操作的关联表的特定字段
        》如果需要进行反序列化输入(对数据进行校验),那么必须指定queryset参数,为关联表的查询集对象,同时关联字段最好要有唯一约束
        》如果不需要进行反序列化输入,那么必须指定read_only=True
        》如果关联字段的数据有多条,那么必须指定many=True
    6.由于定义的任意序列化器类最终为Field子类,所有可以作为任意一个序列化器类中的字段来使用

    """
    # 需求:
    # 在创建项目时,前端不需要传递id,但是必须将项目id返回给前端
    id = serializers.IntegerField(max_value=1000000, min_value=1,
                                  label='项目id', help_text='输出项目id', read_only=True)
    name = serializers.CharField(max_length=50, min_length=2, required=True,
                                 validators=[
                                     # validate_project_name,
                                     validators.UniqueValidator(queryset=models.Project.objects.all(),
                                                                message='项目名称已经存在')])

    leader = serializers.CharField(max_length=20,
                                   error_messages={
                                       'min_length': '项目负责人长度不能少于1个字符',
                                       'max_length': '项目负责人长度不能超过10个字符',
                                       'null': '项目负责人不能为null',
                                       'required': '项目负责人为必填参数',
                                       'blank': '项目负责人不能为空字符串'
                                   },
                                   allow_blank=True,
                                   trim_whitespace=True)

    # 需求:
    # 在创建项目时,前端必须传递is_execute,但是不要将项目is_execute返回给前端
    is_execute = serializers.BooleanField(write_only=True)
    # desc = serializers.CharField()

    create_time = serializers.DateTimeField(read_only=True,
                                            format='%Y年%m月%d日 %H:%M:%S')

    # interfaces_set = serializers.PrimaryKeyRelatedField(queryset=Interfaces.objects.all(), many=True)
    # interfaces = serializers.PrimaryKeyRelatedField(queryset=Interfaces.objects.all(), many=True)
    interfaces = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
    # interfaces = serializers.StringRelatedField(many=True)    # 一个项目有多个接口,所以这里必须指定many=True
    # interfaces = serializers.SlugRelatedField(slug_field='name', read_only=True, many=True)

    # interfaces = InterfaceXXX(read_only=True, many=True)    # 把序列化器类当作字段来使用

    def validate_name(self, value):
        if not str(value).endswith('22'):
            raise serializers.ValidationError('项目名称必须以22结尾')
        return value


class UserSerializer(serializers.Serializer):
    username = serializers.CharField(min_length=5, max_length=20)
    gender = serializers.CharField()
    age = serializers.IntegerField(min_value=0, max_value=150)
    password = serializers.CharField(min_length=6, max_length=50)
    confirm_password = serializers.CharField(min_length=6, max_length=50)

    def validate(self, attrs):
        if attrs.get('password') != attrs.get('confirm_password'):
            raise serializers.ValidationError('输入的密码与确认密码不一致')
        return attrs


class ProjectModelSerializer(serializers.ModelSerializer):
    """
    序列化器类与模型类的关系?
    1.这两个类高度相似
    2.当模型类中字段非常多时,定义序列化器类就相当麻烦
    3.可以定义模型序列化器,来自动将模型类中的字段生成序列化器中的字段
        》必须继承serializers.ModelSerializer父类
        》必须在Meta内部类中,使用model类属性关联一个模型类
        》需要在在Meta内部类中,使用fields指定模型类中哪些字段需要生成序列化器字段
        》如果指定fields = '__all__',那么会将模型类中的所有字段生成序列化器字段
        》在生成的字段中,会将主键id设置为IntegerField类型,同时会自动指定read_only=True
        》会将DateTimeField类型中有添加auto_now_add或auto_now参数,会自动指定read_only=True
        》会将unique=True的字段,自动生成validators中UniqueValidator唯一约束
        !!!模型类中字段设置的属性 --> 对应在序列化器类中字段设置的属性!!!
            》null=True  -> allow_null=True required=False
              blank=True -> allow_blank=True
              default='xxx'  -> required=False
        》如果只需要将模型类中某些字段生成序列化器字段,可以将这些字段组成元组或者列表,传递给fields

        》可以在模型序列化器类中定义模型类中的字段(会覆盖自动生成的字段)
        》fields类属性,如果指定的说元组类型,那么必须包含所有的序列化器字段(模型类中的、模型类外的)
        》如果fields为'__all__'或者exclude,那么无需指定模型类外的字段
        》模型序列化器类自带create、update方法,一般无需重写
        》可以在Meta内部类中的extra_kwargs类属性中对模型类中自动生成的字段进行修改
            将模型类字段名作为key,把具体要修改的参数key-value字典作为值

    不同方式定义的序列化器对象的区别?
    1.如果在创建序列化器对象时,仅仅只传递instance参数,那么当前只会进行序列化输出操作,不可能进行反序列化输入操作,
        不可以调用序列化器对象的save()的方法
    2.如果在创建序列化器对象时,仅仅只传递data参数,那么在调用is_valid()方法后会进行反序列化输入操作,
        同时在调用save方法时,会自动调用序列化器对象的create方法(用于数据的创建操作),会把create方法返回的数据作为
        序列化输出的数据源
    3.如果在创建序列化器对象时,仅仅只传递data参数,调用is_valid()方法,对数据进行校验之后,直接调用data属性(未调用save方法),
        会把校验通过的数据作为序列化输出的数据源,如果校验通过的数据中有相应的数据,同时该字段需要输出,那么输出的数据中才会有该字段
    4.如果在创建序列化器对象时,!!!同时传递instance和data参数!!!,调用is_valid()方法,对数据进行校验,那么在调用save方法时,
        会自动调用序列化器对象的update方法(用于数据的更新操作),会把update方法返回的数据作为序列化输出的数据源。

    """
    # name = serializers.CharField(max_length=50, min_length=2, required=True,
    #                              validators=[
    #                                  # validate_project_name,
    #                                  validators.UniqueValidator(queryset=models.Project.objects.all(),
    #                                                             message='项目名称已经存在')])

    # 需求1:
    #   需要定义一些在模型类中没有的字段(仅仅只进行反序列化输入操作),例如:确认密码
    xxx = serializers.CharField(write_only=True)

    # 需求2:
    #   需要定义一些在模型类中没有的字段(仅仅只进行序列化输出操作),例如:token
    token = serializers.CharField(read_only=True)

    class Meta:
        model = models.Project
        # fields = '__all__'
        fields = ['id', 'name', 'leader', 'is_execute', 'xxx', 'token']
        # exclude = ['create_time', 'update_time']
        extra_kwargs = {
            'name': {
                'min_length': 2,
                'label': '新的label',
                # 'write_only': True,
                # 'validators': [
                #     validate_project_name
                # ],
                # 'error_messages': {
                #      'min_length': '项目负责人长度不能少于1个字符',
                #      'max_length': '项目负责人长度不能超过10个字符',
                #      'null': '项目负责人不能为null',
                #      'required': '项目负责人为必填参数',
                #      'blank': '项目负责人不能为空字符串'
                # },
            }
        }

    def validate(self, attrs: dict):
        # attrs 就是校验通过的数据validated_data
        var = attrs.get('xxx')
        # 对xxx进行校验
        # if var != '密码':
        #     raise serializers.ValidationError('用户输入的确认密码与密码不一致')

        attrs.pop('xxx')
        # attrs['token'] = 'fh ggg'
        return attrs

    # def create(self, validated_data: dict):
    #     validated_data.pop('xxx')
    #     instance = super().create(validated_data)
    #     return instance

    def create(self, validated_data):
        instance = super().create(validated_data)
        # 动态添加属性用于序列化输出
        instance.token = 'xxxdff ghgosfhsoh shfoshof'
        return instance


class ProjectModelSerializer1(serializers.ModelSerializer):
    class Meta:
        model = models.Project
        fields = '__all__'


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


views.py文件
import json

from django.http import HttpResponse, JsonResponse, HttpRequest

# Create your views here.
from django.urls import reverse
from django.views import View
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.request import Request
# drf框架的渲染类
from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
# drf框架的解析类
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser

from .models import Project
# from .serializers import ProjectSerializer
from . import serializers


# class ProjectDetailView(View):
# class ProjectDetailView(APIView):
class ProjectDetailView(GenericAPIView):
    # parser_classes = [JSONParser]
    # lookup_field = 'pk'
    # lookup_url_kwarg = 'ids'
    serializer_class = serializers.ProjectModelSerializer2
    queryset = Project.objects.all()

    # def get_object(self):
    #     data = {
    #         'code': 0,
    #         'msg': '',
    #     }
    #     try:
    #         # return Project.objects.get(id=pk)
    #         pk = self.kwargs.get(self.lookup_field)
    #         return Project.objects.get(id=pk)
    #     except Exception as e:
    #         data['code'] = 1
    #         data['msg'] = f'项目id({pk})不存在'
    #         return Response(data, status=status.HTTP_400_BAD_REQUEST)

    def get_serializer_class(self):
        if self.request.method == 'GET':
            return serializers.ProjectModelSerializer1
        else:
            return self.serializer_class

    def get(self, request, pk):
        """
        数据校验过程
        数据库操作过程
        序列化输出过程
        :param request:
        :param pk:
        :return:
        """

        # data = {
        #     'code': 0,
        #     'msg': '',
        # }
        # try:
        #     # 1、从数据库中获取项目模型对象
        #     project_obj = Project.objects.get(id=pk)
        #     # 2、将模型对象转化为字典
        # except Exception as e:
        #     data['code'] = 1
        #     data['msg'] = f'项目id({pk})不存在'

        instance = self.get_object()
        # serializer = serializers.ProjectModelSerializer(instance=instance)
        # serializer = self.serializer_class(instance=instance)
        serializer = self.get_serializer(instance=instance)
        # data['msg'] = '成功'
        # data.update(serializer.data)
        return JsonResponse(serializer.data, status=200, json_dumps_params={
            'ensure_ascii': False
        })

    def put(self, request, pk):
        """
        反序列化输入过程
        数据校验过程
        数据库操作过程
        序列化输出过程
        :param request:
        :param pk:
        :return:
        """
        # 1、从前端获取项目数据
        # data = {
        #     'code': 0,
        #     'msg': '',
        # }
        #
        # try:
        #     # 从数据库中读取id为pk的项目模型对象
        #     obj = Project.objects.get(id=pk)
        # except Exception as e:
        #     data['code'] = 1
        #     data['msg'] = '项目id不存在'
        #     return JsonResponse(data, status=400, json_dumps_params={'ensure_ascii': False})

        # serializer1 = serializers.ProjectModelSerializer(data=python_dict, instance=obj)
        # serializer = serializers.ProjectModelSerializer(data=request.data, instance=self.get_object())
        serializer = self.get_serializer(data=request.data, instance=self.get_object())
        if not serializer.is_valid():
            return JsonResponse(serializer.errors, status=400, json_dumps_params={'ensure_ascii': False})

        serializer.save()
        return JsonResponse(serializer.data, status=200, json_dumps_params={'ensure_ascii': False})

    def delete(self, request, pk):
        """
        数据校验过程
        数据库操作过程
        :param request:
        :param pk:
        :return:
        """
        # data = {
        #     'code': 0,
        #     'msg': '',
        # }
        #
        # # 1、从数据库中读取id为pk的项目模型对象
        # try:
        #     # 从数据库中读取id为pk的项目模型对象
        #     obj = Project.objects.get(id=pk)
        # except Exception as e:
        #     data['code'] = 1
        #     data['msg'] = '项目id不存在'
        #     return JsonResponse(data, status=400, json_dumps_params={'ensure_ascii': False})

        # 2、项目模型对象调用delete()方法
        instance = self.get_object()
        instance.delete()
        return HttpResponse(None, status=204)


# class ProjectView(View):
# class ProjectView(APIView):
class ProjectView(GenericAPIView):
    """
    可以继承DRF中的APIView视图
    1.APIView为View的子类
    2.每一个get、post、delete、put实例方法的第二个参数为Request对象(rest_framework.request.Request)
    3.Request在Django的HttpRequest之上做了拓展,获取get的参数用request.query_params,获取表单、json、file用request.data
        》与HttpRequest中解析参数的方法完全兼容
        》解析查询字符串参数:GET   ->  query_params
        》解析application/x-www-form-urlencoded参数:POST   ->  data
        》解析application/json参数:body   ->  data
        》解析multipart/form-data参数:POST、FILES   ->  data
    4.提供了认证、授权、限流功能
    5.返回DRF中的Response
        》为HttpResponse子类
        》可以自动根据请求头中的Accept字段,返回相应格式的数据
        》data接受序列化输出的数据(字典、嵌套字典的列表)
        》status指定响应状态码
        》headers修改响应头信息(字典)
    6.解析器类
        》提供针对请求头中Content-Type参数,自动解析请求参数
        》默认的解析器有三种:JSONParser(application/json)、FormParser(application/x-www-form-urlencoded)、
            MultiPartParser(multipart/form-data)
        》有两种方式可以修改使用的解析器类:
            方式一:全局settings.py中REST_FRAMEWORK -> DEFAULT_PARSER_CLASSES中指定需要使用的解析器类
            方式二:在具体某个类视图中指定parser_classes类属性(列表),优先级高于方式一

    7.渲染器类
        》提供针对请求头中Accept参数,自动选择需要的渲染器,将数据以特定的格式返回
        》默认的渲染器类有二种:JSONRenderer(application/json)、BrowsableAPIRenderer(text/html)
            如果未指定Accept或者指定的Accept不为text/html,默认返回json数据
        》有两种方式可以修改使用的解析器类:
            方式一:全局settings.py中REST_FRAMEWORK -> DEFAULT_RENDERER_CLASSES中指定需要使用的渲染器类
            方式二:在具体某个类视图中指定renderer_classes类属性(列表),优先级高于方式一

    8.GenericAPIView类视图
        》是APIView的子类,继承了APIView所有功能(认证、授权、限流、Request、Response、解析器、渲染器)
        》提供了获取列表数据的相关功能(过滤、排序、分页)
        》往往需要指定queryset类属性(定义当前类视图操作的查询集对象)
        》往往需要指定serializer_class类属性(定义了当前类视图使用的公共序列化器类)
        》使用get_queryset()方法获取queryset类属性、使用get_serializer()方法获取serializer_class类属性
        》提供了get_object()方法,获取某一个模型对象
        》在定义url路由时,指定接收主键值的关键字参数名称,默认为pk,如果不为pk的话,必须重写lookup_url_kwarg
        》一般lookup_field类属性不需要修改(默认为pk),指定的是过滤模型对象时,使用的关键词参数名称

    """
    # parser_classes = [FormParser, MultiPartParser]    # 继承APIView类,可以设置支持该类的解析器类型
    # renderer_classes = [JSONRenderer] # 继承APIView类,可以设置该类支持的渲染类类型

    queryset = Project.objects.all()
    serializer_class = serializers.ProjectModelSerializer2

    def get_serializer_class(self):
        if self.request.method == 'GET':
            return serializers.ProjectModelSerializer1
        else:
            return self.serializer_class

    def get(self, request):
        """
        数据库操作过程
        序列化输出过程
        :param request:
        :return:
        """
        # 1、从数据库中读取所有的项目数据(QuerySet对象)
        # queryset = Project.objects.all()
        # queryset = self.queryset
        queryset = self.get_queryset()
        # serializer = serializers.ProjectModelSerializer(instance=queryset, many=True)
        # serializer = self.get_serializer_class()(instance=queryset, many=True)
        serializer = self.get_serializer(instance=queryset, many=True)
        # return JsonResponse(serializer.data, safe=False, json_dumps_params={
        #     'ensure_ascii': False
        # })

        return Response(data=serializer.data, status=status.HTTP_200_OK, headers={
            'xxx': '200'
        })

    # def post(self, request: HttpRequest):
    def post(self, request: Request):
        """
        反序列化输入过程
        数据校验过程
        数据库操作过程
        序列化输出过程

        request.query_params
        request.data
        :param request:
        :return:
        """
        # 1、从前端获取项目数据
        # data = {
        #     'code': 0,
        #     'msg': '',
        # }
        # try:
        #     # 反序列化输入过程:将前端传递的字符串数据转化为python中的数据类型
        #     python_dict = json.loads(request.body)
        # except Exception as e:
        #     data['code'] = 1
        #     data['msg'] = '参数有误'
        #     return JsonResponse(data, status=400, json_dumps_params={'ensure_ascii': False})
        # serializer1 = serializers.ProjectModelSerializer(data=python_dict)

        # serializer = serializers.ProjectModelSerializer(data=request.data)
        serializer = self.get_serializer(data=request.data)
        try:
            serializer.is_valid(raise_exception=True)
        except Exception as e:
            return JsonResponse(serializer.errors, status=400)

        serializer.save()
        # return JsonResponse(serializer.data, status=200, json_dumps_params={'ensure_ascii': False})
        return Response(data=serializer.data, status=status.HTTP_201_CREATED, headers={
            'xxx': '200'
        })



posted @ 2025-11-11 15:44  大海一个人听  阅读(5)  评论(0)    收藏  举报