【django2.0之Rest_Framework框架一】rest_framework序列器介绍

Django RestFramework(简称DRF) 提供了序列化器Serialzier的定义,可以帮助我们简化序列化与反序列化的过程,不仅如此,还提供丰富的类视图、扩展类、视图集来简化视图的编写工作。REST framework还提供了认证、权限、限流、过滤、分页、接口文档等功能支持。

github地址: https://github.com/encode/django-rest-framework

中文文档:https://q1mi.github.io/Django-REST-framework-documentation/#django-rest-framework

1 项目基础搭建

1.1 安装DRF

shell 复制代码
pip install Django==2.0.13
pip install djangorestframework==3.10.3
pip install PyMySQL==1.0.2

1.2 创建django项目

shell 复制代码
django-admin startproject drfdemo
# 创建应用
python manage.py startapp students

settings.pyINSTALLED_APPS中添加'rest_framework'和其他子应用:

python 复制代码
INSTALLED_APPS = [
    ...
    'rest_framework',
    'students',
]

1.3 models和数据库设置

students/models.py 文件内容

python 复制代码
class Student(models.Model):
    # 模型字段
    name = models.CharField(max_length=100,verbose_name="姓名")
    sex = models.BooleanField(default=1,verbose_name="性别")
    age = models.IntegerField(verbose_name="年龄")
    class_null = models.CharField(max_length=5,verbose_name="班级编号")
    description = models.TextField(max_length=1000,verbose_name="个性签名")

    class Meta:
        db_table="tb_student"
        verbose_name = "学生"
        verbose_name_plural = verbose_name

创建本地数据库,并在django项目中进行mysql链接
settings.py文件修改DATABASES内容:

python 复制代码
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': "rest_django_stu",
        'HOST': '127.0.0.1',
        'PORT': 3306,
        'USER': 'root',
        'PASSWORD': 'root',
    }
}

# 打印每次执行sql时输出 sql语句
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level': 'DEBUG',
        },
    }
}

主引用中__init__.py设置使用pymysql作为数据库驱动

python 复制代码
import pymysql

pymysql.install_as_MySQLdb()

在本地创建测试数据库:

shell 复制代码
# 连接本地mysql后执行
create database rest_django_stu charset=utf8;

# 终端下执行数据迁移
python manage.py makemigrations
python manage.py migrate

2 序列化器-Serializer的基础使用

  1. 序列化:序列化器会把模型对象转换成字典,经过response以后变成json字符串
  2. 反序列化:把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
  3. 反序列化可以完成数据校验功能

2.1 定义序列化器

子应用下新建serializer.py文件,内容:

python 复制代码
from rest_framework import serializers

# 声明序列化器,所有的序列化器都要直接或者间接继承于 Serializer
class StudentSerializer(serializers.Serializer):
    """学生信息序列化器"""
    # 1. 需要进行数据转换的字段
    id = serializers.IntegerField()
    name = serializers.CharField()
    age = serializers.IntegerField()
    sex = serializers.BooleanField()
    description = serializers.CharField()

注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。 serializer是独立于数据库之外的存在。

常用字段类型

字段 字段构造方式
BooleanField BooleanField()
NullBooleanField NullBooleanField()
CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugField SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
URLField URLField(max_length=200, min_length=None, allow_blank=False)
UUIDField UUIDField(format='hex_verbose') format: 1) 'hex_verbose'"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex'"5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
IPAddressField IPAddressField(protocol='both', unpack_ipv4=False, **options)
IntegerField IntegerField(max_value=None, min_value=None)
FloatField FloatField(max_value=None, min_value=None)
DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置
DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DurationField DurationField()
ChoiceField ChoiceField(choices) choices与Django的用法相同
MultipleChoiceField MultipleChoiceField(choices)
FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ListField ListField(child=, min_length=None, max_length=None)
DictField DictField(child=)

选项参数:

参数名称 作用
max_length 最大长度
min_length 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符
max_value 最大值
min_value 最小值

通用的选项参数:

参数名称 说明
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,默认False
required 表明该字段在反序列化时必须输入,默认True
default 反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
validators 该字段使用的验证器
error_messages 包含错误编号与错误信息的字典
label 用于HTML展示API页面时,显示的字段名称
help_text 用于HTML展示API页面时,显示的字段帮助提示信息

2.2 配置url路由分发

python 复制代码
# 全局urls.py文件
from django.contrib import admin
from django.urls import path,re_path,include #  re_path --- django1.11 url

urlpatterns = [
    path('admin/', admin.site.urls),
    path('stu/', include('student.urls')),
]

# 子应用student/urls.py文件
from django.contrib import admin
from django.urls import path,re_path,include #  re_path --- django1.11 url
from ser import views
urlpatterns = [
    path('students/', views.StudentsView.as_view()),  # stu/students/
]

2.3 序列器的序列化功能

在子应用views.py文件中:

python 复制代码
from django.http import JsonResponse
from django.views import View
from .serializers import StudentSerializer
from students.models import Student
class StudentView(View):
    def get(self,request):  # [{},]
        # queryset类型数据
        # students = models.Student.objects.all()  #
        # serializer_obj = StudentSerializer(instance=students,many=True)  # 列表套字典

        # 序列化单条数据(模型类对象)
        students = models.Student.objects.get(id=1)
        serializer_obj = StudentSerializer(instance=students)  #--字典

        print(serializer_obj.data,type(serializer_obj.data))
        return JsonResponse(serializer_obj.data,safe=False,json_dumps_params={'ensure_ascii':False})

定义好Serializer类后,就可以创建Serializer对象了。

Serializer的构造方法为:

python 复制代码
Serializer(instance=None, data=empty, **kwarg)

说明:

1)用于序列化时,将模型类对象传入instance参数

2)用于反序列化时,将要被反序列化的数据传入data参数

3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如

python 复制代码
serializer = AccountSerializer(account, context={'request': request})

通过context参数附加的数据,可以通过Serializer对象的context属性获取。

  1. 使用序列化器的时候一定要注意,序列化器声明了以后,不会自动执行,需要我们在视图中进行调用才可以。
  2. 序列化器无法直接接收数据,需要我们在视图中创建序列化器对象时把使用的数据传递过来。
  3. 序列化器的字段声明类似于我们前面使用过的表单系统。
  4. 开发restful api时,序列化器会帮我们把模型数据转换成字典.
  5. drf提供的视图会帮我们把字典转换成json,或者把客户端发送过来的数据转换字典.

2.4 反序列化功能

python 复制代码
from rest_framework.views import APIView
class StudentsView(APIView):
# class StudentsView(View): # 基础视图类无法接收json数据。
    def post(self,request):
        # print('>>>>>>', request.POST)  #由于用户提交的数据可能是json数据,django解析不了,所有我们借助drf来解析,就需要继承drf的APIView类
        print('>>>>>>', request.data)  #{'name': 'chaochaochao', 'age': 18}字典类型数据

        serializer_obj = StudentSerializer(data=request.data)
        if serializer_obj.is_valid():  #所有字段校验都没问题,返回True,但凡是有一个字段校验失败,返回False
            print('校验成功之后的数据',serializer_obj.validated_data)
            # 然后保存数据
            return JsonResponse(serializer_obj.validated_data)

        else:
            print(serializer_obj.errors)
            return JsonResponse({'error':'校验失败'},status=400)

2.4.1 数据验证

使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。

在获取反序列化的数据前,必须调用**is_valid()**方法进行验证,验证成功返回True,否则返回False。

验证失败,可以通过序列化器对象的errors 属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。

验证成功,可以通过序列化器对象的validated_data属性获取数据。

在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。

python 复制代码
from rest_framework import serializers
class StudentSerializer(serializers.Serializer):
    # 需要转换的字段声明
    # 小括号里面声明主要提供给反序列化使用的
    name = serializers.CharField(required=True, max_length=20)
    age = serializers.IntegerField(max_value=150, min_value=0,required=True)
    sex = serializers.BooleanField(default=True)
    description = serializers.CharField(required=False,allow_null=True, allow_blank=True) #required=False,字段都可以不传递给后端,allow_null=True,允许提交过来的数据为空值(null--None),allow_blank=True 允许提交过来的数据为空字符串

如果觉得这些还不够,需要再补充定义验证行为,可以使用以下三种方法:

2.4.2 局部钩子

validate_字段名 方式

<field_name>字段进行验证,如

python 复制代码
class StudentSerializer(serializers.Serializer):
    """学生数据序列化器"""
    ...

    # 序列化器中可以自定义单个字段的验证方法  def validate_<字段名>(用户提交的字段数据):
    def validate_name(self,data):
        if(data=="老男孩"):
            raise serializers.ValidationError("用户名不能是老男孩")

        # 验证完成以后务必要返回字段值
        return data

2.4.3 全局钩子

在序列化器中需要同时对多个字段进行比较验证时,可以定义validate方法来验证

python 复制代码
class StudentSerializer(serializers.Serializer):
    """学生数据序列化器"""
    ...
		
    # 方法名时固定的,用于验证多个字段,参数就是实例化序列化器类时的data参数
    def validate(self,data):
        name = data.get("name")
        if(name == "python"):
            raise serializers.ValidationError("用户名不能是python")

        age = data.get("age")
        if(age==0):
            raise serializers.ValidationError("年龄不能是0")

        # 验证完成以后务必要返回data
        return data

2.4.4 自定义检验函数

在字段中添加validators选项参数,也可以补充验证行为

python 复制代码
def check_age(age):
    if age ==50:
        raise serializers.ValidationError("年龄不能刚好是50")
    return age

class StudentSerializer(serializers.Serializer):
    # 需要转换的字段声明
    # 小括号里面声明主要提供给反序列化使用的
    name = serializers.CharField(required=True, max_length=20)
    age = serializers.IntegerField(max_value=150, min_value=0,required=True,validators=[check_age])
    sex = serializers.BooleanField(default=True)
    description = serializers.CharField(required=False,allow_null=True, allow_blank=True)

3 序列化器 保存和修改数据库

前面的验证数据成功后,我们可以使用序列化器来完成数据反序列化的过程.这个过程可以把数据转成模型类对象.

3.1 保存和修改方式

首先我们可以在views中直接写上保存数据的代码

python 复制代码
# views.py 方式一
from django.http import JsonResponse
from django.views import View
from .serializers import StudentSerializer
from students.models import Student
class StudentView(View):
    def post(self,request):
        """添加一个学生"""
        # 接受参数
        post_data = request.POST
        data = {
            "name":post_data.get('name'),
            "age":post_data.get('age'),
            "sex":post_data.get('sex'),
            "description":post_data.get('description'),
        }
        serializer = StudentSerializer(data=data)
				serializer.errors  
        result = serializer.is_valid(raise_exception=True)
        print( "验证结果:%s" % result )
        print( serializer.validated_data ) 
        
        student = Student.objects.create(
            name=serializer.validated_data.get("name"),
            age=serializer.validated_data.get("age"),
            sex=serializer.validated_data.get("sex")
        )

        print(student)
        return JsonResponse({"message": "ok"})

还可以通过序列化器提供的create()和update()两个方法来实现。

python 复制代码
from rest_framework import serializers
from students.models import Student

class StudentSerializer(serializers.Serializer):
    # 需要转换的字段声明
    # 小括号里面声明主要提供给反序列化使用的
    name = serializers.CharField(required=True, max_length=20)
    age = serializers.IntegerField(max_value=150, min_value=0,required=True)
    sex = serializers.BooleanField(default=True)
    description = serializers.CharField(required=False,allow_null=True, allow_blank=True) #required=False,

    # 添加和更新代码
    # 序列化器中会提供了两个方法: create 和 update,方法名是固定的
    def create(self, validated_data): # validated_data 参数,在序列化器调用时,会自动传递验证完成以后的数据
        student = Student.objects.create(
            name=self.validated_data.get("name"),
            age=self.validated_data.get("age"),
            sex=self.validated_data.get("sex")
        )

        return student

    def update(self,instance,validated_data): #instance表示当前更新的记录对象
        """更新学生信息"""
        instance.name=validated_data.get("name")
        instance.sex=validated_data.get("sex")
        instance.age=validated_data.get("age")
        instance.description=validated_data.get("description")
        # 调用模型的save更新保存数据
        instance.save()

        return instance

实现了上述两个方法后,在视图中调用序列化器进行反序列化数据的时候,就可以通过save()方法返回一个数据对象实例了

python 复制代码
from django.http import JsonResponse
from django.views import View
from .serializers import StudentSerializer
from students.models import Student
class StudentView(View):
    def put(self,request):
        """更新学生信息"""
        # 接受参数
        data = {
            "id":9,
            "name":"abc",
            "age":18,
            "sex":1,
            "description":"测试",
        }
        # 获取要修改的数据
        instance = Student.objects.get(pk=data.get("id"))
        # 调用序列化器
        serializer = StudentSerializer(instance=instance,data=data)
        # 验证
        serializer.is_valid(raise_exception=True)
        # 转换成模型数据 如果是添加,自动会调用create,更新就自动调用update
        student = serializer.save()

        return JsonResponse({"message": "ok"})

如果创建序列化器对象的时候,没有传递instance实例,则调用save()方法的时候,create()被调用,相反,如果传递了instance实例,则调用save()方法的时候,update()被调用。

3.2 说明

1) 在对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()和update()中的validated_data参数获取到

python 复制代码
# request.user 是django中记录当前登录用户的模型对象
serializer.save(owner=user)

2)默认序列化器必须传递所有required的字段,否则会抛出验证异常。但是我们可以使用partial参数来允许部分字段更新(只检验传来的数据

python 复制代码
# 更新学生的部分字段信息,当数据库允许为空,但是序列化器要求必须字段填写的时候,可以使用以下方式避开
serializer = StudentSerializer(instance=instance, data=data, partial=True)

把上面序列化器子应用sers和反序列化器子应用users里面的序列化器进行对比。

python 复制代码
from rest_framework import serializers

class StudentSerializer(serializers.Serializer):
    """学生信息序列化器"""
    # 1. 需要进行数据转换的字段
    id = serializers.IntegerField()
    name = serializers.CharField()
    age = serializers.IntegerField()
    sex = serializers.BooleanField()
    description = serializers.CharField()
python 复制代码
from rest_framework import serializers
from students.models import Student

class StudentSerializer(serializers.Serializer):
    # 需要转换的字段声明
    # 小括号里面声明主要提供给反序列化使用的
    name = serializers.CharField(required=True, max_length=20)
    age = serializers.IntegerField(max_value=150, min_value=0,required=True)
    sex = serializers.BooleanField(default=True)
    description = serializers.CharField(required=False, allow_null=True, allow_blank=True)

    # 添加和更新代码
    # 序列化器中会提供了两个方法: create 和 update,方法名是固定的
    def create(self, validated_data): # validated_data 参数,在序列化器调用时,会自动传递验证完成以后的数据
        student = Student.objects.create(
            name=self.validated_data.get("name"),
            age=self.validated_data.get("age"),
            sex=self.validated_data.get("sex")
        )

        return student

    def update(self,instance,validated_data):
        """更新学生信息"""
        instance.name=validated_data.get("name")
        instance.sex=validated_data.get("sex")
        instance.age=validated_data.get("age")
        instance.description=validated_data.get("description")
        # 调用模型的save更新保存数据
        instance.save()

        return instance

可以发现,反序列化器中的代码会包含了序列化器中的大部分代码,除了ID字段的声明。

所以在开发的时候,我们一般都是直接写在一起,那么有些字段只会出现在序列化器阶段,例如ID。还有些字段只会出现在反序列化阶段,例如:用户密码。

那么, 我们需要在序列化器类中,声明那些字段是在序列化时使用,哪些字段在反序列化中使用了。

最终序列化器中的代码:

python 复制代码
from rest_framework import serializers
from students.models import Student

class StudentSerializer(serializers.Serializer):
    # 需要转换的字段声明
    # 小括号里面声明主要提供给反序列化使用的
    id=serializers.IntegerField(read_only=True)  #read_only=True读取数据时能读出来,反序列化校验数据的时候不需要校验。
    name = serializers.CharField(required=True, max_length=20)
    age = serializers.IntegerField(max_value=150, min_value=0,required=True)
    sex = serializers.BooleanField(default=True,write_only=True)#write_only=True读取数据时不能读出来。但是反序列化校验数据保存时,需要传给我们的序列化器
    description = serializers.CharField(required=True, allow_null=True, allow_blank=True)
   
    # 添加和更新代码
    # 序列化器中会提供了两个方法: create 和 update,方法名是固定的
    def create(self, validated_data): # validated_data 参数,在序列化器调用时,会自动传递验证完成以后的数据
        student = Student.objects.create(
            name=self.validated_data.get("name"),
            age=self.validated_data.get("age"),
            sex=self.validated_data.get("sex")
        )

        return student

    def update(self,instance,validated_data):
        """更新学生信息"""
        instance.name=validated_data.get("name")
        instance.sex=validated_data.get("sex")
        instance.age=validated_data.get("age")
        instance.description=validated_data.get("description")
        # 调用模型的save更新保存数据
        instance.save()

        return instance

4. 模型类序列化器

如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。

ModelSerializer与常规的Serializer相同,但提供了:

  • 基于模型类自动生成一系列字段
  • 基于模型类自动为Serializer生成validators,比如unique_together
  • 包含默认的create()update()的实现

子应用下创建一个StudentModelSerializer.py 文件

python 复制代码
from rest_framework import serializers
from students.models import Student
class StudentModelSerializer(serializers.ModelSerializer):
    # 字段声明

    # 如果模型类序列化器,必须声明本次调用是哪个模型,模型里面的哪些字段
    class Meta:
        model = Student # model 指明参照哪个模型类
        fields = ["id","name","age","description","sex"]
        # fields = "__all__" # 表示操作模型中的所有字段
        # 添加额外的验证选项
        exclude = ['id',] # 排除字段
        extra_kwargs = {
            "sex":{"write_only":True,},
            "id":{"read_only":True,}
        }

4.1 可用字段

  1. 使用fields 来明确字段,__all__表名包含所有字段,也可以写明具体哪些字段,如
python 复制代码
class StudentModelSerializer(serializers.ModelSerializer):
    """学生数据序列化器"""
    class Meta:
        model = Student
        fields = ['id', 'age', 'name',"description"]
  1. 使用exclude可以明确排除掉哪些字段
python 复制代码
class StudentModelSerializer(serializers.ModelSerializer):
    """学生数据序列化器"""
    class Meta:
        model = Student
        exclude = ['sex']
  1. 指明只读字段[少用,通过extra_kwargs更方便一些
    可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段
python 复制代码
class StudentModelSerializer(serializers.ModelSerializer):
    """学生数据序列化器"""
    class Meta:
        model = Student
        fields = ['id', 'age', 'name',"description"]
        read_only_fields = ('id',)
        #write_only_fields = ('sex',)
  1. 额外参数extra_kwargs
    我们可以使用extra_kwargs 参数为ModelSerializer添加或修改原有的选项参数
python 复制代码
from rest_framework import serializers
from students.models import Student
class StudentModelSerializer(serializers.ModelSerializer):
    # 额外字段声明,必须在fields里面也要声明上去,否则序列化器不会调用
    password = serializers.CharField(write_only=True,required=True) #加上write_only的字段可以直接删除

    # 如果模型类序列化器,必须声明本次调用是哪个模型,模型里面的哪些字段
    class Meta:
        model = Student
        # fields = ["id","name","age","description","sex","password"]
        fields = ["id","name","age","description","sex"]
        # fields = "__all__" # 表示操作模型中的所有字段
        # 添加额外的验证选项,比如额外的字段验证
        extra_kwargs = {
            "sex":{"write_only":True,},
            "id":{"read_only":True,}
        }

示例:接收额外参数,进行检验,但不保存

python 复制代码
# serializers.py
from rest_framework import serializers
from ser import models
class StudentModelSerializer(serializers.ModelSerializer):
    password = serializers.CharField(max_length=5) # 接收额外password
    
    class Meta:
        model = models.Student
        fields = ['name', 'age', 'password','class_null','sex', 'description']
        extra_kwargs = {
            'id':{'read_only':True},
            'name':{
                'max_length':5,
                # 定制错误信息
                'error_messages': {
                    'max_length':'name不能超过5个字符',
                },
                # 自定义校验函数
                # 'validators':[]
            },
        }

    # 局部钩子
    def validate_password(self,data):
        if '666' in data:
            raise serializers.ValidationError('密码里不能含有666')
        return data

# views.py
from django.shortcuts import render
from rest_framework.views import APIView
from ser import models
from mser.serializers import StudentModelSerializer
from django.http import JsonResponse

class StudentsView(APIView):

    def get(self,request):
        all_student = models.Student.objects.all()  #[{},]
        serializer_obj = StudentModelSerializer(instance=all_student,many=True)
        return JsonResponse(serializer_obj.data,safe=False)

    def post(self,request):
        serializer_obj = StudentModelSerializer(data=request.data)
        print(serializer_obj.is_valid())
        if serializer_obj.is_valid():
            print('>>>>>>>',serializer_obj.validated_data)
            # 保存之前进行删除
            serializer_obj.validated_data.pop('password')
            obj = serializer_obj.save()
            new_obj = StudentModelSerializer(instance=obj)
            return JsonResponse(new_obj.data)

        else:
            print(serializer_obj.errors)
            return JsonResponse({'error':'校验失败'})
相关推荐
databook3 小时前
Manim实现闪光轨迹特效
后端·python·动效
Juchecar5 小时前
解惑:NumPy 中 ndarray.ndim 到底是什么?
python
用户8356290780515 小时前
Python 删除 Excel 工作表中的空白行列
后端·python
Json_5 小时前
使用python-fastApi框架开发一个学校宿舍管理系统-前后端分离项目
后端·python·fastapi
数据智能老司机12 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机13 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机13 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机13 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i13 小时前
drf初步梳理
python·django
每日AI新事件13 小时前
python的异步函数
python