Django-model进阶(中介模型,查询优化,extra,整体插入)

前端之家收集整理的这篇文章主要介绍了Django-model进阶(中介模型,查询优化,extra,整体插入)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

<div class="postBody">
<div id="cnblogs_post_body">

QuerySet

可切片

查询集记录的数目。sql 的子句。

Highlighter sh-gutter">
Highlighter_854643" class="SyntaxHighlighter sql">

</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="sql plain">>>> Entry.objects.<code class="sql color1">all<code class="sql plain">()[:5] # (LIMIT5)

</td>

</tr>

</table>

>>> Entry.objects.all()[5:10]    # (OFFSET5LIMIT5)

不支持负的索引(例如)。通常,的切片返回一个新的—— 它不会执行查询。

可迭代

articleListmodels.Article.objects.<span style="color: #0000ff;">for article <span style="color: #808080;">in<span style="color: #000000;"> articleList:
<span style="color: #0000ff;">print(article.title)

惰性查询

是惰性执行的 —— 创建不会带来任何数据库的访问。需要求值时,Django 才会真正运行这个查询。

sql plain">queryResult=models.Article.objects.sql color1">allsql plain">() # sql color1">not sql plain">hits sql keyword">database
sql plain">print(queryResult) # hits sql keyword">database
sql keyword">for sql plain">article sql color1">in sql plain">queryResult:
sql spaces">sql plain">print(article.title) # hits sql keyword">database

查询集的结果时才会到数据库中去获取它们。查询集通过访问数据库求值何时计算查询集。

缓存机制

查询集都包含一个缓存来最小化对数据库的访问。代码。

查询集中,缓存为空。查询集进行求值 —— 同时发生数据库查询 ——Django 将保存查询的结果到查询集的缓存中并返回明确请求的结果(例如,如果正在迭代查询集,则返回下一个结果)。查询集的求值将重用缓存的结果。

查询集使用不当的话,它会坑你的。查询集,对它们求值,然后扔掉它们:

Highlighter sh-gutter">
Highlighter_650216" class="SyntaxHighlighter sql">

Article并重新使用它:

sql plain">queryResult=models.Article.objects.sql color1">allsql plain">()
sql plain">print([a.title sql keyword">for sql plain">a sql color1">in sql plain">queryResult])
sql plain">print([a.create_time sql keyword">for sql plain">a sql color1">in sql plain">queryResult])

查询集不会被缓存?

查询集不会永远缓存它们的结果。查询集的部分进行求值时会检查缓存, 如果这个部分不在缓存中,那么接下来查询返回的记录都将不会被缓存。所以查询集将不会填充缓存。

获取查询集对象中一个特定的索引将每次都查询数据库

Highlighter sh-gutter">
Highlighter_290732" class="SyntaxHighlighter python">
>> queryset
>>
>>

然而,如果已经对全部查询集求值过,则将检查缓存:

>> queryset
>> [entry
>>
>>

下面是一些其它例子,它们会使得全部的查询集被求值并填充到缓存中:

Highlighter sh-gutter">
Highlighter_981435" class="SyntaxHighlighter python">
>> [entry
>>
>> entry
>>

exists()与iterator()方法

exists:

简单的使用if语句进行判断也会完全执行整个queryset并且把数据放入cache,虽然你并不需要这些 数据!为了避免这个,可以用exists()方法来检查是否有数据:

()

iterator:

当queryset非常巨大时,cache会成为问题。

处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的queryset可能会锁住系统 进程,让你的程序濒临崩溃。要避免在遍历数据的同时产生queryset cache,可以使用iterator()方法 来获取数据,处理完数据就将其丢弃。

objs =数据库获取少量数据,这样可以节省内存
 obj 
 obj (obj.title)

当然,使用iterator()方法来防止生成cache,意味着遍历同一个queryset时会重复执行查询。所以使 #用iterator()的时候要当心,确保你的代码在操作一个大的queryset时没有重复执行查询

总结:

queryset的cache是用于减少程序对数据库查询,在通常的使用下会保证只有在需要的时候才会查询数据库。 使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能 会造成额外的数据库查询。 

中介模型

就可以了。

表示小组和成员之间的多对多关系。

字段将使用参数指向中介模型。代码如下:

Highlighter sh-gutter">
Highlighter_865466" class="SyntaxHighlighter python">
>>
>> beatles.members.clear()
>>
>> Membership.objects.

查询优化

表数据

Highlighter sh-gutter">
Highlighter_543493" class="SyntaxHighlighter sql">
sql plain">class UserInfo(AbstractUser):
sql spaces">sql string">""sql string">"
sql spaces">sql string">用户信息
sql spaces">sql string">"sql string">""
sql spaces">sql plain">nid = models.BigAutoField(primary_key=sql keyword">Truesql plain">)
sql spaces">sql plain">nickname = models.CharField(verbose_name=sql string">'昵称'sql plain">,max_length=32)
sql spaces">sql plain">telephone = models.CharField(max_length=11,blank=sql keyword">Truesql plain">,sql color1">nullsql plain">=sql keyword">Truesql plain">,sql keyword">uniquesql plain">=sql keyword">Truesql plain">,verbose_name=sql string">'手机号码'sql plain">)
sql spaces">sql plain">avatar = models.FileField(verbose_name=sql string">'头像'sql plain">,upload_to = sql string">'avatar/'sql plain">,sql keyword">defaultsql plain">=sql string">"/avatar/default.png"sql plain">)
sql spaces">sql plain">create_time = models.DateTimeField(verbose_name=sql string">'创建时间'sql plain">,auto_now_add=sql keyword">Truesql plain">)
sql spaces">sql plain">fans = models.ManyToManyField(verbose_name=sql string">'粉丝们'sql plain">,
sql spaces">sql keyword">tosql plain">=sql string">'UserInfo'sql plain">,
sql spaces">sql plain">through=sql string">'UserFans'sql plain">,
sql spaces">sql plain">related_name=sql string">'f'sql plain">,
sql spaces">sql plain">through_fields=(sql string">'user'sql plain">,sql string">'follower'sql plain">))
sql spaces">sql plain">def __str__(self):
sql spaces">sql keyword">return sql plain">self.username
sql plain">class UserFans(models.Model):
sql spaces">sql string">""sql string">"
sql spaces">sql string">互粉关系表
sql spaces">sql string">"sql string">""
sql spaces">sql plain">nid = models.AutoField(primary_key=sql keyword">Truesql plain">)
sql spaces">sql color2">user sql plain">= models.ForeignKey(verbose_name=sql string">'博主'sql plain">,sql keyword">tosql plain">=sql string">'UserInfo'sql plain">,to_field=sql string">'nid'sql plain">,related_name=sql string">'users'sql plain">)
sql spaces">sql plain">follower = models.ForeignKey(verbose_name=sql string">'粉丝'sql plain">,related_name=sql string">'followers'sql plain">)
sql plain">class Blog(models.Model):
sql spaces">sql string">""sql string">"
sql spaces">sql string">博客信息
sql spaces">sql string">"sql string">""
sql spaces">sql plain">nid = models.BigAutoField(primary_key=sql keyword">Truesql plain">)
sql spaces">sql plain">title = models.CharField(verbose_name=sql string">'个人博客标题'sql plain">,max_length=64)
sql spaces">sql plain">site = models.CharField(verbose_name=sql string">'个人博客后缀'sql plain">,max_length=32,sql keyword">uniquesql plain">=sql keyword">Truesql plain">)
sql spaces">sql plain">theme = models.CharField(verbose_name=sql string">'博客主题'sql plain">,max_length=32)
sql spaces">sql color2">user sql plain">= models.OneToOneField(sql keyword">tosql plain">=sql string">'UserInfo'sql plain">,to_field=sql string">'nid'sql plain">)
sql spaces">sql plain">def __str__(self):
sql spaces">sql keyword">return sql plain">self.title
sql plain">class Category(models.Model):
sql spaces">sql string">""sql string">"
sql spaces">sql string">博主个人文章分类
sql spaces">sql string">"sql string">""
sql spaces">sql plain">nid = models.AutoField(primary_key=sql keyword">Truesql plain">)
sql spaces">sql plain">title = models.CharField(verbose_name=sql string">'分类标题'sql plain">,max_length=32)
sql spaces">sql plain">blog = models.ForeignKey(verbose_name=sql string">'所属博客'sql plain">,sql keyword">tosql plain">=sql string">'Blog'sql plain">,to_field=sql string">'nid'sql plain">)
sql plain">class Article(models.Model):
sql spaces">sql plain">nid = models.BigAutoField(primary_key=sql keyword">Truesql plain">)
sql spaces">sql plain">title = models.CharField(max_length=50,verbose_name=sql string">'文章标题'sql plain">)
sql spaces">sql keyword">desc sql plain">= models.CharField(max_length=255,verbose_name=sql string">'文章描述'sql plain">)
sql spaces">sql plain">read_count = models.IntegerField(sql keyword">defaultsql plain">=0)
sql spaces">sql plain">comment_count= models.IntegerField(sql keyword">defaultsql plain">=0)
sql spaces">sql plain">up_count = models.IntegerField(sql keyword">defaultsql plain">=0)
sql spaces">sql plain">down_count = models.IntegerField(sql keyword">defaultsql plain">=0)
sql spaces">sql plain">category = models.ForeignKey(verbose_name=sql string">'文章类型'sql plain">,sql keyword">tosql plain">=sql string">'Category'sql plain">,sql color1">nullsql plain">=sql keyword">Truesql plain">)
sql spaces">sql plain">create_time = models.DateField(verbose_name=sql string">'创建时间'sql plain">)
sql spaces">sql plain">blog = models.ForeignKey(verbose_name=sql string">'所属博客'sql plain">,to_field=sql string">'nid'sql plain">)
sql spaces">sql plain">tags = models.ManyToManyField(
sql spaces">sql keyword">tosql plain">=sql string">"Tag"sql plain">,
sql spaces">sql plain">through=sql string">'Article2Tag'sql plain">,
sql spaces">sql plain">through_fields=(sql string">'article'sql plain">,sql string">'tag'sql plain">),
sql plain">)
sql plain">class ArticleDetail(models.Model):
sql spaces">sql string">""sql string">"
sql spaces">sql string">文章详细表
sql spaces">sql string">"sql string">""
sql spaces">sql plain">nid = models.AutoField(primary_key=sql keyword">Truesql plain">)
sql spaces">sql plain">content = models.TextField(verbose_name=sql string">'文章内容'sql plain">,)
sql spaces">sql plain">article = models.OneToOneField(verbose_name=sql string">'所属文章'sql plain">,sql keyword">tosql plain">=sql string">'Article'sql plain">,to_field=sql string">'nid'sql plain">)
sql plain">class Comment(models.Model):
sql spaces">sql string">""sql string">"
sql spaces">sql string">评论
sql spaces">sql string">"sql string">""
sql spaces">sql plain">nid = models.BigAutoField(primary_key=sql keyword">Truesql plain">)
sql spaces">sql plain">article = models.ForeignKey(verbose_name=sql string">'评论文章'sql plain">,to_field=sql string">'nid'sql plain">)
sql spaces">sql plain">content = models.CharField(verbose_name=sql string">'评论内容'sql plain">,max_length=255)
sql spaces">sql plain">create_time = models.DateTimeField(verbose_name=sql string">'创建时间'sql plain">,auto_now_add=sql keyword">Truesql plain">)
sql spaces">sql plain">parent_comment = models.ForeignKey(sql string">'self'sql plain">,verbose_name=sql string">'父级评论'sql plain">)
sql spaces">sql color2">user sql plain">= models.ForeignKey(verbose_name=sql string">'评论者'sql plain">,to_field=sql string">'nid'sql plain">)
sql spaces">sql plain">up_count = models.IntegerField(sql keyword">defaultsql plain">=0)
sql spaces">sql plain">def __str__(self):
sql spaces">sql keyword">return sql plain">self.content
sql plain">class ArticleUpDown(models.Model):
sql spaces">sql string">""sql string">"
sql spaces">sql string">点赞表
sql spaces">sql string">"sql string">""
sql spaces">sql plain">nid = models.AutoField(primary_key=sql keyword">Truesql plain">)
sql spaces">sql color2">user sql plain">= models.ForeignKey(sql string">'UserInfo'sql plain">,sql color1">nullsql plain">=sql keyword">Truesql plain">)
sql spaces">sql plain">article = models.ForeignKey(sql string">"Article"sql plain">,sql color1">nullsql plain">=sql keyword">Truesql plain">)
sql spaces">sql plain">models.BooleanField(verbose_name=sql string">'是否赞'sql plain">)
sql plain">class CommentUp(models.Model):
sql spaces">sql string">""sql string">"
sql spaces">sql string">点赞表
sql spaces">sql string">"sql string">""
sql spaces">sql plain">nid = models.AutoField(primary_key=sql keyword">Truesql plain">)
sql spaces">sql color2">user sql plain">= models.ForeignKey(sql string">'UserInfo'sql plain">,sql color1">nullsql plain">=sql keyword">Truesql plain">)
sql spaces">sql plain">comment = models.ForeignKey(sql string">"Comment"sql plain">,sql color1">nullsql plain">=sql keyword">Truesql plain">)
sql plain">class Tag(models.Model):
sql spaces">sql plain">nid = models.AutoField(primary_key=sql keyword">Truesql plain">)
sql spaces">sql plain">title = models.CharField(verbose_name=sql string">'标签名称'sql plain">,max_length=32)
sql spaces">sql plain">blog = models.ForeignKey(verbose_name=sql string">'所属博客'sql plain">,to_field=sql string">'nid'sql plain">)
sql plain">class Article2Tag(models.Model):
sql spaces">sql plain">nid = models.AutoField(primary_key=sql keyword">Truesql plain">)
sql spaces">sql plain">article = models.ForeignKey(verbose_name=sql string">'文章'sql plain">,sql keyword">tosql plain">=sql string">"Article"sql plain">,to_field=sql string">'nid'sql plain">)
sql spaces">sql plain">tag = models.ForeignKey(verbose_name=sql string">'标签'sql plain">,sql keyword">tosql plain">=sql string">"Tag"sql plain">,to_field=sql string">'nid'sql plain">)

返回一个,当执行它的查询时它沿着外键关系查询关联的对象的数据。生成一个复杂的查询并引起性能的损耗,但是在以后使用外键关系时将不需要数据库查询

函数后,Django会获取相应外键对应的对象,从而在之后需要的时候不必再查询数据库了。

查询和查询的区别。

查询id=2的文章分类名称,查询:

Highlighter sh-gutter">
Highlighter_97516" class="SyntaxHighlighter python">
Highlighter sh-gutter">
Highlighter_256937" class="SyntaxHighlighter sql">
sql string">''sql string">'
sql string">SELECT
sql spaces">sql string">"blog_article"."nid",
sql spaces">sql string">"blog_article"."title",
sql spaces">sql string">"blog_article"."desc",
sql spaces">sql string">"blog_article"."read_count",
sql spaces">sql string">"blog_article"."comment_count",
sql spaces">sql string">"blog_article"."up_count",
sql spaces">sql string">"blog_article"."down_count",
sql spaces">sql string">"blog_article"."category_id",
sql spaces">sql string">"blog_article"."create_time",
sql spaces">sql string">"blog_article"."blog_id",
sql spaces">sql string">"blog_article"."article_type_id"
sql spaces">sql string">FROM "blog_article"
sql spaces">sql string">WHERE "blog_article"."nid" = 2; args=(2,)
sql string">SELECT
sql spaces">sql string">"blog_category"."nid",
sql spaces">sql string">"blog_category"."title",
sql spaces">sql string">"blog_category"."blog_id"
sql spaces">sql string">FROM "blog_category"
sql spaces">sql string">WHERE "blog_category"."nid" = 4; args=(4,)
sql string">'sql string">''

如果我们使用select_related()函数

Highlighter sh-gutter">
Highlighter_449873" class="SyntaxHighlighter sql">
sql plain">articleList=models.Article.objects.select_related(sql string">"category"sql plain">).sql color1">allsql plain">()
sql spaces">sql keyword">for sql plain">article_obj sql color1">in sql plain">articleList:
sql spaces">sql plain"># Doesn't hit the sql keyword">databasesql plain">,because article_obj.category
sql spaces">sql plain"># has been prepopulated sql color1">in sql plain">the prevIoUs query.
sql spaces">sql plain">print(article_obj.category.title)
Highlighter sh-gutter">
Highlighter_235305" class="SyntaxHighlighter sql">
sql keyword">SELECT
sql spaces">sql string">"blog_article"sql plain">.sql string">"nid"sql plain">,
sql spaces">sql string">"blog_article"sql plain">.sql string">"title"sql plain">,
sql spaces">sql string">"blog_article"sql plain">.sql string">"desc"sql plain">,
sql spaces">sql string">"blog_article"sql plain">.sql string">"read_count"sql plain">,
sql spaces">sql string">"blog_article"sql plain">.sql string">"comment_count"sql plain">,
sql spaces">sql string">"blog_article"sql plain">.sql string">"up_count"sql plain">,
sql spaces">sql string">"blog_article"sql plain">.sql string">"down_count"sql plain">,
sql spaces">sql string">"blog_article"sql plain">.sql string">"category_id"sql plain">,
sql spaces">sql string">"blog_article"sql plain">.sql string">"create_time"sql plain">,
sql spaces">sql string">"blog_article"sql plain">.sql string">"blog_id"sql plain">,
sql spaces">sql string">"blog_article"sql plain">.sql string">"article_type_id"sql plain">,
sql spaces">sql string">"blog_category"sql plain">.sql string">"nid"sql plain">,
sql spaces">sql string">"blog_category"sql plain">.sql string">"title"sql plain">,
sql spaces">sql string">"blog_category"sql plain">.sql string">"blog_id"
sql keyword">FROM sql string">"blog_article"
sql color2">LEFT sql color1">OUTER sql color1">JOIN sql string">"blog_category" sql keyword">ON sql plain">(sql string">"blog_article"sql plain">.sql string">"category_id" sql plain">= sql string">"blog_category"sql plain">.sql string">"nid"sql plain">);

多外键查询

这是针对category的外键查询,如果是另外一个外键呢?让我们一起看下:

Highlighter sh-gutter">
Highlighter_60520" class="SyntaxHighlighter sql">

观察logging结果,发现依然需要查询两次,所以需要改为:

sql plain">article=models.Article.objects.select_related(sql string">"category"sql plain">,sql string">"articledetail"sql plain">).get(nid=1)
sql plain">print(article.articledetail)

或者:

articlemodels.Article.objects
             .select_related("category")
             .select_related("articledetail")
             .get(nid) # django 支持链式操作 (article.articledetail)

<div class="cnblogs_Highlighter sh-gutter">

Highlighter_780148" class="SyntaxHighlighter sql">
sql keyword">SELECT
sql spaces">sql string">"blog_article"sql plain">.sql string">"nid"sql plain">,
sql spaces">sql string">"blog_article"sql plain">.sql string">"title"sql plain">,
sql spaces">sql plain">......
sql spaces">sql string">"blog_category"sql plain">.sql string">"nid"sql plain">,
sql spaces">sql string">"blog_category"sql plain">.sql string">"title"sql plain">,
sql spaces">sql string">"blog_category"sql plain">.sql string">"blog_id"sql plain">,
sql spaces">sql string">"blog_articledetail"sql plain">.sql string">"nid"sql plain">,
sql spaces">sql string">"blog_articledetail"sql plain">.sql string">"content"sql plain">,
sql spaces">sql string">"blog_articledetail"sql plain">.sql string">"article_id"
sql spaces">sql keyword">FROM sql string">"blog_article"
sql spaces">sql color2">LEFT sql color1">OUTER sql color1">JOIN sql string">"blog_category" sql keyword">ON sql plain">(sql string">"blog_article"sql plain">.sql string">"category_id" sql plain">= sql string">"blog_category"sql plain">.sql string">"nid"sql plain">)
sql spaces">sql color2">LEFT sql color1">OUTER sql color1">JOIN sql string">"blog_articledetail" sql keyword">ON sql plain">(sql string">"blog_article"sql plain">.sql string">"nid" sql plain">= sql string">"blog_articledetail"sql plain">.sql string">"article_id"sql plain">)
sql spaces">sql keyword">WHERE sql string">"blog_article"sql plain">.sql string">"nid" sql plain">= 1; args=(1,)

深层查询

Highlighter sh-gutter">
Highlighter_99549" class="SyntaxHighlighter sql">
sql plain"># 查询id=1的文章用户姓名
sql spaces">sql plain">article=models.Article.objects.select_related(sql string">"blog"sql plain">).get(nid=1)
sql spaces">sql plain">print(article.blog.sql color2">usersql plain">.username)

依然需要查询两次:

Highlighter sh-gutter">
Highlighter_472473" class="SyntaxHighlighter sql">
sql keyword">SELECT
sql spaces">sql string">"blog_article"sql plain">.sql string">"nid"sql plain">,
sql spaces">sql plain">......
sql spaces">sql string">"blog_blog"sql plain">.sql string">"nid"sql plain">,
sql spaces">sql string">"blog_blog"sql plain">.sql string">"title"sql plain">,
sql spaces">sql keyword">FROM sql string">"blog_article" sql keyword">INNER sql color1">JOIN sql string">"blog_blog" sql keyword">ON sql plain">(sql string">"blog_article"sql plain">.sql string">"blog_id" sql plain">= sql string">"blog_blog"sql plain">.sql string">"nid"sql plain">)
sql spaces">sql keyword">WHERE sql string">"blog_article"sql plain">.sql string">"nid" sql plain">= 1;
sql keyword">SELECT
sql spaces">sql string">"blog_userinfo"sql plain">.sql string">"password"sql plain">,
sql spaces">sql string">"blog_userinfo"sql plain">.sql string">"last_login"sql plain">,
sql spaces">sql plain">......
sql keyword">FROM sql string">"blog_userinfo"
sql keyword">WHERE sql string">"blog_userinfo"sql plain">.sql string">"nid" sql plain">= 1;

这是因为第一次查询没有query到userInfo表,所以,修改如下:

Highlighter sh-gutter">
Highlighter_223440" class="SyntaxHighlighter sql">
sql plain">article=models.Article.objects.select_related(sql string">"blog__user"sql plain">).get(nid=1)
sql plain">print(article.blog.sql color2">usersql plain">.username)
Highlighter sh-gutter">
Highlighter_247105" class="SyntaxHighlighter sql">
sql keyword">SELECT
sql string">"blog_article"sql plain">.sql string">"nid"sql plain">,sql string">"blog_article"sql plain">.sql string">"title"sql plain">,
sql plain">......
sql spaces">sql string">"blog_blog"sql plain">.sql string">"nid"sql plain">,sql string">"blog_blog"sql plain">.sql string">"title"sql plain">,
sql plain">......
sql spaces">sql string">"blog_userinfo"sql plain">.sql string">"password"sql plain">,sql string">"blog_userinfo"sql plain">.sql string">"last_login"sql plain">,
sql plain">......
sql keyword">FROM sql string">"blog_article"
sql keyword">INNER sql color1">JOIN sql string">"blog_blog" sql keyword">ON sql plain">(sql string">"blog_article"sql plain">.sql string">"blog_id" sql plain">= sql string">"blog_blog"sql plain">.sql string">"nid"sql plain">)
sql keyword">INNER sql color1">JOIN sql string">"blog_userinfo" sql keyword">ON sql plain">(sql string">"blog_blog"sql plain">.sql string">"user_id" sql plain">= sql string">"blog_userinfo"sql plain">.sql string">"nid"sql plain">)
sql keyword">WHERE sql string">"blog_article"sql plain">.sql string">"nid" sql plain">= 1;

总结

  1. select_related主要针一对一和多对一关系进行优化。
  2. select_related使用sql的JOIN语句进行优化,通过减少SQL查询次数来进行优化、提高性能
  3. 可以通过可变长参数指定需要select_related的字段名。也可以通过使用双下划线“__”连接字段名来实现指定的递归查询
  4. 没有指定的字段不会缓存,没有指定的深度不会缓存,如果要访问的话Django会再次进行SQL查询
  5. 也可以通过depth参数指定递归的深度,Django会自动缓存指定深度内所有的字段。如果要访问指定深度外的字段,Django会再次进行SQL查询
  6. 也接受无参数的调用,Django会尽可能深的递归查询所有的字段。但注意有Django递归的限制和性能的浪费。
  7. Django >= 1.7,链式调用的select_related相当于使用可变长参数。Django < 1.7,链式调用会导致前边的select_related失效,只保留最后一个。

prefetch_related()

对于多对多字段(ManyToManyField)和一对多字段,可以使用prefetch_related()来进行优化。

prefetch_related()和select_related()的设计目的很相似,都是为了减少SQL查询数量,但是实现的方式不一样。后者是通过JOIN语句,在SQL查询解决问题。但是对于多对多关系,使用sql语句解决就显得有些不太明智,因为JOIN得到的表将会很长,会导致sql语句运行时间的增加和内存占用的增加。若有n个对象,每个对象的多对多字段对应Mi条,就会生成Σ(n)Mi 行的结果表。

prefetch_related()的解决方法是,分别查询每个表,然后用Python处理他们之间的关系。

Highlighter sh-gutter">
Highlighter_462893" class="SyntaxHighlighter sql">
sql plain"># 查询所有文章关联的所有标签
sql spaces">sql plain">article_obj=models.Article.objects.prefetch_related(sql string">"tags"sql plain">).sql color1">allsql plain">()
sql spaces">sql keyword">for sql plain">i sql color1">in sql plain">article_obj:
sql spaces">sql plain">print(i.tags.sql color1">allsql plain">()) #4篇文章: hits sql keyword">database sql plain">2
Highlighter sh-gutter">
Highlighter_290992" class="SyntaxHighlighter sql">
sql keyword">SELECT sql string">"blog_article"sql plain">.sql string">"nid"sql plain">,
sql spaces">sql string">"blog_article"sql plain">.sql string">"title"sql plain">,
sql spaces">sql plain">......
sql keyword">FROM sql string">"blog_article"sql plain">;
sql keyword">SELECT
sql spaces">sql plain">(sql string">"blog_article2tag"sql plain">.sql string">"article_id"sql plain">) sql keyword">AS sql string">"_prefetch_related_val_article_id"sql plain">,
sql spaces">sql string">"blog_tag"sql plain">.sql string">"nid"sql plain">,
sql spaces">sql string">"blog_tag"sql plain">.sql string">"title"sql plain">,
sql spaces">sql string">"blog_tag"sql plain">.sql string">"blog_id"
sql spaces">sql keyword">FROM sql string">"blog_tag"
sql spaces">sql keyword">INNER sql color1">JOIN sql string">"blog_article2tag" sql keyword">ON sql plain">(sql string">"blog_tag"sql plain">.sql string">"nid" sql plain">= sql string">"blog_article2tag"sql plain">.sql string">"tag_id"sql plain">)
sql spaces">sql keyword">WHERE sql string">"blog_article2tag"sql plain">.sql string">"article_id" sql color1">IN sql plain">(1,2,3,4);

extra(None,None,paramsNone,
tablesNone,order_byNone,select_paramsNone)

查询语法难以简单的表达复杂的子句,修改机制 — 它能在生成sql从句中注入新子句

,例如,or.数据库引擎可能存在移植性问题.(因为你在显式的书写sql语句),除非万不得已,尽量避免这样做

参数可以让你在从句中添加其他字段信息,属性名到 sql 从句的映射。

queryResultmodels.Article
           .objects.extra({: "create_time "})

结果集中每个 Entry 对象都有一个额外的属性is_recent,它是一个布尔值,表示 Article对象的create_time 是否晚于2017-09-05.

练习:

# sqlite:
    article_objmodels.Article.objects
              .filter(nid)
              .extra({"standard_time":"strftime(,create_time)"})
              .QuerySet

参数之where/tables

定义显式sql子句 - 也许执行非显式连接。手动将表添加sql子句。

都接受字符串列表。参数均为“与”任何其他搜索条件。

queryResultmodels.Article
           .objects.extra(2')

创建对象时,尽可能使用bulk_create()来减少SQL查询数量。例如:

Entry.objects.bulk_create([
    Entry(headline="Python 3.0 Released"),Entry(headline="Python 3.1 Planned")
])

...更优于:

Entry.objects.create(headline="Python 3.0 Released")
Entry.objects.create(headline="Python 3.1 Planned")

注意该方法有很多注意事项,所以确保它适用于你的情况。

这也可以用在ManyToManyFields中,所以:

my_band.members.add(me,my_friend)

...更优于:

my_band.members.add(me)
my_band.members.add(my_friend)

...其中Bands和Artists具有多对多关联。

猜你在找的Django相关文章