Как я вынуждаю Django проигнорировать какие-либо кэши и данные перезагрузки?

Я использую модели базы данных Django от процесса, которым это не называют из Запроса HTTP. Процесс, как предполагается, опрашивает относительно новых данных каждые несколько секунд и делает некоторую обработку на нем. У меня есть цикл, который спит в течение нескольких секунд и затем получает все необработанные данные из базы данных.

То, что я вижу, - то, что после первой выборки, процесс никогда не видит новых данных. Я запустил несколько тестов, и похоже, что Django кэширует результаты, даже при том, что я создаю новый QuerySets каждый раз. Для проверки этого я сделал это от оболочки Python:

>>> MyModel.objects.count()
885
# (Here I added some more data from another process.)
>>> MyModel.objects.count()
885
>>> MyModel.objects.update()
0
>>> MyModel.objects.count()
1025

Как Вы видите, добавляя, что новые данные не изменяют количество результата. Однако называя обновление менеджера () метод, кажется, решает проблему.

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

Мой вопрос, почему я вижу это поведение кэширования, которое противоречит тому, что говорят документы Django? И как я предотвращаю его?

74
задан scippy 27 July 2010 в 17:17
поделиться

2 ответа

Похоже, что count () попадает в кеш после первого раза. Это исходный код django для QuerySet.count:

def count(self):
    """
    Performs a SELECT COUNT() and returns the number of records as an
    integer.

    If the QuerySet is already fully cached this simply returns the length
    of the cached results set to avoid multiple SELECT COUNT(*) calls.
    """
    if self._result_cache is not None and not self._iter:
        return len(self._result_cache)

    return self.query.get_count(using=self.db)

update , похоже, делает довольно много дополнительной работы помимо того, что вам нужно.
Но я не могу придумать лучшего способа сделать это, кроме написания собственного SQL для подсчета.
Если производительность не очень важна, я бы просто сделал то, что делаете вы, вызвав update до count .

QuerySet.update:

def update(self, **kwargs):
    """
    Updates all elements in the current QuerySet, setting all the given
    fields to the appropriate values.
    """
    assert self.query.can_filter(), \
            "Cannot update a query once a slice has been taken."
    self._for_write = True
    query = self.query.clone(sql.UpdateQuery)
    query.add_update_values(kwargs)
    if not transaction.is_managed(using=self.db):
        transaction.enter_transaction_management(using=self.db)
        forced_managed = True
    else:
        forced_managed = False
    try:
        rows = query.get_compiler(self.db).execute_sql(None)
        if forced_managed:
            transaction.commit(using=self.db)
        else:
            transaction.commit_unless_managed(using=self.db)
    finally:
        if forced_managed:
            transaction.leave_transaction_management(using=self.db)
    self._result_cache = None
    return rows
update.alters_data = True
6
ответ дан 24 November 2019 в 12:01
поделиться

Вы также можете использовать MyModel.objects._clone().count(). Все методы в QuerySet вызывают _clone() перед выполнением любой работы - это гарантирует, что все внутренние кэши будут аннулированы.

Основная причина заключается в том, что MyModel.objects каждый раз является одним и тем же экземпляром. Клонируя его, вы создаете новый экземпляр без кэшированного значения. Конечно, вы всегда можете зайти и аннулировать кэш, если хотите использовать один и тот же экземпляр.

-1
ответ дан 24 November 2019 в 12:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: