Sentry 開發(fā)者貢獻指南 - Django Rest Framework(Serializers)
本文轉(zhuǎn)載自微信公眾號「黑客下午茶」,作者為少 。轉(zhuǎn)載本文請聯(lián)系黑客下午茶公眾號。
Serializer 用于獲取復(fù)雜的 python 模型并將它們轉(zhuǎn)換為 json。序列化程序還可用于在驗證傳入數(shù)據(jù)后將 json 反序列化回 Python 模型。
在 Sentry,我們有兩種不同類型的序列化器 :Django Rest Framework Serializer 和 Model Serializer。
Django Rest Framework
Django Rest Framework 序列化程序用于處理進入 Sentry 的數(shù)據(jù)的輸入驗證和轉(zhuǎn)換。
- https://www.django-rest-framework.org/
示例
在典型的 serializer 中,指定了字段,以便它們根據(jù)您的規(guī)范驗證數(shù)據(jù)的類型和格式。如果寫入適合 model,Django Rest Framework 序列化程序還可以將信息保存到數(shù)據(jù)庫中。
- 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。默認(rèn)情況下,字段是必需的,如果不提供,serializer 將標(biāo)記為無效。請注意,integer 字段 age,required 設(shè)置為 False。因此可能不包括在內(nèi),serializer 仍將被視為有效。
自定義驗證
對于需要自定義驗證的值(除了簡單的類型檢查),
def validate_
可以創(chuàng)建其中
用法
在 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)
驗證數(shù)據(jù)
來自 Django Rest Framework 的 Serializer 將用于需要驗證的傳入數(shù)據(jù)的方法(即 put 和 post 方法)。一旦序列化器被實例化,你可以調(diào)用 serializer.is_valid() 來驗證數(shù)據(jù)。 serializer.errors 將給出關(guān)于給定數(shù)據(jù)無效的具體反饋。
例如給定的輸入
- {
- 'age':5,
- 'type':'puppy'
- }
serializer 將返回一個錯誤,指出未提供所需的字段名稱。
保存數(shù)據(jù)
確認(rèn)數(shù)據(jù)有效后,您可以通過以下兩種方式之一保存數(shù)據(jù)。上面給出的例子是 sentry 中最常見的。取 serializer.object,它只是經(jīng)過驗證的數(shù)據(jù)(如果 serializer.is_valid() 返回 False,則為 None) 并使用
另一種方法使用了更多的 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 僅用于傳出數(shù)據(jù)。典型的 model serializer 如下所示:
- https://github.com/getsentry/sentry/blob/master/src/sentry/api/serializers/base.py
- @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 匹配,您只需執(zhí)行
- @register(<ModelName>)
- class ModelSerializer(Serializer):
- ...
get_attrs 方法
當(dāng) Django Rest Framework 具有類似功能時,為什么要這樣做? get_attrs 方法就是原因。它允許您執(zhí)行批量查詢而不是多個查詢。在我們的示例中,我可以過濾我想要的 item,并使用 python 將它們分配給相關(guān) item, 而不是調(diào)用 ExampleTypes.objects.get(...) 多個 item。在 attr 字典的情況下,key 是 item 本身。并且 value 是一個字典,其中包含要添加的屬性的名稱及其值。
- attrs[item] = {'attribute_name': attribute}
Serialize 方法
最后,您返回一個帶有 json 可序列化信息的字典,該信息將與 response 一起返回。