Django Queryset预取优化用于迭代嵌套结果
考虑到我想要获取嵌套关系,我正在寻找一种通过提高数据库访问性能来优化Django中queryset结果处理的方法 例如,我制作了以下结构:Django Queryset预取优化用于迭代嵌套结果,django,django-models,django-queryset,django-orm,Django,Django Models,Django Queryset,Django Orm,考虑到我想要获取嵌套关系,我正在寻找一种通过提高数据库访问性能来优化Django中queryset结果处理的方法 例如,我制作了以下结构: class Movie(models.Model): name = models.CharField(max_length=50) class Ticket(models.Model): code = models.CharField(max_length=255, blank=True, unique=True) movie =
class Movie(models.Model):
name = models.CharField(max_length=50)
class Ticket(models.Model):
code = models.CharField(max_length=255, blank=True, unique=True)
movie = models.ForeignKey(Movie, related_name='tickets')
class Buyer(models.Model):
name = models.CharField(max_length=50)
class Purchase(models.Model):
tickets = models.ManyToManyField(Ticket, related_name='purchases')
buyer = models.ForeignKey(Buyer, related_name='purchases')
假设我有一个电影查询集:
movies = Movie.objects.all().prefetch_related('tickets__purchases__buyer')
如果我想从qs中的每部电影中检索所有买家,我可以这样做:
for movie in movies:
buyers = Buyer.objects.filter(purchases__tickets__in=movie.tickets.all()).distinct()
但在这种方法中,每次迭代的电影都会再次命中数据库。要解决此问题,我将执行以下操作:
def get_movie_buyers(movie):
buyers = set()
for ticket in movie.tickets.all():
for purchase in ticket.purchases.all():
if purchase.buyer:
buyers.add(purchase.buyer)
return buyers
for movie in movies:
buyers = get_movie_buyers(movie)
# do something with the buyers
movies = Movie.objects.prefetch_related(
Prefetch(lookup='tickets__purchases__buyer',
to_attr='buyers')
).all()
for movie in movies:
print movie.buyers
这样它只会访问数据库一次,因为我以前使用过prefetch_related,但我认为这不是一个好方法,因为我必须迭代许多嵌套循环,这将增加内存过载
我认为有更好的方法,但我仍然没有找到“正确”的方法,我希望有人能指导我
更新
如前所述,使用预回迁对象,但我已尝试使用以下方法:
def get_movie_buyers(movie):
buyers = set()
for ticket in movie.tickets.all():
for purchase in ticket.purchases.all():
if purchase.buyer:
buyers.add(purchase.buyer)
return buyers
for movie in movies:
buyers = get_movie_buyers(movie)
# do something with the buyers
movies = Movie.objects.prefetch_related(
Prefetch(lookup='tickets__purchases__buyer',
to_attr='buyers')
).all()
for movie in movies:
print movie.buyers
这给了我以下错误:
“电影”对象没有“买家”属性
它看起来太难的原因是购买和门票之间有很多关系
这种关系允许同一张票出现在多次购买中。但实际数据并非如此,因为一张票只能购买一次。
如果删除此ManyToMany字段并在Ticket to purchase中添加ForeignKey字段,则可以简化查询
class Ticket(models.Model):
code = models.CharField(max_length=255, blank=True, unique=True)
movie = models.ForeignKey(Movie, related_name='tickets')
purchase = models.ForeignKey(Purchase, null=True, blank=True)
然后查询可以简化如下
movies = Movie.objects.all().prefetch_related('tickets__purchase__buyer')
for movie in movies:
print(set(ticket.purchase.buyer for ticket in movie.tickets if ticket.purchase))
当您需要使用purchase\u id更新票证对象时,确保这会在创建购买时增加复杂性
您需要根据这两个操作的频率来调用在何处保持复杂性我想您可以使用
Prefetch()
对象来实现这一点。我尝试过使用Prefetch()对象:Prefetch(lookup='tickets'\uu purchases'\uu buyer',to'u attr='buseers'),但我不知道如何构建queryset参数,因为所查询的买家与自拍照相关。你能给我举个例子吗?很抱歉,我不知道如何处理你的案例,我留下了评论,因为我认为这是可能的。尝试在预回迁之后添加.all()
,调用相关的调用。all()
我得到了AttributeError