如何提高Django查询效率(django优化执行速度)

请教下,如何提高Django查询效率(django优化执行速度)
最新回答
夏了夏天

2025-03-31 00:41:39

导读:本篇文章首席CTO笔记来给大家介绍有关如何提高Django查询效率的相关内容,希望对大家有所帮助,一起来看看吧。

Django中复杂的查询

在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?

Django提供F()来做这样的比较。F()的实例可以在查询中引用字段,来比较同一个model实例中两个不同字段的值。

Django支持F()对象之间以及F()对象和常数之间的加减乘除和取模的操作。

filter()等方法中的关键字参数查询都是一起进行“AND”的。如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象。

fromdjango.db.modelsimportQ

Q(title__startswith='Py')

Q对象可以使用和|操作符组合起来。当一个操作符在两个Q对象上使用时,它产生一个新的Q对象。

查询名字叫水浒传或者价格大于100的书

你可以组合和|操作符以及使用括号进行分组来编写任意复杂的Q对象。同时,Q对象可以使用~操作符取反,这允许组合正常的查询和取反(NOT)查询:

查询函数可以混合使用Q对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q对象)都将"AND”在一起。但是,如果出现Q对象,它必须位于所有关键字参数的前面。例如:

查询名字叫水浒传与价格大于100的书

请教Python里的queryset是什么,以及Objects类的用法?

这是哪儿的django面试题目或者笔试题目吧,请查看django开发手册。

1.queryset是查询集,就是传到服务器上的url里面的查询内容。Django会对查询返回的结果集QuerySet进行缓存,这是为了提高查询效率。也就是说,在你创建一个QuerySet对象的时候,Django并不会立即向数据库发出查询命令,只有在你需要用到这个QuerySet的时候才会这样做。

2.Objects是django实现的mvc中的m,Django中的模型类都有一个objects对象,它是一个Django中定义的QuerySet类型的对象,它包含了模型对象的实例。

3.不能,因为get可能会有异常,可以用filter函数,如下

Entry.objects.filter(blog__id__exact=1)#显示的使用__exact

Entry.objects.filter(blog__id=1)#隐含的使用__exactEntry.objects.filter(blog__pk=1)#__pk相当于__id__exact

Django表关联对象及多表查询

首先建立Student,Dpartment,Course,Stu_info表

一对多表关系数据的添加:

1.第一种方式就是跟之前的一样,用传参的方法添加,需要注意的是外键的值必须是关联表中已经存在的值.

2.第二种方式是用的属性赋值的方式,因为我们在模型类有定义了一个department的属性,而这个属性的对象的类型必须是department表的类实例对象

表关联对象的访问:

Student的模型类中我们有定义department的属性,所以当我们去访问的时候,可以直接通过student.department的形式去找到某个学生的所属学院是哪个.

那么如果我们也希望在在访问某个学院的实现对象的学生的时候改怎么访问呢???

表关联对象的访问:

可以在定义时设置related_name参数来覆盖foo_set的名称.

clear()从关联的对象集中删除所有的对象

多表查询----跨关联关系的查询:

Django提供一种强大而又直观的方式来“处理”查询中的关联关系,它在后台自动帮你处理JOIN。若要跨越关联关系,只需使用关联的模型字段的名称,并使用双下划线分隔,直至你想要的字段:

它还可以反向工作。若要引用一个“反向”的关系,只需要使用该模型的小写的名称。

Django中使用model怎么查询不等于某个值的情况

Model是django项目的基础,如果一开始没有好好设计好,那么在接下来的开发过程中就会遇到更多的问题.然而,大多数的开发人员都容易在缺少思考的情况下随意的增加或修改model.这样做的后果就是,在接下来的开发过程中,我们不得不做出更多努力来修正这些错误.

因此,在修改model时,一定尽可能的经过充分的考虑再行动!以下列出的是我们经常用到的一些工具和技巧:

South,用于数据迁移,我们会在每个django项目中都用到.但到django1.7时,将会有django.db.migrations代替.

django-model-utils,用于处理常见的模式,例如TimeStampedModel.

django-extensions,主要用到shell_plus命令,该命令会在shell中自动载入所有的app的model

1.基本原则

第一,将model分布于不同的app中.如果你的django项目中,有一个app拥有超过20个model,那么,你就应当考虑分拆该app了.我们推荐每个app拥有不超过5个model.

第二,尽量使用ORM.我们需要的大多数数据库索引都能通过Object-Relational-Model实现,且ORM带给我们许多快捷方式,例如生成SQL语句,读取/更新数据库时的安全验证.因此,如果能使用简单的ORM语句完成的,应当尽量使用ORM.只有当纯SQL语句极大地简化了ORM语句时,才使用纯SQL语句.并且,在写纯SQL语句是,应当优先考虑使用raw(),再是extra().

第三,必要时添加index.添加db_index=True到model中非常简单,但难的是理解何时应该添加.在建立model时,我们事先不会添加index,只有当以下情况时,才会考虑添加index:

在所有的数据库查询中使用率在10%-25%时

或当有真实的数据,或能正确估计出使用index后的效果确实满意时

第四,注意model的继承.model的继承在django中需要十分小心,django提供了三种继承方式,1.abstractbaseclass继承(不要和Pyhton标准库的abc模块搞混),2.多表(multi-table)继承,3.proxymodel继承.下表罗列了这三种继承的优劣:

django的创造者和其他许多开发人员都认为,多表继承的方法不是一个良好的方法.因此我们强烈建议大家不要使用该方法.下面列举了一些常见的如何选择model继承的情形:

如果只有少数model拥有重复的field时,大可不必使用model继承,只需要在每个model中添加这些相同的field即可.

如果有足够的model拥有重复的field时,大多是情况下,可以使用abstractbaseclass继承,将相同的field提取到abstractbaseclass中.

Proxymodel继承很少被用到,和其他两种继承也有着许多不一样之处.

请不要使用多表(multi-table)继承,因为它既消耗资源又复杂,如果可以,尽量使用OneToOneFields和ForeignKeys代替.

django项目中,创建时间和修改时间这两个field是最用到的,下面给出一个abstractbaseclass继承的例子:

2.DjangoModel的设计

如何设计出好的djangomodel可能是最难也是最复杂的一个话题了,在此,我们看看一些基本的技巧吧:

a.规范化

我们首先建议了解数据库规范化(databasenormalization).如果你还不清楚这是什么,那么,我们强烈建议你先阅读一下相关的书籍,或搜索"关系型数据库设计"或"数据库规范化".在创建djangomodel之前,应当首先保证设计的数据库是规范化的.

b.cache

正确的使用cache能帮助我们提高数据库的性能.详细的信息,我们会在今后的文章中作进一步介绍.

c.何时使用null和blank

当定义modelfield时,我们可以设置null=True和blank=True(默认都是False),知道何时设置null和blank对于开发人员也是十分重要的,在下面的表格中,我们一一列举了如何使用这两个选项:

d.什么时候使用BinaryField

在django1.6中,新增了BinaryField,用于储存二进制数据(binarydata或bytes).对于BinaryField,我们无法使用ORM的filters,excludes或其他SQL操作.但在少数情况下,我们会用到BinaryField,例如MessagePack格式的内容,传感器接受的原始数据和压缩数据等.但需要注意的是,BinaryData一般都十分庞大,因此可能会拖慢数据库的速度.如果发生这一现象,我们可以将binarydata储存在文件中,然后使用FileField储存该文件的路径信息.

还有,不要从BinaryField中直接读取文件并呈献给用户.因为,1.从数据库读写总是比从文件系统读写慢;2.数据库备份会变得十分庞大,花费更多的时间;3.获得文件的过程,增加了从django到数据库的这一环节.

3.不要替换默认的ModelManager

从ORM获取model,实际上是通过django中的Modelmanager完成的,django为每一个model提供了默认的modelmanager,我们不建议将其替换掉,因为:

当使用model继承时,model会继承abstractbaseclassmodel的modelmanager,而不会继承非abstractbaseclass的manager.

model的第一个modelmanager通常作为默认的manager,当被替换时,可能会发生不可预测的问题.

4.数据库事务(Transaction)

在django1.6中,ORM默认会autocommit每一个数据库查询,也就是说,每次使用m.create()或m.update()时,在数据库中马上就会做出相应的修改.这样做的好处就是简化了初学者对ORM的理解.但坏处就是,当一个view中包含两个数据库修改,可能一个成功,但另一个失败,这就可能导致数据库不完整,给我们带来很大的危险.

解决这一问题的方法就是使用数据库transaction,即将一系列数据库操作包含在一个transaction中,当其中有一个失败时,其他操作也会自动回退.Django1.6为我们带来了一套崭新的既简单又强大的transaction机制,使我们方便的使用数据库transaction.

a.将整个httprequest包裹在transaction中

django给我们提供了一个简单地方法,将一个httprequest中的所有数据库操作包裹在transaction中:

只需要在数据库设置中加入'ATOMIC_REQUESTS':True选项,就能将整个httprequest包裹在transaction中.这样做的好处显而易见是是安全,但坏处则是性能可能会下降,因此随着流量的增大,我们必须采取更针对性的transaction.其次,需要注意的是,回退的只是数据库的状态,而不包括其他费数据库项,例如发送email等.所以当涉及这些非数据库项时,我们应当使用transaction.con_atomic_request()修饰(decorate)这些view:

b.更明确地transaction控制

更明确地transaction控制意味着提高真题webapp的性能,但也意味着更多的开发时间.大多数网站下,由于有限的流量,使用ATOMIC_REQUESTS已经足够.在使用手动transaction控制时,应当注意:

不做数据修改的操作,应当排除在transaction之外

做数据修改的操作,则应在transaction内

特殊情况下,可以违反以上两条

需要注意的是,当view返回的是django.http.StreamingHttpResponse时,应当设置ATOMIC_REQUESTS为false,或使用transaction.non_atomic_requests将该view修饰.因为对于view本身,是可以使用transaction的,但对于之后生成的responsestream触发的额外SQL查询,会自动变为django默认的autocommit模式.

django和gin的开发效率

django开发效率毋庸置疑,在效率上可谓非常之快。

然而框架的易用性也增加了框架内部实现的复杂性,必然导致性能的下降。

gin的一次只能获取一个表单数据,开发效率较慢。

如何优化DjangoRESTFramework的性能

解决Django「懒惰」的基本方法

现在我们解决这个问题的方法就是「预加载」。从本质上讲,就是你提前警告DjangoORM你要一遍又一遍的告诉它同样无聊的指令。在上面的例子中,在DRF开始获取前很简单地加上这句话就搞定了:

queryset=queryset.prefetch_related('orders')

当DRF调用上述相同序列化customers时,出现的是这种情况:

获取所有customers(执行两个往返数据库操作,第一个是获取customers,第二个获取相关customers的所有相关的orders。)

对于第一个返回的customers,获取其order(不需要访问数据库,我们已经在上一步中获取了所需要的数据)

对于第二个返回的customers,获取其order(不需要访问数据库)

对于第三个返回的customers,获取其order(不需要访问数据库)

对于第四个返回的customers,获取其order(不需要访问数据库)

对于第五个返回的customers,获取其order(不需要访问数据库)

对于第六个返回的customers,获取其order(不需要访问数据库)

你又意识到,你可以有了很多customers,已经不需要再继续等待去数据库。

其实DjangoORM的「预备」是在第1步进行请求,它在本地高速缓存的数据能够提供步骤2+所要求的数据。与之前往返数据库相比从本地缓存数据中读取数据基本上是瞬时的,所以我们在有很多customers时就获得了巨大的性能加速。

解决DjangoRESTFramework性能问题的标准化模式

我们已经确定了一个优化DjangoRESTFramework性能问题的通用模式,那就是每当序列化查询嵌套字段时,我们就添加一个新的@staticmethod名叫setup_eager_loading,像这样:

classCustomerSerializer(serializers.ModelSerializer):

orders=OrderSerializer(many=True,read_only=True)

defsetup_eager_loading(cls,queryset):

"""Performnecessaryeagerloadingofdata."""

queryset=queryset.prefetch_related('orders')

returnqueryset

这样,不管哪里要用到这个序列化,都只需在调用序列化前简单调用setup_eager_loading,就像这样:

customer_qs=Customers.objects.all()

customer_qs=CustomerSerializer.setup_eager_loading(customer_qs)#SetupeagerloadingtoavoidN+1selects

post_data=CustomerSerializer(customer_qs,many=True).data

或者,如果你有一个APIView或ViewSet,你可以在get_queryset方法里调用setup_eager_loading:

defget_queryset(self):

queryset=Customers.objects.all()

#SetupeagerloadingtoavoidN+1selects

queryset=self.get_serializer_class().setup_eager_loading(queryset)

returnqueryset

结语:以上就是首席CTO笔记为大家整理的关于如何提高Django查询效率的相关内容解答汇总了,希望对您有所帮助!如果解决了您的问题欢迎分享给更多关注此问题的朋友喔~