Подтвердить что ты не робот

Как мне запоминать дорогостоящие вычисления на объектах модели Django?

У меня есть несколько столбцов TextField в моем объекте UserProfile, который содержит объекты JSON. Я также определил свойство setter/getter для каждого столбца, который инкапсулирует логику для сериализации и десериализации JSON в python datastructures.

Характер этих данных гарантирует, что к нему будет обращаться много раз по логике вида и шаблона в рамках одного запроса. Чтобы сэкономить на затратах на десериализацию, я хотел бы memoize datastructures python при чтении, недействительности при прямой записи в свойство или сохранении сигнала от объекта модели.

Где/Как сохранить заметку? Я нервничаю из-за использования переменных экземпляра, так как я не понимаю магии того, как какой-либо конкретный UserProfile создается экземпляром запроса. Является ли __init__ безопасным для использования, или мне нужно проверить наличие атрибута memo через hasattr() при каждом чтении?

Вот пример моей текущей реализации:

class UserProfile(Model):
    text_json = models.TextField(default=text_defaults)

    @property
    def text(self):
        if not hasattr(self, "text_memo"):
            self.text_memo = None
        self.text_memo = self.text_memo or simplejson.loads(self.text_json)
        return self.text_memo
    @text.setter
    def text(self, value=None):
        self.text_memo = None
        self.text_json = simplejson.dumps(value)
4b9b3361

Ответ 1

Вам может быть интересен встроенный декоратор django django.utils.functional.memoize.

Django использует это для кэширования дорогостоящей операции, например, для разрешения URL.

Ответ 2

Как правило, я использую такой шаблон:

def get_expensive_operation(self):
    if not hasattr(self, '_expensive_operation'):
        self._expensive_operation = self.expensive_operation()
    return self._expensive_operation

Затем вы используете метод get_expensive_operation для доступа к данным.

Однако, в вашем конкретном случае, я думаю, вы приближаетесь к этому несколько неправильно. Вам нужно выполнить десериализацию, когда модель сначала загрузится из базы данных, и сериализуется только при сохранении. Затем вы можете просто получить доступ к атрибутам в качестве стандартного словаря Python каждый раз. Вы можете сделать это, указав настраиваемый тип JSONField, модели подклассов. TextField, который переопределяет to_python и get_db_prep_save.

Фактически кто-то уже сделал это: см. здесь.

Ответ 3

Для методов класса вы должны использовать django.utils.functional.cached_property.

Поскольку первый аргумент метода класса self, memoize будет поддерживать ссылку на объект и результаты функции даже после того, как вы его выбросите. Это может привести к утечке памяти, не позволяя сборщику мусора очистить устаревший объект. cached_property превращает предложение Даниэля в декоратор.