#django #django-models
#django #django-модели
Вопрос:
У меня есть две модели:
class Person(models.Model):
name = models.CharField()
email = models.EmailField()
class Vote(models.Model):
person = models.ForeignKey('Person', related_name='votes')
email = models.EmailField()
Я могу получить положение пользователя, используя этот метод в модели person:
@property
def position(self):
person_list = Person.objects.annotate(Count('votes')).order_by(
'-votes__count', 'name')
for i, x in enumerate(person_list, start=1):
if x == self:
return i
Проблема в том, что набор запросов person_list вычисляется каждый раз при вызове метода position, который, на мой взгляд, запускает ненужные запросы к базе данных, поскольку этот запрос нужно выполнить только один раз во время цикла запроса / ответа. В идеале я хочу воспользоваться кэшем набора запросов. У кого-нибудь есть идеи, как я мог бы это сделать?
Спасибо.
РЕДАКТИРОВАТЬ: я вызываю метод position из шаблона, поэтому не думаю, что смогу передать набор запросов в качестве аргумента.
Ответ №1:
Вы могли бы просто сохранить его внутри модели
@property
def position(self):
if not self.entry_list:
self.entry_list = Entry.objects.annotate(Count('votes')).order_by(
'-votes__count', 'name')
for i, x in enumerate(self.entry_list, start=1):
if x == self:
return i
Однако этот запрос, похоже, не зависит от конкретной модели, я бы, скорее всего, использовал Manager для создания запроса и сохранения его там локально.
class PersonManager(models.Manager):
def most_votes(self):
if not self.most_votes_queryset:
self.most_votes_queryset = self.get_query_set()
.annotate(Count('votes'))
.order_by('-votes__count','name')
return self.most_votes_queryset
class Person(models.Model):
objects = VoteManager()
что тогда привело бы к вашей модели:
@property
def position(self):
entry_list = Person.objects.most_votes()
for i, x in enumerate(entry_list, start=1):
if x == self:
return i
Ответ №2:
Как насчет чего-то подобного:
def position(self):
if hasattr(self, '_position'):
return self._position
person_list = Person.objects.annotate(vc=Count('votes'))
.order_by('-vc', 'name')
num_votes = self.votes.count()
place = person_list.filter(vc__gt=num_votes).count()
place = person_list.filter(vc=num_votes, name__lte=self.name).count()
self._position = place
return place
Я думаю, это должно работать * лучше *, если у вас много записей в таблице модели Person и это позиция кэширования в объекте модели.