Sentry 開發者貢獻指南 - Django Rest Framework(Serializers)

為少發表於2022-01-14

Serializer 用於獲取複雜的 python 模型並將它們轉換為 json。序列化程式還可用於在驗證傳入資料後將 json 反序列化回 Python 模型。

Sentry,我們有兩種不同型別的序列化器 :Django Rest Framework SerializerModel Serializer

Django Rest Framework

Django Rest Framework 序列化程式用於處理進入 Sentry 的資料的輸入驗證和轉換。

示例

在典型的 serializer 中,指定了欄位,以便它們根據您的規範驗證資料的型別和格式。
如果寫入適合 modelDjango 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 將接受並驗證包含三個欄位的 jsonnameagetype
其中 nametype 必須是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 FrameworkSerializer 將用於需要驗證的傳入資料的方法(即 putpost 方法)。
一旦序列化器被例項化,你可以呼叫 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
給定變數 examplemodel 型別。
要將 model serializerModel 匹配,您只需執行

@register(<ModelName>)
class ModelSerializer(Serializer):
...

get_attrs 方法

Django Rest Framework 具有類似功能時,為什麼要這樣做?
get_attrs 方法就是原因。它允許您執行批量查詢而不是多個查詢。
在我們的示例中,我可以過濾我想要的 item,並使用 python 將它們分配給相關 item
而不是呼叫 ExampleTypes.objects.get(...) 多個 item
attr 字典的情況下,keyitem 本身。
並且 value 是一個字典,其中包含要新增的屬性的名稱及其值。

attrs[item] = {'attribute_name': attribute}

Serialize 方法

最後,您返回一個帶有 json 可序列化資訊的字典,該資訊將與 response 一起返回。

更多

相關文章