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.
-  解决方法: # 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
简单的序列化
# 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’属性。
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)
两张关联的表进行序列化
# 比如现在有 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)])
简单的反序列化
- 反序列化一般是将数据保存到数据库才需要反序列化。
- 步骤: 
  - 创建序列化对象 
    - 新增只需要传入 data 即可
- 修改需要传入 instance(被修改的对象),以及 data
- 如果在修改时,反序列化的 data 不全,可以加上 partial=True字段
 
- 验证数据的合法性.is_valid()- 如果不合法,.errors可以查看不合法原因
 
- 如果不合法,
- 将数据进行保存.save()- 新增调用序列化类的create方法
- 修改调用序列化类的update方法
 
- 新增调用序列化类的
 
- 创建序列化对象 
    
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,可以验证所有字段
 
- 在定义字段的时候进行限制数据,比如
## 字段级别的校验
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')]}
## 序列化器级别的校验
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')]}
反序列化之数据保存
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()方法
 
- ModelSerilaizer 是 Serializer 的子类,基于模型类字段,自动生成序列化器类的字段,包含默认的
基本使用
class UserModelSerializer(serializers.ModelSerializer):
    car_set = serializers.StringRelatedField(many=True,label="拥有车辆",required=False)
    class Meta:
        model = models.User  # 指定序列化那个模型类
        fields = "__all__"  # 指定序列化模型类的那些字段,__all__ 代表序列化全部
指定具体字段
class UserSerializer(serializers.ModelSerializer):
	class Meta:
	    # model:指明序列化器类对应的模型类
	    model = User
	    # fields:指明依据模型类的哪些字段生成序列化器类的字段
	    fields = ('id', 'name')
指定排除那些字段
class UserSerializer(serializers.ModelSerializer):
	class Meta:
	    # model:指明序列化器类对应的模型类
	    model = User
	    # fields:指明依据模型类的哪些字段生成序列化器类的字段
	    fields = '__all__'
        exculde = ('name')
指定字段的额外属性
class UserSerializer(serializers.ModelSerializer):
	class Meta:
	    # model:指明序列化器类对应的模型类
	    model = User
	    # fields:指明依据模型类的哪些字段生成序列化器类的字段
	    fields = '__all__'
        extra_kwargs = {
        	"name": {'max_length':3,'required':False},
        
        }










