django中的orm查询,针对复杂的查询,除了使用a.objects.filter(foreign_name__field)进行查询外。还可以使用select_related 和prefetch_related,进行性能的优化
select_related:
将会根据外键关系(注意: 仅限单对单和单对多关系),在执行查询语句的时候通过创建一条包含sql inner join操作的select语句来一次性获得主对象及相关对象的信息
1、模型类创建
users/modes.py
from django.db import models # create your models here. class userinfo(models.model): username = models.charfield(verbose_name='用户名', max_length=225) def __str__(self): return self.username class meta: db_table = 'userinfo' class tag(models.model): name = models.charfield(verbose_name='标签名称', max_length=225) def __str__(self): return self.name class meta: db_table = 'tag' class article(models.model): title = models.charfield(verbose_name='标题', max_length=225) content = models.charfield(verbose_name='内容', max_length=225) # 外键 username = models.foreignkey(verbose_name='用户', to='userinfo', on_delete=models.do_nothing) tag = models.manytomanyfield(verbose_name='标签', to='tag') def __str__(self): return self.title class meta: db_table = 'article'
2、添加admin站点,插入测试数据
user/admin.py
from django.contrib import admin from .models import article, userinfo, tag # register your models here. admin.site.register(userinfo) admin.site.register(article) admin.site.register(tag)
3、select_related示例查询
3.1 普通查询
<h1>article列表</h1> <body> <ul> {% for article in article_queryset %} <li>{{ article.title }} <==> {{ article.title }}</li> {% endfor %} </ul> </body>
def article_list0(request): if request.method == 'get': article_queryset = article.objects.all() return render(request, 'user/t1.html', {'article_queryset': article_queryset})
以上可知:只有一次sql查询记录
3.2 外键查询
<h1>article列表</h1> <body> <ul> {% for article in article_queryset %} <li>{{ article.title }} <==> {{ article.username }}</li> {% endfor %} </ul> </body>
def article_list(request): if request.method == 'get': article_queryset = article.objects.all() return render(request, 'user/t2.html', {'article_queryset': article_queryset})
以上可知:有13次sql查询
1次查询article表,12次查询article的外键
3.3 性能优化
<h1>article列表</h1> <body> <ul> {% for article in article_queryset %} <li>{{ article.title }} <==> {{ article.username }}</li> {% endfor %} </ul> </body>
def article_list2(request): if request.method == 'get': article_queryset = article.objects.all().select_related('username') # article_queryset = article.objects.all().prefetch_related() return render(request, 'user/t2.html', {'article_queryset': article_queryset})
以上可知:使用select_related进行优化,只有一次sql查询
3.4 其他示例
# 获取id=1的文章对象同时,获取其相关username信息 article.objects.select_related('username').get(id=1) # 获取id=1的文章对象同时,获取其相关作者名字信息 article.objects.select_related('username__username').get(id=1) # 获取id=1的文章对象同时,获取其相关tag和相关作者名字信息。下面方法等同。 # 方式一: article.objects.select_related('tag', 'username__username').get(id=1) # 方式二: article.objects.select_related('tag').select_related('username__username').get(id=1) # 使用select_related()可返回所有相关主键信息。all()非必需。 article.objects.all().select_related() # 获取article信息同时获取username信息。filter方法和selected_related方法顺序不重要。 # 方式一: article.objects.filter(tag__gt=3).select_related('username') # 方式二: article.objects.select_related('username').filter(tag__gt=3)
4、prefetch_related示例查询
对于多对多字段,你不能使用select_related方法,这样做是为了避免对多对多字段执行join操作从而造成最后的表非常大。
prefetch_related()和select_related()的设计目的很相似,都是为了减少sql查询的数量,但是实现的方式不一样。后者是通过join语句,在sql查询内解决问题。但是对于多对多关系,使用sql语句解决就显得有些不太明智,因为join得到的表将会很长,会导致sql语句运行时间的增加和内存占用的增加。若有n个对象,每个对象的多对多字段对应mi条,就会生成σ(n)mi 行的结果表。
4.1 普通查询
<h1>{{ tag.name }}</h1> <body> <ul> {% for article in article_list %} <li>{{ article.title }}</li> {% endfor %} </ul> </body>
def tag_list(request, tid): if request.method == 'get': tag = tag.objects.get(pk=tid) article_list = tag.article_set.all() return render(request, 'user/t4.html', {'tag': tag, 'article_list': article_list})
4.2 性能优化
<h1>{{ tag.name }}</h1> <body> <ul> {% for article in tag.article_set.all %} <li>{{ article.title }}</li> {% endfor %} </ul> </body>
def tag_list1(request, tid): if request.method == 'get': tag = tag.objects.prefetch_related('article_set').get(pk=tid) return render(request, 'user/t5.html', {'tag': tag})
到此这篇关于django之select_related、prefetch_related的文章就介绍到这了,更多相关django select_related、prefetch_related内容请搜索3w代码以前的文章或继续浏览下面的相关文章希望大家以后多多支持3w代码!
发表评论