Sentry Developer Contribution Guide: Using Django REST Framework Serializers

This guide explains Sentry's two serializer types—generic DRF Serializer and ModelSerializer—showing how to define fields, perform built‑in and custom validation, use them in endpoints, save data, and leverage the @register decorator and get_attrs method for efficient batch processing.

Hacker Afternoon Tea
Hacker Afternoon Tea
Hacker Afternoon Tea
Sentry Developer Contribution Guide: Using Django REST Framework Serializers

Overview

Sentry provides two serializer classes for handling data: the generic Django Rest Framework Serializer for input validation and conversion, and the ModelSerializer used primarily for outbound data.

Django Rest Framework Serializer

A serializer extracts data from complex Python models and converts it to JSON; it can also deserialize validated JSON back into Python objects. In Sentry, a typical serializer defines fields that enforce type and format constraints.

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

Field checks: name and type must be strings, age must be an integer. By default fields are required; setting required=False makes a field optional while still allowing the serializer to be considered valid.

Custom validation methods follow the pattern validate_<em>field_name</em>. For a field named typeName the method would be validate_typeName; for type_name it would be validate_type_name. If validation fails, a ValidationError is raised.

Typical endpoint usage:

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
        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)

After validation, data can be saved either by accessing serializer.object (the validated dict) and calling the model's .objects.create, or by using the serializer’s save() method when a ModelSerializer is employed.

Model Serializer

Model serializers are used only for outbound data. They are registered with the @register decorator so that Sentry can locate the appropriate serializer for a given model.

@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,
        }

The get_attrs method performs a batch query (e.g., fetching all related ExampleTypes in one query) instead of issuing a separate query per item, reducing database load. It builds a dictionary where each key is an item and the value is another dictionary of attribute names and their values.

The serialize method returns a JSON‑serializable dictionary that will be included in the HTTP response.

Why Use get_attrs

When the DRF framework provides similar functionality, get_attrs is still valuable because it allows bulk retrieval of related data, avoiding repeated .get(...) calls for each item and improving performance.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

DjangoSerializerModelSerializerREST Framework
Hacker Afternoon Tea
Written by

Hacker Afternoon Tea

You might find something interesting here ^_^

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.