Evgenii Legotckoi
Evgenii LegotckoiҚар. 3, 2019, 4:03 Т.Ж.

ЖАМАНДЫҚ ЯРЕК. Model_cached_property бар үлгі нысанының сипаттарын кэштеу

Сайтты жеделдету үшін дерекқор сұрауларын оңтайландырудан басқа, кэштеуді пайдалануға болады.

Django кэштеуге мүмкіндік береді:

  • жеке көрініс , Класқа негізделген көрініс және тұрақты көру функциялары
  • тұтас үлгілер немесе осы үлгілердің бөліктері
  • Сұраулар жинағы
  • сонымен қатар cached_property көмегімен үлгі нысандарының қасиеттері

Мені ауыр есептеулер немесе ауыр дерекқор сұраулары үшін үлгі нысандарының жеке қасиеттерін кэштеу мүмкіндігі қызықтырды.
cached_property декораторының осындай функционалдығы бар, бірақ мен үшін минус кэштеу объектінің қызмет ету мерзімі ішінде ғана орын алды.
Ал маған бет сұралған кезде объектінің бар болуынан ұзақ уақыт бойы кэштеу қажет. Сондай-ақ кіріс аргументтеріне байланысты қасиеттерді кэштеу керек болды. Бұл сайт безендірушісі ұнатулар мен ұнатпаулар санын, сондай-ақ ағымдағы пайдаланушыға белгілі бір мазмұн элементін ұнатқан-ұнамағаны туралы ақпаратты кэштейді.

model_cached_property декораторы осылай жазылған


үлгінің_кэштелген_сипаты

Бұл декоратор өзінің кэштеу механизмі ретінде redis пайдаланады, себебі кэшті жарамсыз деп тану үшін осы сипатқа жататын кілттер тобын жою қажет болуы мүмкін. Өйткені сипат әртүрлі пайдаланушылар үшін әртүрлі жолдармен кэштелуі мүмкін.

EVILEG-CORE орнату

pip install evileg-core

Сондай-ақ, evileg_core осы пакетке қажетті барлық тәуелділіктерді тартады. Соның ішінде redis -мен жұмыс істеу үшін пайдаланылатын django-redis кітапханасы.

Егер сіз әлі redis қолданбасаңыз, оны орнатуыңыз керек.

sudo apt install redis-server

settings.py

Орнатылған қолданбаларға evileg_core қосыңыз

INSTALLED_APPS = [
    ...
    'evileg_core',
]

Кэштеу серверін орнату

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}

Үлгі_кэштелген_сипатты пайдалану

Қалыпты кэштеу

from evileg_core.cache.decorators import model_cached_property

class Article(models.Model):

    @model_cached_property
    def comments_count(self):
        return self.comments.count()

Бұл декоратор мақаланың пікірлер санын 60 секунд ішінде кэштейді. Келесі жолы мақала беті сұралғанда, сұрау алдымен белгілі бір мақала нысанының кэшіне жасалады және кэштің мерзімі өткен жағдайда ғана сұрау дерекқорға қайта жасалады.

Кэштеу уақытын орнату

Белгілі бір кэш уақытын орнатқыңыз келсе, декоратормен тайм-аут аргументін пайдалануға болады.

class Article(models.Model):

    @model_cached_property(timeout=3000)
    def comments_count(self):
        return self.comments.count()

Жаһандық кэш ұзақтығы параметрі

Сондай-ақ settings.py ішіндегі барлық декораторлар үшін жаһандық кэш уақытын секундтарда орнатуға болады.

MODEL_CACHED_PROPERTY_TIMEOUT = 300000

Аргументтермен сипаттарды пайдалану

Ал енді ең қызығы. Аргументтермен сипаттарды кэштеу, осылайша деректер үлгісі сипатының кіріс аргументтері туралы ақпаратты пайдаланып нәтижені кэштей аласыз.

Бұл декоратордың артықшылығы да, кемшілігі де. Өйткені, кэштеу дұрыс, кіріс аргументтері бірегей болуы керек. Мысалы, егер енгізу аргументтері AnonymousUser сияқты уақытша бірегей емес нысандар болса, кэштеу жұмыс істемейді.

Дегенмен, пайдаланушыға байланысты кэштеу үшін декораторды пайдалануға болады. Мынадай көрінуі мүмкін.

class Article(models.Model):

    @model_cached_property
    def __user_in_bookmarks(self, user):
        return self.bookmarks.filter(user=user).exists()

    def user_in_bookmarks(self, user):
        return self.__user_in_bookmarks(user) if user.is_authenticated else False

user.is_authenticated үшін тексеру бар екенін ескеріңіз, себебі аутентификацияланбаған пайдаланушыны кэштеу дұрыс жұмыс істемейді, бірақ түпнұсқалығы расталған пайдаланушы үшін ол дұрыс жұмыс істейді, себебі аутентификацияланған пайдаланушы бірегей нысан болып табылады.

Кэштің жарамсыздығы

Кэш оның қызмет ету мерзімі аяқталғанға дейін маңызды емес болып қалса, invalidate_model_cached_property функциясын пайдалануға болады.

from evileg_core.cache.utils import invalidate_model_cached_property

class Article(models.Model):

    def invalidate_cache(self):
        invalidate_model_cached_property(self, self.comments_count)

Кэшті дұрыс жарамсыз деп тану үшін кэшті тазалағыңыз келетін нысанды, сондай-ақ осы нысанның әдісін өтуіңіз керек.

Бұл бірдей көрінуі мүмкін.

article = get_object_or_404(Article, pk=12)
invalidate_model_cached_property(article, article.comments_count)

Қорытынды

Сондықтан model_cached_property үшін қолдануға болады

  • ұзақ уақыт бойы үлгі нысандарының кэштеу қасиеттері, бетті сұрау кезінде нысанның қызмет ету мерзімі ұзағырақ
  • енгізу аргументтеріне байланысты модель объектілерінің кэштеу қасиеттері

Шектеулер бар

  • бұл декораторды тек үлгілерде, яғни models.Model -дан мұраланған сыныптарда пайдалануға болады.
  • аргументтерге байланысты үлгі қасиеттерін кэштеу тек бірегей енгізу аргументтері үшін орындалуы керек, әйтпесе кэштеу дұрыс емес болады.
Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

МК
  • Қар. 6, 2019, 2:25 Т.Ж.

а functools.lru_cache в данном случае не поможет?

Evgenii Legotckoi
  • Қар. 6, 2019, 3:16 Т.Ж.
  • (өңделген)

Добрый день.

Думаю, что не совсем. Технически здесь решается задача кэширования не последних вызовов функции, как в lru_cache, а кэширование свойств для ряда объектов модели данных. К тому же cache_clear() будет полностью удалять весь кэш, тогда как у меня предусмотрен более специфический функционал для инвалидации части ключей, которые перестали быть актуальны.

Давайте поясню на примере.

На сайте есть модель данных ForumTopic , у которой есть лайки и дислайки, а также они подсвечиваются, если пользователь выбрал лайк или дислайк. Вся эта информация у меня кэшируется, поскольку для лайков и дислайков используются GenericForeignKey и запросы к базе данных посылаются отдельно, что получается несколько накладно для страниц со списком тем на форуме. Поэтому я предпочитаю кэшировать эти данные и при срабатывание некоторых событий делать инвалидацию кэша.

Так вот, если использовать lru_cache, то он будет кэшировать лишь n-последних вызовов метода, то есть придётся отслеживать количество контента и вручную поправлять количество последних кэширований, если решать эту задачу в лоб. А в случае очистки кэша, при вызове страниц будут заново кэшироваться все свойства для всех объектов ForumTopic. Получается ситуация, если пользователь лайкнул один единственный пост, то кэш будет очищаться для всех объектов, чего я не хочу.

model_cached_property же работает немного иначе. Он кэширует информацию о модели данных, а именно о таблице в базе данных, а также об id объекта, а потом информацию об имени свойства и входных аргументах. В результате происходит уникальное кжширование для каждого отдельного объекта.

Когда вы вызываете функцию invalidate_model_cached_property, то кэш очищается только для конкретного объекта базы данных.

Таким образом, когда пользователь лайкнет один какой-то объект ForumTopic , то кэш будет очищен только для этого ForumTopic . И при следующем запросе список объектов ForumTopic будет выполняться запрос о лайках и дислайках только для одного единственного объекта. Плюс я не беспокоюсь о том, что мне нужно думать, какой максимальный размер кэша нужно делать.

Конечно, вопрос расхода памяти на кэширование является довольно важным и если появится бутылочное горлышко, то я буду его решать. Но на данный момент я поставил у себя длительность кэширования подобных активностей, как лайки, на целый месяц и на данный момент ещё не заметил проблем.

Но если я что-то не учёл и у вас есть, что дополнить, то с удовольствием выслушаю вашу точку зрения, возможно, что это поможет доработать функциональность model_cached_property

NSProject
  • Мамыр 27, 2022, 6:27 Т.Ж.
  • (өңделген)

Всё конечно супер классно. Интересует лишь один вопрос.

NSProject
  • Мамыр 28, 2022, 10:20 Т.Ж.

Здравствуйте. В общем меня интересует такой вопрос. Я пробовал это на Like , Dislike. Как я понимаю если не перевалидировать кеш то ничего не изменится на странице. Вернётся значение из кэша? Отсюда второй вопрос как и где прописть эту перевалидацию? Ибо если я пишу её через модель как сказано в статье. То ничего не происходит. По этому интересует то как и где перевалидировать кеш.

Evgenii Legotckoi
  • Мамыр 30, 2022, 10:25 Т.Ж.

Да, если не вызывать invalidate_cache , то ничего не произойдёт.
Место вызова инвалидации обычно индивидуально. Но я стараюсь вешать его на сигналы сохранения и удаления объектов.

В случае с Like Dislike , которые используют GenericForeignKey удобнее всего поступить следующим образом.

Добавить метод invalidate_cache , который будет вызывать метод инвалидации content_object

class LikeDislike(...):

    ...

    def invalidate_cache(self):
        self.content_object.invalidate_like_dislike_cache()

А потом навешать инвалидацию на сигналы

# -*- coding: utf-8 -*-

from django.db.models.signals import post_save, pre_delete

from .models import LikeDislike

def cache_invalidate_activity(sender, instance, **kwargs):
    instance.invalidate_cache()

post_save.connect(cache_invalidate_activity, sender=LikeDislike)
pre_delete.connect(cache_invalidate_activity, sender=LikeDislike)

В таком случае инвалидация будет действовать на лету, главное, чтобы во всех моделях были, к которым привязываются лайки и дизлайки, были определены соответсвующие методы инвалидации.

NSProject
  • Маусым 2, 2022, 9:33 Т.Ж.

Спасибо за пояснения. Я ток щас догнал как это всё работает. Просто с сигналами не работал никогда. Но вот теперь стало понятно.

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
Г

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:66ұпай,
  • Бағалау ұпайлары-1
t

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:33ұпай,
  • Бағалау ұпайлары-10
t

Qt - Тест 001. Сигналы и слоты

  • Нәтиже:52ұпай,
  • Бағалау ұпайлары-4
Соңғы пікірлер
G
GoattRockҚыр. 3, 2024, 1:50 Т.Қ.
Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssrАқп. 8, 2024, 6:43 Т.Қ.
Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий КононенкоАқп. 5, 2024, 1:50 Т.Ж.
Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
F
FynjyШілде 22, 2024, 4:15 Т.Ж.
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
BlinCT
BlinCTМаусым 25, 2024, 1 Т.Ж.
Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
BlinCT
BlinCTМамыр 5, 2024, 5:46 Т.Ж.
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
Evgenii Legotckoi
Evgenii LegotckoiМамыр 2, 2024, 2:07 Т.Қ.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

Бізді әлеуметтік желілерде бақылаңыз