【发布时间】:2017-05-03 05:55:53
【问题描述】:
我有一个数据库结构,可以简化如下(版本和附加信息未显示,因为与我的问题没有直接关系):
class Image(models.Model):
file = models.ImageField(blank=False, null=False, upload_to='images')
version = models.ForeignKey(Version, blank=False, null=False)
class ExampleImage(models.Model):
example = models.ForeignKey('Example', blank=False, null=False)
image = models.ForeignKey(Image, blank=False, null=False)
additional_info = models.ForeignKey(AdditionalInfo, blank=True, null=True)
class Example(models.Model):
name = models.Charfield(max_length=255)
images = models.ManyToManyField(Image, through=ExampleImage, through_fields=('example', 'image')
def get_default_image(self):
try:
image = self.images.get(version=Version.objects.get(name=DEFAULT_VERSION))
except Image.DoesNotExist:
# Get some other image, this happens maybe 1 out of 10
现在我有一个非常常见的需求,即查询所有 Example 对象及其默认图像。目前,我正在做以下事情:
example_list = []
examples = Example.objects.all()
for example in examples:
example_dict = dict(name=example.name, image=example.get_default_image())
example_list.append(example_dict)
# Then show example_list in template
这种方法有效,但它会导致数千个数据库查询,并且需要一分钟以上的时间来执行,这对于下载单个网页来说太长了!
所以我的问题是,优化这种用例的正确方法是什么。我可以为 Example 模型设置 default_image 字段(然后使用 select_related,但这会使添加图像更加复杂),将版本 ID 硬编码为 get_default_image 方法(不太灵活),将 get_default_image 方法设置为 cached_property 等,但我不完全确定应该使用哪种方法。我已经尝试了很多技巧,但似乎对我的情况没有任何帮助。我应该找到一种解决方案,它允许我用一个大查询同时查询示例和默认图像,而不是在 for 循环中进行工作。
【问题讨论】:
标签: django django-models django-queryset database-optimization