Фильтр не работает с prefetch_related_objects - Django
Я пытаюсь написать представление, которое предварительно получает содержимое запроса, чтобы ускорить выполнение запроса (3.5s вместо 3min при цепочке запросов).
Целью является выборка некоторых строк (Exchange_pair
объектов) в зависимости от значения корневой модели в пути предварительной выборки (connection.exchange_id
).
connections__wallets__currency__base_pairs
^ |
|_______________________________|
depends on the current
connection's exchange_id
Вид:
@api_view(['GET'])
@permission_classes([permissions.IsAuthenticated])
def get_portfolio_view(request):
portfolio_id = request.GET.get('id')
# get portfolio + prefetch connections (and other things...)
portfolio = Portfolio.objects.prefetch_related(
'connections__exchange',
'connections__wallets__currency__metadata__images'
).get(id=portfolio_id)
for connection in portfolio.connections.all():
# build filter
pairs_queryset = ExchangePair.objects.filter(
exchange_id=connection.exchange_id,
quote_id__in=["825", "2781", "3408", "4687"],
last_price__isnull=False,
)
# prefetch for related connection
prefetch_related_objects(
[connection],
Prefetch('wallets__currency__base_pairs', queryset=pairs_queryset)
)
data = PortfolioSerializer(portfolio).data
return Response(data)
Модели:
class Connection(models.Model):
exchange = models.ForeignKey(Exchange, related_name='exchange', on_delete=models.CASCADE)
portfolios = models.ManyToManyField(Portfolio, related_name='connections')
# ...
class ExchangePair(models.Model):
id = models.IntegerField(primary_key=True) # CoinMarketCap id
exchange = models.ForeignKey(Exchange, related_name='pairs', on_delete=models.CASCADE)
# ...
Код работает в 90% случаев. Он не работает, когда ExchangePair
находится в нескольких соединениях запроса. Django просто повторно использует префетчированные ExchangePair
данные предыдущего Connection
. Как мне сделать каждый префетч независимым в цикле?
Удаление повторного использования кэша в коде Django из prefetch_related_objects()
(django/db/models/query.py, строка 1690) заставляет его работать. Я удаляю условие, которое проверяет, кэшируются ли объекты, так что из этого:
if not hasattr(obj, '_prefetched_objects_cache'):
try:
obj._prefetched_objects_cache = {}
except (AttributeError, TypeError):
# ...
К этому:
try:
obj._prefetched_objects_cache = {}
except (AttributeError, TypeError):
# Must be an immutable object from
Однако это делает запрос очень медленным. Таким образом, Django, похоже, работает неправильно, поскольку он загружает объект из кэшированного объекта, который не является точно таким же.