Наборы запросов Django - убедитесь, что результаты получены только один раз - PullRequest
1 голос
/ 15 сентября 2010

У меня есть простая функция для получения дополнительных данных на основе request.user:

def getIsland(request):
 try:
  island = Island.objects.get(user=request.user) # Retrieve
 except Island.DoesNotExist:
  island = Island(user=request.user) # Doesn't exist, create default one
  island.save()
 island.update() # Run scheduled tasks
 return island # Return

Проблема в том, что функция вызывается во многих местах (промежуточное ПО, шаблоны, представления ETC)и, таким образом, выполняет запрос много раз.Любой способ помочь этому?т.е.

def getIsland(request):
    if HasBeenEvaluatedAlreadyOnThisRequest: return cached
    else:
        [...]

Ответы [ 3 ]

2 голосов
/ 15 сентября 2010

Вы пробовали использовать кеш?

У Django замечательная система кеширования: http://docs.djangoproject.com/en/dev/topics/cache/

Это сделает вашу функцию похожей на:

def getIsland(request):
 island = cache.get("island_"+request.user)
 if island == None:
   try:
    island = Island.objects.get(user=request.user) # Retrieve
   except Island.DoesNotExist:
    island = Island(user=request.user) # Doesn't exist, create default one
    island.save()
   island.update() # Run scheduled tasks
   cache.set("island_"+request.user, island, 60)
 return island # Return

Скорее всего, вам понадобится выполнить сериализацию и десериализацию при кэшировании, но это основная суть. Преимущество заключается в том, что результат вашего запроса теперь хранится в ОЗУ в течение x секунд, и не имеет значения, какой конкретный процесс обращается к нему. Это всегда там. Доступно для всех.

1 голос
/ 15 сентября 2010

Быстро и грязно:

def getIsland(request):
    if hasattr(request, "_cached_island"):
        return request._cached_island
    try:
        island = Island.objects.get(user=request.user) # Retrieve
    except Island.DoesNotExist:
        island = Island(user=request.user) # Doesn't exist, create default one
        island.save()
    island.update() # Run scheduled tasks
    request._cached_island = island
    return island # Return
0 голосов
/ 15 сентября 2010

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

Одна вещь, которую вы можете попытаться сделать, - использовать локальное хранилище для хранения глобального «кэша» пользователей. Как пример:

class UserStorage(threading.local):
    store = {}
    def getIsland(self, request):
        user_id = request.user.pk
        island = store.get(user_id)
        if island is None:
            island, created = Island.objects.get_or_create(user = user_id)
            store[user_id] = island
        island.update()
        return island

Однако вы можете заметить, что объект Island НИКОГДА НЕ ОБНОВЛЯЕТСЯ. Поэтому вы должны действовать с особой осторожностью. Возможно, вам понадобится глобальное время ожидания для этого объекта, но затем вы реализуете свое собственное решение для кеширования, так почему бы не использовать систему кеширования django с memcached или их локально-кеш-память?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...