Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is django not using my custom encoder class?

  1. I have two classes: Website and WordpressWebsite.
  2. WordpressWebsite subclasses Website.

When an instance of WordpressWebsite is being encoded into JSON, only the attributes of WordpressWebsite are present (and none of the attributes of Website).

My goal is to write a custom encoder which will encode a WordpressWebsite as a Website instead.

This is what I have so far:

from django.core.serializers.json import DjangoJSONEncoder
from websites.models import Website

class WebsiteEncoder(DjangoJSONEncoder):

    def default(self, obj):
        raise Exception()  # TEST
        if isinstance(obj, Website) and hasattr(obj, 'website_ptr'):
            return super().default(obj.website_ptr)
        return super().default(obj)

I have the following test case:

from django.core import serializers
from django.test import TestCase
from websites.models.wordpress import WordpressWebsite
from websites.serialize import WebsiteEncoder


class SerializationTest(TestCase):

    def setUp(self):
        self.wordpress = WordpressWebsite.objects.create(
            domain='test.com'
        )

    def test_foo(self):
        JSONSerializer = serializers.get_serializer("json")
        json_serializer = JSONSerializer()
        json_serializer.serialize(
            WordpressWebsite.objects.all(),
            cls=WebsiteEncoder
        )
        data = json_serializer.getvalue()
        print(data)

This test case runs fine. It does not raise an exception.

Does anyone know why WebsiteEncoder.default is not being invoked?

like image 709
Tinker Avatar asked Oct 27 '25 23:10

Tinker


1 Answers

Django models are encoded natively with its serializers. Django's own DjangoJSONEncoder supplies a complete serializer for all possible models with any of the default Django datatypes. If you look at the JSONEncoder.default() documentation, you'll notice that you would only supply encoders for datatypes that are not yet known to the encoder.

Only if you were using a field type which Django doesn't natively support, you could provide an encoder for it - and only that field type - through .default(). Therefore DjangoJSONEncoder isn't what you're looking for.

Trying to make your example work I discovered you can actually customize the process by subclassing django.core.serializers.json.Serializer:

from django.core.serializers.json import Serializer

class WebsiteSerializer(Serializer):
    def get_dump_object(self, obj):
        return {
            "pk": obj.pk,
            **self._current,
        }

After that, you can make your serializer work in the test case like so:

def test_foo(self):
    serializer = WebsiteSerializer()
    data = serializer.serialize(WordpressWebsite.objects.all())
    print(data)
like image 155
mar77i Avatar answered Oct 30 '25 14:10

mar77i