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},
        
        }
相关推荐
云和数据.ChenGuang8 小时前
Django 应用安装脚本 – 如何将应用添加到 INSTALLED_APPS 设置中 原创
数据库·django·sqlite
LuiChun1 天前
Django 模板分割及多语言支持案例【需求文档】-->【实现方案】
数据库·django·sqlite
凡人的AI工具箱1 天前
每天40分玩转Django:Django管理界面
开发语言·数据库·后端·python·django
中科院提名者1 天前
Django连接mysql数据库报错ModuleNotFoundError: No module named ‘MySQLdb‘
数据库·mysql·django
碧水澜庭1 天前
django中cookie与session的使用
python·django
鬼义II虎神1 天前
将Minio设置为Django的默认Storage(django-storages)
python·django·minio·django-storages
大霸王龙1 天前
在 Django 中使用 SMTP 发送邮件是一个常见的需求
数据库·django·sqlite
凡人的AI工具箱1 天前
每天40分玩转Django:Django测试
数据库·人工智能·后端·python·django·sqlite
qyq11 天前
Django框架与ORM框架
后端·python·django
LuiChun2 天前
Django 中的 reverse 【反向/逆转/扭转/逆向】使用详解以及使用案例
数据库·django·sqlite