Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Django Queryset预取优化用于迭代嵌套结果_Django_Django Models_Django Queryset_Django Orm - Fatal编程技术网

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 =

考虑到我想要获取嵌套关系,我正在寻找一种通过提高数据库访问性能来优化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 = 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