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 序列化器一共有两个类,分别是
Serializer
和ModelSerializer
,它们都在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)])
- 使用
序列化类嵌套
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)]
- 使用
StringRelatedField
- 需要定义模型类的
__str__
函数,定义其返回值。返回值定义什么,car_set 就返回什么
pythonclass 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']
简单的反序列化
- 反序列化一般是将数据保存到数据库才需要反序列化。
- 步骤:
- 创建序列化对象
- 新增只需要传入 data 即可
- 修改需要传入 instance(被修改的对象),以及 data
- 如果在修改时,反序列化的 data 不全,可以加上
partial=True
字段
- 验证数据的合法性
.is_valid()
- 如果不合法,
.errors
可以查看不合法原因
- 如果不合法,
- 将数据进行保存
.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()
方法
- ModelSerilaizer 是 Serializer 的子类,基于模型类字段,自动生成序列化器类的字段 ,包含默认的
基本使用
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},
}