🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[参考文档][1] ### 查看 Django queryset 执行的 SQL 在QuerySet最后增加query,即可查询SQL ~~~ Author.objects.all().query ~~~ ### extra 实现 别名 原始名称和别名都会显示 ~~~ Tag.objects.all().extra(select={'tag_name': 'name'}).query.__str__() Out[47]: u'SELECT (name) AS "tag_name", "blog_tag"."id", "blog_tag"."name" FROM "blog_tag"' ~~~ 不显示原始名称,使用defer除去 ~~~ Tag.objects.all().extra(select={'tag_name': 'name'}).defer('name').query.__str__() Out[49]: u'SELECT (name) AS "tag_name", "blog_tag"."id" FROM "blog_tag"' ~~~ ### defer 排除不需要的字段 在复杂的情况下,表中可能有些字段内容非常多,取出来转化成 Python 对象会占用大量的资源。 这时候可以用 defer 来排除这些字段,比如我们在文章列表页,只需要文章的标题和作者,没有必要把文章的内容也获取出来(因为会转换成python对象,浪费内存) ### only 仅选择需要的字段 和 defer 相反,only 用于取出需要的字段,假如我们只需要查出 作者的名称 ~~~ Author.objects.all().only('name') ~~~ >[info] only类似于value_list只获取一个字段 ### select_related 优化一对一,多对一查询 查询了两次 ~~~ >>> art = Article.objects.filter(id=1).first() (0.000) SELECT "app_article"."id", "app_article"."title", "app_article"."author_id", "app_article"."content", "app_article"."score" FROM "app_article" WHERE "app_article"."id" = 1 ORDER BY "app_article"."id" ASC LIMIT 1; args=(1 ,) >>> art.title 'Django 教程_1' >>> art.author (0.000) SELECT "app_author"."id", "app_author"."name", "app_author"."qq", "app_author"."addr", "app_author"."email" FROM "app_author" WHERE "app_author"."id" = 2; args=(2,) <Author: twz915> >>> art.author.name 'twz915' ~~~ 查询了一次 ~~~ >>> art = Article.objects.filter(id=1).select_related('author').first() (0.000) SELECT "app_article"."id", "app_article"."title", "app_article"."author_id", "app_article"."content", "app_article"."score", "app_author"."id", "app_author"."name", "app_author"."qq", "app_author"."addr", "app_author"."e mail" FROM "app_article" INNER JOIN "app_author" ON ("app_article"."author_id" = "app_author"."id") WHERE "app_article"."id" = 1 ORDER BY "app_article"."id" ASC LIMIT 1; args=(1,) >>> art.author <Author: twz915> >>> art.author.name 'twz915' ~~~ ### prefetch_related 优化一对多,多对多查询 和 select_related 功能类似,但是实现不同。 select_related 是使用 **SQL JOIN** 一次性取出相关的内容。 prefetch_related 用于 一对多,多对多 的情况,这时 select_related 用不了,因为当前一条有好几条与之相关的内容。 prefetch_related是通过再执行一条额外的SQL语句,然后用 Python 把两次SQL查询的**内容关联**(joining)到一起 >[info]使用和不使用的区别在第二步,会不会有查询`art.tags.all()` 使用prefetch_related ~~~ >>> art = Article.objects.all().prefetch_related('tags').first() (0.000) SELECT "app_article"."id", "app_article"."title", "app_article"."author_id", "app_article"."content", "app_article"."score" FROM "app_article" ORDER BY "app_article"."id" ASC LIMIT 1; args=() (0.001) SELECT ("app_article_tags"."article_id") AS "_prefetch_related_val_article_id", "app_tag"."id", "app_tag"."name" FROM "app_tag" INNER JOIN "app_article_tags" ON ("app_tag"."id" = "app_article_tags"."tag_id") WHERE "app_a rticle_tags"."article_id" IN (1); args=(1,) >>> art.tags.all() <QuerySet [<Tag: Django>]> >>> art.tags.all().first().name (0.000) SELECT "app_tag"."id", "app_tag"."name" FROM "app_tag" INNER JOIN "app_article_tags" ON ("app_tag"."id" = "app_article_tags"."tag_id") WHERE "app_article_tags"."article_id" = 1 ORDER BY "app_tag"."id" ASC LIMIT 1; args=( 1,) 'Django' ~~~ 不使用prefetch_related ~~~ >>> art = Article.objects.all().first() (0.000) SELECT "app_article"."id", "app_article"."title", "app_article"."author_id", "app_article"."content", "app_article"."score" FROM "app_article" ORDER BY "app_article"."id" ASC LIMIT 1; args=() >>> art.tags.all() (0.000) SELECT "app_tag"."id", "app_tag"."name" FROM "app_tag" INNER JOIN "app_article_tags" ON ("app_tag"."id" = "app_article_tags"."tag_id") WHERE "app_article_tags"."article_id" = 1 LIMIT 21; args=(1,) <QuerySet [<Tag: Django>]> >>> art.tags.all().first().name (0.000) SELECT "app_tag"."id", "app_tag"."name" FROM "app_tag" INNER JOIN "app_article_tags" ON ("app_tag"."id" = "app_article_tags"."tag_id") WHERE "app_article_tags"."article_id" = 1 ORDER BY "app_tag"."id" ASC LIMIT 1; args=( 1,) 'Django' ~~~ [1]:http://code.ziqiangxuetang.com/django/django-queryset-advance.html