一、Response封裝
用def自帶的response模塊返回數據需要data和status等參數,就算有相同的response也需要重新寫一遍,這樣顯得很不方便。
因此我們可以將response模塊進行二次封裝,減少一些代碼的重復書寫,這樣就可以使我們的工作量變小。
方法:
在應用文件夾中重新寫一個response.py文件,專門用來二次封裝drf的response模塊。
class APIResponse(Response):
def __init__(self, status=0, msg='ok', results=None, http_status=None,headers=None, exception=False, content_type=None, **kwargs):
# 將status、msg、results、kwargs格式化成data
data = {
'status': status,
'msg': msg,
}
# results只要不為空都是數據:False、0、'' 都是數據 => 條件不能寫if results
if results is not None:
data['results'] = results
# 將kwargs中額外的k-v數據添加到data中
data.update(**kwargs)
super().__init__(data=data, status=http_status, headers=headers, exception=exception, content_type=content_type)
二、外鍵字段深度查詢
1、序列化配置exclude、depth
必須有子序列化類配合,不能反序列化了。
-
只能在序列化中使用。
-
字段名必須是外鍵(正向反向)字段。
- 因為相對於自定義序列化外鍵字段,自定義序列化字段是不能參與反序列化的,而子序列化必須為外鍵名,所以就無法入庫。
-
在外鍵關聯數據是多條時,需要明確many=True。
-
是單向操作,因為作為子系列的類必須寫在上方,所以不能產生逆方向的子序列化。
class PublishModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Publish
# fields = ['name', 'address', 'books']
# 了解配置
# fields = '__all__' # 所有字段
exclude = ['name'] # 排除字段
depth = 2 # 自動深度,值代表深度次數,但是被深度的外鍵采用__all__,顯示所有字段
2、模型層函數、插拔式字段查詢
設置模型表中需要進行序列化和反序列化的字段(容器,列表或元組)。
並且容器中的名稱可以映射到模型類中不存在任何參數的屬性或方法,通過這種特性可以完成自定義字段的插拔式設計。
# models.py
class Car(models.Model):
name = models.CharField(max_length=64,unique=True)
price = models.DecimalField(max_digits=10,decimal_places=2)
image = models.ImageField(upload_to='img',default='img/default.jpg')
brand = models.CharField(max_length=32,default='unknown')
@property # 可以不寫
def image_path(self): # 該方法不能攜帶參數
return f'{settings.BASE_URL}{settings.MEDIA_URL}{self.image}'
# serializer.py
class CarModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Car
fields = [
'name','price','image_path','brand'
]
三、listserializer輔助類
ListSerializer類能夠序列化和一次驗證多個對象。你通常不需要直接使用ListSerializer,而是應該在實例化一個序列化器時簡單地傳遞一個many=True參數。
當一個序列化器在帶有many=True選項被序列化時,將創建一個ListSerializer實例。該序列化器類將成為ListSerializer類的子類。
當你要自定義多個對象的更新行為(群改)時,你需要手動定制ListSerializer類的一些行為。
可以通過使用序列化器類的Meta類下面的list_serializer_class選項來修改當many=True時正在使用的類。
# 多表操作
class CarListSerializer(serializers.ListSerializer):
# 自定義的群增群改輔助類,沒有必要重寫create方法
def create(self, validated_data):
return super().create(validated_data)
def update(self, instance_list, validated_data_list):
return [
self.child.update(instance_list[index], attrs) for index, attrs in enumerate(validated_data_list)
]
# 汽車表序列化
class CarModelSerializer(serializers.ModelSerializer):
# 通過SerializerMethodField設置的字段為只讀字段
car_color = serializers.SerializerMethodField()
def get_car_color(self,obj):
return obj.get_color_display()
re_brand = serializers.CharField(
write_only=True,
error_messages={
'required':'re_brand為必填字段!'
}
)
class Meta: # 聲明
# 綁定需要進行序列化和反序列化的模型表
model = models.Car
# 設置模型表中需要進行序列化和反序列化的字段(容器,列表或元組)。
# 並且容器中的名稱可以映射到模型類中不存在任何參數的屬性或方法,
# 通過這種特性可以完成自定義字段的插拔式設計
fields = [
'name','car_color','price','image_path','brand','re_brand'
]
read_only_fields = ['car_color','image_path']
# 設置額外的序列化與反序列化的規則
extra_kwargs = {
'name':{
'min_length':2,
'max_length':10,
'error_messages':{
'min_length': '太短',
'max_length': '太長',
}
}
}
def validate(self, attrs):
brand = attrs.get('brand')
re_brand = attrs.pop('re_brand',False)
if not brand == re_brand:
raise serializers.ValidationError({'re_brand':'兩次品牌不一致!'})
return attrs
