Django 使用 select_related() 仍然访问 MySQL?
我正在尝试优化一个相对较小的Django应用程序中的数据库调用。目前我有几个模型,分别是Inquiry
和InquiryStatus
。当我从MySQL中选择所有记录时,我得到了一个很好的JOIN
语句,这个语句连接了两个表,但接下来却有很多请求去访问InquiryStatus表。即使我已经使用了select_related()
,为什么Django还会发出单独的请求呢?
模型大致长这样:
class InquiryStatus(models.Model):
status = models.CharField(max_length=25)
status_short = models.CharField(max_length=5)
class Meta:
ordering = ["-default_status", "status", "status_short"]
class Inquiry(models.Model):
ts = models.DateTimeField(auto_now_add=True)
type = models.CharField(max_length=50)
status = models.ForeignKey(InquiryStatus)
class Meta:
ordering = ["-ts"]
我为了调试写的视图大致长这样:
def inquiries_list(request, template_name="inquiries/list_inquiries.js"):
## Notice the "print" on the following line. Forces evaluation.
print models.Inquiry.objects.select_related('status').all()
return HttpResponse("CRAPSTICKS")
我尝试使用select_related(depth=1)
,但没有任何变化。每个多余的数据库请求都是在WHERE
子句中选择一个特定的id
。
更新:
有一段非常重要的代码应该放在模型中:
from fullhistory import register_model
register_model(Inquiry)
register_model(InquiryStatus)
结果是,fullhistory
(出于我无法理解的原因)在获取每个单独的结果并进行解析。
3 个回答
你展示的代码其实不会生成任何查询。QuerySets(查询集)只有在需要的时候才会被计算,而不是在定义的时候。因为你没有在任何地方使用这个值,所以它不会被执行。
请给我们看看一个模板或者其他代码,这些代码实际上会对这个查询集进行计算,比如切片、遍历、打印,或者其他操作。
我觉得这和“懒惰求值”有关。Django 只有在必要的时候才会去访问数据库,而不是在你调用模型的时候就去访问。例如,当你使用 Inquiry.objects.select_related('status').all() 这个命令时,Django 可能会等到真正需要数据的时候才去查询数据库。
看起来 fullhistory 最终会把对象进行序列化,这个过程会检查实例中的每个字段,以便给它一个比较的基础。
你可以看看 get_all_data
这个函数:
http://code.google.com/p/fullhistory/source/browse/trunk/fullhistory/fullhistory.py
如果有人想详细解释一下为什么会这样,我会很乐意把那个答案标记为正确。