Serializer
用於獲取複雜的 python
模型並將它們轉換為 json
。序列化程式還可用於在驗證傳入資料後將 json
反序列化回 Python
模型。
在 Sentry
,我們有兩種不同型別的序列化器 :Django Rest Framework Serializer
和 Model Serializer
。
Django Rest Framework
Django Rest Framework
序列化程式用於處理進入 Sentry
的資料的輸入驗證和轉換。
示例
在典型的 serializer
中,指定了欄位,以便它們根據您的規範驗證資料的型別和格式。
如果寫入適合 model
,Django Rest Framework
序列化程式還可以將資訊儲存到資料庫中。
from rest_framework import serializers
from sentry.api.serializers.rest_framework import ValidationError
class ExampleSerializer(serializers.Serializer):
name = serializers.CharField()
age = serializers.IntegerField(required=False)
type = serializers.CharField()
def validate_type(self, attrs, source):
type = attrs[source]
if type not in ['bear', 'rabbit', 'puppy']:
raise ValidationError('%s is not a valid type' % type)
return attrs
欄位檢查
在上面的示例中,
serializer
將接受並驗證包含三個欄位的 json
:name
、age
和 type
。
其中 name
和 type
必須是strings
,
age
必須是建議的 integer
。
預設情況下,欄位是必需的,如果不提供,serializer
將標記為無效。
請注意,integer
欄位 age
,required
設定為 False
。
因此可能不包括在內,serializer
仍將被視為有效。
自定義驗證
對於需要自定義驗證的值(除了簡單的型別檢查),
def validate_<variable_name>(self, attrs, source)
可以建立其中 <variable_name>
替換為給定欄位的確切變數名稱。
因此,例如,如果我有一個欄位名稱 typeName
,驗證方法名稱將是 validate_typeName
,
而如果我有一個名為 type_name
的欄位,驗證方法名稱將是 validate_type_name
。
在上面給出的示例中,型別被檢查並且必須是某個字串。
如果某個欄位與您的驗證方法所期望的不匹配,則會引發 ValidationError
。
用法
在 endpoint
中,這是 Django Rest Framework Serializer
的典型用法
class ExampleEndpoint(Endpoint):
def post(self, request):
serializer = ExampleSerializer(request.DATA)
if not serializer.is_valid():
return Response(serializer.errors, status=400)
result = serializer.object
#Assuming Example is a model with the same fields
try:
with transaction.atomic():
Example.objects.create(
name=result['name'],
age=result.get('age'),
type=result['type'],
)
except IntegrityError:
return Response('This example already exists', status=409)
return Response(serialize(result, request.user), status=201)
驗證資料
來自 Django Rest Framework
的 Serializer
將用於需要驗證的傳入資料的方法(即 put
和 post
方法)。
一旦序列化器被例項化,你可以呼叫 serializer.is_valid()
來驗證資料。
serializer.errors
將給出關於給定資料無效的具體反饋。
例如給定的輸入
{
'age':5,
'type':'puppy'
}
serializer
將返回一個錯誤,指出未提供所需的欄位名稱。
儲存資料
確認資料有效後,您可以通過以下兩種方式之一儲存資料。
上面給出的例子是 sentry
中最常見的。
取 serializer.object
,它只是經過驗證的資料(如果 serializer.is_valid()
返回 False
,則為 None
)
並使用 <ModelName>.objects.create
將該資料直接儲存在 model
中.
另一種方法使用了更多的 Django Rest Framework
的特性,
ModelSerializer
from rest_framework import serializers
from sentry.api.serializers.rest_framework import ValidationError
class ExampleSerializer(serializer.ModelSerializer):
name = serializers.CharField()
age = serializers.IntegerField(required=False)
type = serializers.CharField()
class Meta:
model = Example
def validate_type(self, attrs, source):
type = attrs[source]
if type not in ['bear', 'rabbit', 'puppy']:
raise ValidationError('%s is not a valid type' % type)
return attrs
class ExampleEndpoint(Endpoint):
def post(self, request):
serializer = ExampleSerializer(request.DATA)
if not serializer.is_valid():
return Response(serializer.errors, status=400)
example = serializer.save()
return Response(serialize(example, request.user), status=201)
Model Serializer
Sentry's Model Serializers 僅用於傳出資料。 典型的 model serializer
如下所示:
@register(Example)
class ExampleSerializer(Serializer):
def get_attrs(self, item_list, user):
attrs = {}
types = ExampleTypes.objects.filter(
type_name__in=[i.type for i in item_list]
)
for item in item_list:
attrs[item] = {}
attrs[item]['type'] = [t for t in types if t.name == item.type_name]
return attrs
def serialize(self, obj, attrs, user):
return {
'name':obj.name,
'type':attrs['type'],
'age': obj.age,
}
註冊 Model Serializer
裝飾器 @register
是必需的,以便
`return Response(serialize(example, request.user), status=201)`
works. 在這種情況下,它會在後臺搜尋匹配的模型 Example
,
給定變數 example
的 model
型別。
要將 model serializer
與 Model
匹配,您只需執行
@register(<ModelName>)
class ModelSerializer(Serializer):
...
get_attrs 方法
當 Django Rest Framework
具有類似功能時,為什麼要這樣做?
get_attrs
方法就是原因。它允許您執行批量查詢而不是多個查詢。
在我們的示例中,我可以過濾我想要的 item
,並使用 python
將它們分配給相關 item
,
而不是呼叫 ExampleTypes.objects.get(...)
多個 item
。
在 attr
字典的情況下,key
是 item
本身。
並且 value
是一個字典,其中包含要新增的屬性的名稱及其值。
attrs[item] = {'attribute_name': attribute}
Serialize 方法
最後,您返回一個帶有 json
可序列化資訊的字典,該資訊將與 response
一起返回。