day-3-4

day-3

使用test.py

  • django app 下面的 test.py 编写测试函数时会报错,主要时引用 django 或 rest_framework 的函数或方法。

  • 报错信息:django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.

  • 解决方法:

    python 复制代码
    # 1. 在 test.py 添加如下
    import os
    import django
    # '../drf_learn02/settings.py' 为 setting.py 的位置
    os.environ.setdefault('DJANGO_SETTING_MODULE', '../drf_learn02/settings.py')
    django.setup()
    # 2. 然后需要修改 Environment variables: 修改为如下内容
    PYTHONUNBUFFERED=1;DJANGO_SETTINGS_MODULE=drf_learn02.settings
    
    Environment variables: 的位置如下图


serializer

Django DRF 序列化器一共有两个类,分别是SerializerModelSerializer,它们都在rest_framework.serializers下面。

对于Serializer,使用时需要将需要被序列化的字段,全部列出并重新赋值,赋值为serializers.xxxFiled(),如果想在序列化的时候更改某个字段,则需要赋值为SerializerMethodField(),并且重写get_xxx()

简单的序列化

python 复制代码
# test.py
import os
import django
os.environ.setdefault('DJANGO_SETTING_MODULE', '../drf_learn02/settings.py')
django.setup()

from rest_framework import serializers
class User:
    def __init__(self,name,age):
        self.name = name
        self.age = age

# 需要将所序列化的字段一一列出,然后使用不同的序列化函数,例如字符串就用 serializers.CharField()
class UserSerializer(serializers.Serializer):
    name = serializers.CharField()
    age = serializers.IntegerField()

if __name__ == "__main__":
    uer = User(name='codeFun',age=18)
    # 直接将需要序列化的对象赋值给 instance 即可
    user_serializer = UserSerializer(instance=uer)
    # 如果序列化多个对象的话,需要添加 many=True
    user_serializer = UserSerializer(instance=uer,many=True)
    # 序列化的数据为 .data
    print(user_serializer.data)  # {'name':'codeFun','age':18}

序列化时更改对象的某些属性,或给对象增加属性

  • 修改 name 属性,使年龄大于18的为 xxx 先生,小于18 为 xxx 同学,并且额外增加 'extend_key'属性。
python 复制代码
import os
import django
os.environ.setdefault('DJANGO_SETTING_MODULE', '../drf_learn02/settings.py')
django.setup()

from rest_framework import serializers
class User:
    def __init__(self,name,age):
        self.name = name
        self.age = age

# 
class UserSerializer(serializers.Serializer):
    # 在序列化时,修改属性的值,该属性的值要等于 SerializerMethodField 并且重写 get_name 方法
    name = serializers.SerializerMethodField()
    age = serializers.IntegerField()
	
    # 这里的 obj 就是需要序列化的对象,在这里是 User 对象,那么他的属性取值 .name 即可。
    # 如果是 querySet 对象,那就应该 .object.xxxx 了
    # 注意返回值,直接为 name 即可
    def get_name(self,obj):
        origin_name = obj.name
        age = obj.age
        if age < 18:
            res_name = origin_name + ' 同学'
        else:
            res_name = origin_name + ' 先生'
        return res_name
	
    # 这里的 instance 还是 User 对象,
    # 此时的 instance.name 还是 codeFun 而不是 codeFun 先生,
    # 需要使用  super().to_representation(instance=instance) 来调用 get_name
    # 然后再在 data 上添加数据。
    # 最后返回 data 即可
    def to_representation(self, instance):
        data = super().to_representation(instance=instance)
        data['extend_key'] = 'extend_value'
        return data

if __name__ == "__main__":
    uer = User(name='codeFun',age=18)
    print(uer.name)
    user_serializer = UserSerializer(instance=uer)
    user2_serializer = User2Serializer(instance=uer)
    print(user_serializer.data)

两张关联的表进行序列化

使用PrimaryKeyRelatedField

python 复制代码
# 比如现在有 user 用户表,car 汽车表,一个用户可以有多辆车那么它们的模型应该时这样的
# models.py

class User(models.Model):
    name = models.CharField(max_length=6, unique=True, verbose_name='姓名')
    age = models.IntegerField(default=0, verbose_name='年龄')

    class Meta:
        db_table = 'tb_user'
        verbose_name = '用户'
        verbose_name_plural = verbose_name
        
class Car(models.Model):
    TYPE_CHOICES = (
        (0, '轿车'),
        (1, 'SUV')
    )
    name = models.CharField(max_length=8, unique=True, verbose_name='名称')
    price = models.DecimalField(max_digits=5, decimal_places=2, default=0, verbose_name='价格')
    type = models.SmallIntegerField(choices=TYPE_CHOICES, verbose_name='类型')
    user = models.ForeignKey(to=User, on_delete=models.CASCADE, verbose_name="用户")

    class Meta:
        db_table = 'tb_car'
        verbose_name = '车辆'
        verbose_name_plural = verbose_name

# 用户的 serialer 可以这样写
class UserSerializer(serializers.Serializer):
    name = serializers.CharField(label='姓名', max_length=6)
    age = serializers.IntegerField(label="年龄")
    # 使用 PrimaryKeyRelatedField 进行关联,输出的是 car id
	car_set = serializers.PrimaryKeyRelatedField(label='拥有车辆',queryset=models.Car,many=True)

OrderedDict([('id', 1), ('car_set', [1, 2, 4]), ('name', 'zhang'), ('age', 18)])
  1. 使用序列化类嵌套
python 复制代码
# 比如还是上面的 user 类 和 car 类
class CarModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Car
        fields = "__all__"

class UserModelSerializer(serializers.ModelSerializer):
    # 直接将 整个序列化类 赋值给 car_set,那么得到的也是一个车(整个车信息)列表,
    car_set = CarModelSerializer(many=True)
    class Meta:
        model = models.User
        fields = "__all__"

[('id', 1), ('car_set', [OrderedDict([('id', 1), ('name', 'su7'), ('price', '17.00'), ('type', 1), ('user', 1)]
  1. 使用StringRelatedField
    1. 需要定义模型类的 __str__函数,定义其返回值。返回值定义什么,car_set 就返回什么
python 复制代码
class Car(models.Model):
    TYPE_CHOICES = (
        (0, '轿车'),
        (1, 'SUV')
    )
    name = models.CharField(max_length=8, unique=True, verbose_name='名称')
    price = models.DecimalField(max_digits=5, decimal_places=2, default=0, verbose_name='价格')
    type = models.SmallIntegerField(choices=TYPE_CHOICES, verbose_name='类型')
    user = models.ForeignKey(to=User, on_delete=models.CASCADE, verbose_name="用户")

    class Meta:
        db_table = 'tb_car'
        verbose_name = '车辆'
        verbose_name_plural = verbose_name

    def __str__(self):
        return "name:{},price:{}".format(self.name,self.price)

class UserModelSerializer(serializers.ModelSerializer):
    car_set = serializers.StringRelatedField(many=True,label="拥有车辆")
    class Meta:
        model = models.User
        fields = "__all__"

[('id', 1), ('car_set', ['name:su7,price:17.00', 'name:su8,price:18.00', 'name:su10,price:18.00']

简单的反序列化

  • 反序列化一般是将数据保存到数据库才需要反序列化。
  • 步骤:
    1. 创建序列化对象
      • 新增只需要传入 data 即可
      • 修改需要传入 instance(被修改的对象),以及 data
      • 如果在修改时,反序列化的 data 不全,可以加上 partial=True字段
    2. 验证数据的合法性.is_valid()
      • 如果不合法,.errors可以查看不合法原因
    3. 将数据进行保存.save()
      • 新增调用序列化类的create方法
      • 修改调用序列化类的update方法
python 复制代码
class UserModelSerializer(serializers.ModelSerializer):
	# 如果不需要传入该字段需要设置 required=False !!!
    car_set = serializers.StringRelatedField(many=True,label="拥有车辆",required=False)
    class Meta:
        model = models.User
        fields = "__all__"
if __name__ == "__main__":
    data = {'name':'jack','age':18}
    # 反序列化新增时只需传入 data 即可
    # 反序列化修改时需要传入被修改的 instance 以及 修改参数
    # 如果在修改时,饭序列化的 data 不全,可以加上 partial=True 字段
    user_ser = UserModelSerializer(data=data)
    if user_ser.is_valid():
        user_ser.save()
    else:
        # 如果校验不成功,会有校验错误,保存在 .errosrs
        print(user_ser.errors)

反序列化之重写数据校验

  • 三种方法
    • 在定义字段的时候进行限制数据,比如name = serializers.CharField(max_length=16)设置name属性最大长度为 16
    • 使用字段级别的验证器validate_xxx,如果想验证name,就是validate_name
    • 使用序列化器级别的验证器validate,可以验证所有字段
python 复制代码
## 字段级别的校验
class UserModelSerializer(serializers.ModelSerializer):
    car_set = serializers.StringRelatedField(many=True,label="拥有车辆",required=False)
    class Meta:
        model = models.User
        fields = "__all__"

    def validate_age(self, value):
        if value < 18:
            raise serializers.ValidationError("年龄小于 18 岁")
        return value


data = {'name':'vg','age':17}
user_ser = UserModelSerializer(data=data,partial=True)
if user_ser.is_valid():
    user_ser.save()
else:
    print(user_ser.errors) 
# 结果如下
{'age': [ErrorDetail(string='年龄小于 18 岁', code='invalid')]}
python 复制代码
## 序列化器级别的校验
class UserModelSerializer(serializers.ModelSerializer):
    car_set = serializers.StringRelatedField(many=True,label="拥有车辆",required=False)
    class Meta:
        model = models.User
        fields = "__all__"


    def validate(self, attrs):
        print(type(attrs))  # <class 'collections.OrderedDict'>
        age = attrs.get('age','')
        if age > 100:
            raise  serializers.ValidationError("年龄大于 100 岁")
        return attrs

data = {'name':'vg','age':170}
user_ser = UserModelSerializer(data=data,partial=True)
if user_ser.is_valid():
    user_ser.save()
else:
    print(user_ser.errors)  
# 结果如下    
{'non_field_errors': [ErrorDetail(string='年龄大于 100 岁', code='invalid')]}

反序列化之数据保存

python 复制代码
def create(self, validated_data):
        # 在这里修改 validated_data
        validated_data['some_field'] = 'new_value'
        return super().create(validated_data)

def update(self, instance, validated_data):
    # 在这里修改 validated_data
    validated_data['some_field'] = 'updated_value'
    return super().update(instance, validated_data)

ModelSerializer的使用

  • 如果序列化器类对应 django 的某个模型,则定义序列化类的时候,可以直接继承 ModelSerilaizer
    • ModelSerilaizer 是 Serializer 的子类,基于模型类字段,自动生成序列化器类的字段 ,包含默认的create()update()方法

基本使用

python 复制代码
class UserModelSerializer(serializers.ModelSerializer):
    car_set = serializers.StringRelatedField(many=True,label="拥有车辆",required=False)
    class Meta:
        model = models.User  # 指定序列化那个模型类
        fields = "__all__"  # 指定序列化模型类的那些字段,__all__ 代表序列化全部

指定具体字段

python 复制代码
class UserSerializer(serializers.ModelSerializer):
	class Meta:
	    # model:指明序列化器类对应的模型类
	    model = User
	    # fields:指明依据模型类的哪些字段生成序列化器类的字段
	    fields = ('id', 'name')

指定排除那些字段

python 复制代码
class UserSerializer(serializers.ModelSerializer):
	class Meta:
	    # model:指明序列化器类对应的模型类
	    model = User
	    # fields:指明依据模型类的哪些字段生成序列化器类的字段
	    fields = '__all__'
        exculde = ('name')

指定字段的额外属性

python 复制代码
class UserSerializer(serializers.ModelSerializer):
	class Meta:
	    # model:指明序列化器类对应的模型类
	    model = User
	    # fields:指明依据模型类的哪些字段生成序列化器类的字段
	    fields = '__all__'
        extra_kwargs = {
        	"name": {'max_length':3,'required':False},
        
        }
相关推荐
blues_C2 天前
十三、【核心功能篇】测试计划管理:组织和编排测试用例
vue.js·django·测试用例·drf·测试平台
恸流失2 天前
DJango项目
后端·python·django
编程大全3 天前
41道Django高频题整理(附答案背诵版)
数据库·django·sqlite
网安小张3 天前
解锁FastAPI与MongoDB聚合管道的性能奥秘
数据库·python·django
KENYCHEN奉孝3 天前
Pandas和Django的示例Demo
python·django·pandas
老胖闲聊3 天前
Python Django完整教程与代码示例
数据库·python·django
noravinsc3 天前
django paramiko 跳转登录
后端·python·django
践行见远3 天前
django之请求处理过程分析
数据库·django·sqlite
声声codeGrandMaster3 天前
Django之表格上传
后端·python·django
菌菌的快乐生活3 天前
网站静态文件加速-Django项目静态文件存储到腾讯云COS存储提升网络请求速度
django·cos存储