Как я могу кэшировать результат SerializerMethodField

У меня есть сериализатор:

class OrderItemResponseSerializer(serializers.ModelSerializer):
    prepack_qty = serializers.SerializerMethodField()
    product_description = serializers.SerializerMethodField()

    class Meta:
        model = OrderItem
        fields = (
            "product",
            "qty_ordered",
            "qty_approved",
            "status",
            "prepack_qty",
            "product_description"
        )

    def get_prepack_qty(self, obj):
        return obj.product.prepack_quantity

    def get_product_description(self, obj):
        return obj.product.product_description

Когда я делаю get запрос к /orders, я делаю много sql запросов к базе данных, потому что разные заказы могут содержать один и тот же продукт. Как я могу кэшировать результат методов get_prepack_qty и get_product_description? Я пытался использовать @cached_property следующим образом:

class OrderItem(models.Model):
    ...
    @cached_property
    def item_product_description(self):
        return self.product.product_description

но количество запросов к базе данных осталось прежним.

Лучше использовать, например, Redis для кэширования результата

Посмотрите этот учебник для лучшего понимания

Желаю удачи

Во-первых, я должен сказать, что то, что вы реализовали в этом куске кода ниже:

    ...
    @cached_property
    def item_product_description(self):
        return self.product.product_description

И использование @cached_property само по себе не кэширует данные для вас, вы просто создали свойство в модели для метода сериализатора get_product_description, И это совсем не уменьшает объем и количество ваших запросов к базе данных; Конечно, вам нужен метод .bind() в вашем методе сериализатора, как показано ниже:

class BlobSerializer(SerializerCacheMixin, serializers.Serializer):
   blobs = serializers.SerializerMethodField()

   def get_blobs(self, instance):
       # recursive serializer
       serializer = self.__class__(instance.results, many=True)
       serializer.bind('*', self)
       return serializer.data

Но для того, чтобы кэшировать результат этого метода Как вы спросили в своем вопросе, есть хороший проект в Pypi под названием drf-serializer-cache вы можете легко использовать его для этой цели, например, следующий кусок кода взят из документа этого проекта :

from drf_serializer_cache import SerializerCacheMixin
from rest_framework import serializer

class ResultSerializer(SerializerCacheMixin, serializers.Serializer):
   results = serializers.SerializerMethodField()

   def get_results(self, instance):
       # recursive serializer
       serializer = self.__class__(instance.results, many=True)
       serializer.bind('*', self)  # bind call is essential for >efficient cache!
       return serializer.data

Также, если вы хотите реализовать его самостоятельно в своем проекте, просмотр реализации SerializerCacheMixin объекта в этом проекте может помочь вам во многом или даже использовать его напрямую.

You can leverage Django's cache framework to cache the result of a SerializerMethodField. It would look something like this:
from django.core.cache import cache

class MySerializer(serializers.Serializer):
    my_field = serializers.SerializerMethodField()

    def get_my_field(self, obj):
        # Get cached value
        value = cache.get("my_field_%s" % obj.pk)
        if value is None:
            # Value is not cached, compute it
            value = ...
            # Cache the value
            cache.set("my_field_%s" % obj.pk, value, 3600)
        return value

This will cache the result of the field for 1 hour (3600 seconds), using a cache key that depends on the object's primary key.
You can of course adapt the caching logic to your exact use case.
Вернуться на верх