【问题标题】:prefetch_related doesn't cacheprefetch_related 不缓存
【发布时间】:2013-07-30 15:28:36
【问题描述】:

我简直被难住了。我正在尝试在我的 django 应用程序中实现 prefect_related 的教科书案例,但它根本行不通。以下是相关模型:

class CanUseUnit(models.Model):

  objects = UnitManager()

  ingredient = models.ForeignKey('Ingredient', db_column='ingredient', related_name='useable_units')
  unit = models.ForeignKey('Unit', related_name='used_by', db_column='unit', limit_choices_to=models.Q(parent_unit__exact=None))

请注意,虽然这个模型有一个自定义管理器,但这是models.Managar 的一个简单子类,只有一个名为get_all_info() 的方法,所以我认为这与我的问题无关:

我正在尝试查询所有成分,并预取它们的可用单位。这是我的 Django 查询:

def list_ingredients(request):
  ingredients = Ingredient.objects.all().order_by('accepted', 'name').prefetch_related('useable_units')
  for ingredient in ingredients:
    print(ingredient.useable_units.all())

  return render(request, 'admin/list_ingredients.html', {'ingredients': ingredients})

但 Django 似乎在每条print 语句中都会访问数据库……这是怎么回事?

编辑:

从模板调用缓存似乎确实有效。当我在上面的视图中省略打印语句,并访问包含以下模板代码的页面:

{% for ingredient in ingredients %}
<tr>
  <td><a href="/ingredients/edit/{{ ingredient.id }}/">{{ ingredient.name }}</a></td>
  <td align="center">{{ ingredient.useable_units.count }}</td>
</tr>

{% endfor %}

数据库只被访问了两次(我预计,一次用于成分,一次用于 prefetch_related)。

已解决: 好吧,问题似乎已经自行解决了……我一直在尝试并重新启动测试服务器,但它突然停止查询每种成分。不知道发生了什么,但我很高兴它解决了。

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    我发现了问题。 Shacki 的回答是错误的,与预取相关的确实只需要 2 个查询,而不是每个成分一个。

    我的错误出现在模板的不同部分,我正在显示中间模型的属性。

    所以我应该做的是:

    ingredients = Ingredient.objects.all().order_by('accepted', 'name').prefetch_related('canuseunit_set')
    

    代替:

    ingredients = Ingredient.objects.all().order_by('accepted', 'name').prefetch_related('useable_units')
    

    【讨论】:

      【解决方案2】:

      如果您查看文档:https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related,它会说

      另一方面,prefetch_related 对每个关系进行单独的查找,并在 Python 中进行“连接”

      据我了解,这正是你所看到的。

      【讨论】:

      • 好吧,我发现了一个以前的 SO 问题,从接受的答案中,我被引导相信它只会做 2 个查询(不是每个成分 1 个):link 但如果这是不是这样,有没有办法批量做prefetch_related?
      • 似乎有一个误解,relation 是 ForeignKey 关系,所以“对于每个关系”意味着每个 ForeignKey、OneToOne、ManyToMany 等。所以是的,在你的情况下它只有 2,但是什么他的帖子也是正确的。它没有回答你的问题,但事实上也没有错。
      猜你喜欢
      • 1970-01-01
      • 2018-08-11
      • 2021-08-25
      • 2019-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多