我有以下模型(这些模型被显著简化(:
class Job(models.Model):
name = models.CharField(max_length=255)
def get_date_details(self):
pass
#return a list of all jobdate --> details
class JobDate(models.Model):
job = models.ForeignKey(Job, on_delete=models.CASCADE, related_name='dates')
date = models.DateField()
# ... and a bunch of other fields
class JobDateDetail(models.Model):
job_date = models.ForeignKey(JobDate, on_delete=models.CASCADE, related_name='details')
detail = models.CharField(max_length=255)
# ... and a bunch of other fields
并且需要定期处理数据库中所有作业的JobDateDetails
(几千个(。我知道我可以通过以下查询预取所有数据:
q = Job.objects.all().prefetch_related('dates', 'dates__details')
但是,我不知道如何最好地利用Job.get_date_details()
中预取的数据。一种选择是做一些类似的事情:
class Job(models.Model):
def get_date_details(self):
details = []
for job_date in self.dates.all():
details += [detail for detail in job_date.details.all()]
return details
然而,我怀疑可能有一种方法可以直接查询所有这些JobDateDetail
对象。需要注意的一点是,如前所述,我意识到我可以朝另一个方向一次性获取所有细节,但在这种情况下,我使用的是Django Rest Framework,需要将细节组装为Job序列化程序中的一个字段,这需要我从这个方向出发。想法?
我输入了一些随机数据来演示查询。这里有两个选项:
-
第一个在表级,1db命中:
In [23]: Job.objects.all().values_list('id', 'dates__details__detail') Out[23]: <QuerySet [(1, '132'), (1, '4324gg'), (1, 'hrthrthrth'), (1, 'erhehrgnfgnmfgghmn'), (1, 'herhehrnfn'), (1, 'erg eg cvb dfg vb'), (1, 'greg egr erg erg erg'), (1, 'ewrg erg db cvb'), (2, None), (3, None)]>
-
第二个是行级2db命中(一个用于获取对象,另一个用于提取其日期详细信息(:
In [36]: Job.objects.all().first().dates.all().values_list('details__detail') Out[36]: <QuerySet [('132',), ('4324gg',), ('hrthrthrth',), ('erhehrgnfgnmfgghmn',), ('herhehrnfn',), ('erg eg cvb dfg vb',), ('greg egr erg erg erg',), ('ewrg erg db cvb',)]>
如果从模型方法get_date_details
调用第二个,则等效于self.dates.all().values_list('details__detail')
,并且可以在1db命中的情况下产生以下结果:
In [30]: from itertools import chain
In [31]: list(chain.from_iterable(
...: Job.objects.all().first().dates.all().values_list('details__detail')
...: ))
Out[31]:
['132',
'4324gg',
'hrthrthrth',
'erhehrgnfgnmfgghmn',
'herhehrnfn',
'erg eg cvb dfg vb',
'greg egr erg erg erg',
'ewrg erg db cvb']
因此,您的模型方法可以变成:
class Job(models.Model):
def get_date_details(self):
return (
list(chain.from_iterable(
self.dates.all().values_list('details__detail')
))
)