Django也能智能LazyLoad?

今天在本地很快实现了最新评论的功能。在右手边的最新评论点击连接时会去到文章的页面,并定位到评论所在的锚点上,也就是说,我需要在页面上取得评 论所在文章的ID,也就是需要这样:{{comment.comment_to.id}}。这时候,我仅仅需要获得文章的ID,但不知道Django是否 会到数据库去把相应的文章查出来(我没有使用Select_relate)之后再拿ID呢?不过Django好现没有可以设置打印执行Sql语句的开关, 并不能通过配置来看到运行时Django查了多少次数据库。而这样的功能,我使用Java的Hibernate时就有的。

我Google了一下,发现Django本身是没有提供日志和Sql打印功能的。而有人做了些工作,如这位仁兄写了个中间件,可以在页面上打印出该次请求一共执行了多少条语句,每条语句的执行时间。而这里有个叫Django-logging的项目,为Django提供Logging,包括Sql的打印。等会就试验一下。Django天生就是Lazyload的,需要用到数据的时候才去加载,我希望,我的担心是多余的。一会尝试使用Log来看看测试结果吧。

结果一:Select_related对允许为空的外键不起作用。
我的查询语句是这样:entries = blog.entry_set.filter(status=1).select_related(depth=1).order_by('-id') 查询一个Blog下面所有的Entry,并把有关联的数据一并抓取出来(根据ForeignKey)。也就是说,在查询Entry的同时查出Blog,作 者,分类等信息。
但是情况是,我在页面找印这些文章的时候,需要把文章的分类也打显示出来,这时候,Django却跑到数据库执行了N次查询分类的语句。暴汗。这是经典的 Hibernate的延迟加载用得不恰当的情况啊!我一看打印出来的查询语句,有查相关的作者、Blog,但偏偏没有查分类。最后我回到Model里比较 了一下,我的分类属性上面设置了null=true,原意是让文章可以没有分类。最后我尝试着去掉Null=true,一运行。那N条查询不见了。靠。。原来Select_related在外键允许空的情况下是行不通D。

结果二:Django不会智能LazyLoad。要手动去Select_related。
回到对Django有疑问的情景,recent_comments = Comment.objects.filter(blog=blog).order_by('-comment_time')[:10] 查出本BLog最新的十条评论。我的假设是,Comment本身保存有Entry的ID,所以在仅仅是获取Entry的ID的时候不需要去数据据里找, Hibernate的LazyLoad就是这样做的,使用动态代理的解决方案。我想在Python这样的动态语言的解决方案更佳,但事实证明我错了。上面 的语句又产生了经典的1+N的问题。我在页面根据评论取EntryID的时候{{comment.entry.id}}还是去加载了一次数据,搞笑的是, 这句查询需要得到的数据对我有用的是ID,但是查询条件就是ID。我只好把查询语句改成:
recent_comments = Comment.objects.select_related(depth=1).filter(blog=blog).order_by('-comment_time') [:10]。显示去Select_related。宁愿直接去Join相关的表,也不要做1+ N的查询。显然这很浪费,仅仅为了一个ID,要Join好几个表。

原文在这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值