Djangofilter与获取单个对象?
我正在和一些同事讨论这个问题。 有一个首选的方法来检索Django中的对象,当你只有一个?
两个明显的方法是:
try: obj = MyModel.objects.get(id=1) except MyModel.DoesNotExist: # we have no object! do something pass
和
objs = MyModel.objects.filter(id=1) if len(objs) == 1: obj = objs[0] else: # we have no object! do something pass
第一种方法似乎在行为上更正确,但在控制stream中使用exception,这可能会引入一些开销。 第二个是更多的迂回,但永远不会例外。
任何想法哪个更好? 哪个更有效率?
get()
是专门为这种情况提供的。 用它。
选项2几乎正是get()
方法在Django中实际实现的方式,因此应该没有“性能”差异(并且考虑到这一点的事实表明您违反了编程的基本规则之一,即在代码被写入和分析之前尝试优化代码 – 直到你有了代码并且可以运行它,你不知道它将如何执行,然后尝试优化是一个痛苦的道路。
您可以安装一个名为django-annoying的模块,然后执行此操作:
from annoying.functions import get_object_or_None obj = get_object_or_None(MyModel, id=1) if not obj: #omg the object was not found do some error stuff
1是正确的。 在Python中,exception与返回相同。 对于一个简单的certificate,你可以看看这个 。
2这是Django在后端做的事情。 get
调用filter
,如果找不到任何项目或find多于一个对象,则引发exception。
我不能说任何Django的经验,但选项#1清楚地告诉系统,您要求1个对象,而第二个选项不是。 这意味着选项#1可以更容易地利用caching或数据库索引,特别是在您要过滤的属性不保证是唯一的情况下。
另外(再次推测)第二个选项可能必须创build某种结果集合或迭代器对象,因为filter()调用通常可以返回多行。 你可以绕过get()。
最后,第一个选项既短又省略额外的临时variables – 只是一个小的差异,但每一个小的帮助。
一些关于exception的更多信息。 如果他们不提高,他们几乎没有成本。 因此,如果你知道你可能会得到一个结果,使用这个exception,因为使用一个条件expression式,你无论如何都要支付每一次检查的代价。 另一方面,当它们被提升时,它们的成本比条件expression式要多一些,所以如果你期望没有某个频率的结果(例如30%的时间,如果内存服务),条件检查结果要便宜一点。
但是这是Django的ORM,可能是数据库的往返行为,或者甚至caching的结果,可能会主宰性能特性,所以在这种情况下,由于您期望get()
一个结果,请使用get()
。
为什么所有这些工作? 用内置的快捷键replace4行。 (这是自己的尝试/除了。)
from django.shortcuts import get_object_or_404 obj = get_object_or_404(MyModel, id=1)
我晚了一点,但是在Django 1.6中,querysets上有第first()
方法。
https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.first
返回查询集匹配的第一个对象,如果没有匹配对象,则返回None。 如果QuerySet没有定义的顺序,那么查询集由主键自动sorting。
例:
p = Article.objects.order_by('title', 'pub_date').first() Note that first() is a convenience method, the following code sample is equivalent to the above example: try: p = Article.objects.order_by('title', 'pub_date')[0] except IndexError: p = None
我已经玩了一下这个问题,并发现选项2执行两个SQL查询,这对于这样一个简单的任务是过度的。 看我的注释:
objs = MyModel.objects.filter(id=1) # This does not execute any SQL if len(objs) == 1: # This executes SELECT COUNT(*) FROM XXX WHERE filter obj = objs[0] # This executes SELECT x, y, z, .. FROM XXX WHERE filter else: # we have no object! do something pass
执行单个查询的等效版本是:
items = [item for item in MyModel.objects.filter(id=1)] # executes SELECT x, y, z FROM XXX WHERE filter count = len(items) # Does not execute any query, items is a standard list. if count == 0: return None return items[0]
通过切换到这种方法,我可以大大减less我的应用程序执行的查询次数。
有趣的问题,但对我来说,选项#2的过早优化。 我不确定哪一个更高性能,但是选项#1当然会让我感觉更加pythonic。
我build议一个不同的devise。
如果你想对可能的结果执行一个函数,你可以从QuerySet派生,像这样: http : //djangosnippets.org/snippets/734/
结果是非常棒的,你可以例如:
MyModel.objects.filter(id=1).yourFunction()
在这里,filter返回一个空的查询集或一个查询集与一个单一的项目。 您的自定义查询集函数也是可链接和可重用的。 如果你想为你的所有条目执行它: MyModel.objects.all().yourFunction()
。
它们也非常适合在pipe理界面中用作操作:
def yourAction(self, request, queryset): queryset.yourFunction()
选项1更优雅,但一定要使用try..except。
根据我自己的经验,我可以告诉你,有时你确定在数据库中不可能有多个匹配的对象,但是会有两个…(当然除了通过它的主键获取对象之外)。
- ValueError at / image / Tensor张量(“activation_5 / Softmax:0”,shape =(?,4),dtype = float32)不是该图的元素
- Django中的一个应用程序的外键
- Django与模型视图控制器
- 使用Django的HTTPError 403(Forbidden)和使用OAuth2连接到Google的python-social-auth
- Djangodate时间问题(默认= datetime.now())
- Django加载块的CSS
- Python / Django:在runserver下login到控制台,在Apache下login到文件
- Django Rest框架中的用户authentication+ Angular.js Web应用程序
- 我如何使用pip和需求文件升级特定的软件包?