【发布时间】:2022-01-21 15:32:03
【问题描述】:
我正在尝试发出一个预取所有数据的请求,以减少对我的数据库的请求量。我使用prefetch_related() 方法和Prefetch 对象类来告诉在同一个请求中加载什么。
代码:
pairs_queryset = Pair.objects.filter(quote_id="2781", last_price__isnull=False) \
| Pair.objects.filter(quote_id="825", last_price__isnull=False) \
| Pair.objects.filter(quote_id="3408", last_price__isnull=False)
queryset = Portfolio.objects.prefetch_related(
Prefetch('connections__wallets__currency__metadata__images'),
Prefetch('connections__wallets__currency__base_pairs', queryset=pairs_queryset),
).get(id=portfolio_id)
data = Serializer(queryset).data
型号:
class Connection(models.Model):
exchange = models.ForeignKey(Exchange, related_name='exchange', on_delete=models.CASCADE)
portfolios = models.ManyToManyField(Portfolio, related_name='connections')
# ...
class Pair(models.Model):
id = models.IntegerField(primary_key=True) # CoinMarketCap id
exchange = models.ForeignKey(Exchange, related_name='pairs', on_delete=models.CASCADE)
# ...
我的数据库中有多个base_pairs 与Exchange 有关系(见上文)。
我的问题:
我想向预取相关对象添加一个过滤器,该过滤器使用包含在预取的连接(即exchange_id)中的值,如下所示:
connections__wallets__currency__base_pairs
^ |
|_______________________________|
depends on the current
connection's exchange_id attribute
由于connections 是一个集合(多个值),我想要以下内容:connections__wallets__currency__base_pair 检索与当前获取的connection 相关的base_pairs。
我阅读了文档,但找不到任何解决方案。使用预取大大减少了请求时间(约 5 秒而不是约 3 分钟)。
另一种方式:
# get portfolio + prefetch connections (and other things...)
portfolio = Portfolio.objects.prefetch_related(
'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 connections
prefetch_related_objects(
[connection],
Prefetch('wallets__currency__base_pairs', queryset=pairs_queryset),
)
在这里,Django 正在重用来自循环的先前连接查询的缓存。所以它非常快。但是,缓存的 base_pairs 在结果中混杂在一起,因为 Django 忘记了我传递给 Prefetch() 实例的过滤器查询集。显然,这似乎是 Django 的一个错误。所以我正在寻找另一种方法来实现这一目标。
【问题讨论】:
标签: python django django-models django-rest-framework django-views