我正在寻找一种通过提高数据库访问性能来优化Django中的查询集结果处理的方法,考虑到我想获取嵌套关系。
例如,我已经建立了这个结构:
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')
我们说我有一个Movie QuerySet:
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
这样它只会打到数据库一次,因为之前我使用过prefetch_related,但我不认为这是一个很好的方法,因为我必须迭代许多嵌套循环,这将增加内存过载
我认为这是一个更好的方法,但我仍然没有弄清楚“正确的”#39;我希望有人可以指导我完成它。
提到alasdair,使用Prefetch对象,但我已经尝试使用以下内容:
movies = Movie.objects.prefetch_related(
Prefetch(lookup='tickets__purchases__buyer',
to_attr='buyers')
).all()
for movie in movies:
print movie.buyers
这给了我以下错误:
'Movie' object has no attribute 'buyers'
答案 0 :(得分:0)
之所以看起来太困难,是因为“购买”和“票证”之间的“多对多”关系。
此关系允许同一票可以多次购买。但这在实际数据中并非如此,因为一张票只能购买一次。 如果删除此ManyToMany字段并在要购买的票证中添加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_id更新票证对象。
您需要根据两个操作的频率来调用将复杂性保持在何处