Django:从数据库中获取对象,如果没有匹配项,则为“无”

问题:Django:从数据库中获取对象,如果没有匹配项,则为“无”

是否有任何Django函数可以让我从数据库中获取对象,如果没有匹配项,则为None?

现在我正在使用类似:

foo = Foo.objects.filter(bar=baz)
foo = len(foo) > 0 and foo.get() or None

但这还不是很清楚,到处都是混乱的。

Is there any Django function which will let me get an object form the database, or None if nothing matches?

Right now I’m using something like:

foo = Foo.objects.filter(bar=baz)
foo = len(foo) > 0 and foo.get() or None

But that’s not very clear, and it’s messy to have everywhere.


回答 0

在Django 1.6中,您可以使用first()Queryset方法。它返回查询集匹配的第一个对象,如果没有匹配的对象,则返回None。

用法:

p = Article.objects.order_by('title', 'pub_date').first()

In Django 1.6 you can use the first() Queryset method. It returns the first object matched by the queryset, or None if there is no matching object.

Usage:

p = Article.objects.order_by('title', 'pub_date').first()

回答 1

有两种方法可以做到这一点;

try:
    foo = Foo.objects.get(bar=baz)
except model.DoesNotExist:
    foo = None

或者,您可以使用包装器:

def get_or_none(model, *args, **kwargs):
    try:
        return model.objects.get(*args, **kwargs)
    except model.DoesNotExist:
        return None

这样称呼它

foo = get_or_none(Foo, baz=bar)

There are two ways to do this;

try:
    foo = Foo.objects.get(bar=baz)
except model.DoesNotExist:
    foo = None

Or you can use a wrapper:

def get_or_none(model, *args, **kwargs):
    try:
        return model.objects.get(*args, **kwargs)
    except model.DoesNotExist:
        return None

Call it like this

foo = get_or_none(Foo, baz=bar)

回答 2

要将一些示例代码添加到sorki的答案中(我将其添加为评论,但这是我的第一篇文章,并且我没有足够的声誉来发表评论),我实现了一个get_or_none自定义管理器,如下所示:

from django.db import models

class GetOrNoneManager(models.Manager):
    """Adds get_or_none method to objects
    """
    def get_or_none(self, **kwargs):
        try:
            return self.get(**kwargs)
        except self.model.DoesNotExist:
            return None

class Person(models.Model):
    name = models.CharField(max_length=255)
    objects = GetOrNoneManager()

现在我可以这样做:

bob_or_none = Person.objects.get_or_none(name='Bob')

To add some sample code to sorki’s answer (I’d add this as a comment, but this is my first post, and I don’t have enough reputation to leave comments), I implemented a get_or_none custom manager like so:

from django.db import models

class GetOrNoneManager(models.Manager):
    """Adds get_or_none method to objects
    """
    def get_or_none(self, **kwargs):
        try:
            return self.get(**kwargs)
        except self.model.DoesNotExist:
            return None

class Person(models.Model):
    name = models.CharField(max_length=255)
    objects = GetOrNoneManager()

And now I can do this:

bob_or_none = Person.objects.get_or_none(name='Bob')

回答 3

您也可以尝试使用django烦人(它还有另一个有用的功能!)

用以下命令安装:

pip install django-annoying

from annoying.functions import get_object_or_None
get_object_or_None(Foo, bar=baz)

You can also try to use django annoying (it has another useful functions!)

install it with:

pip install django-annoying

from annoying.functions import get_object_or_None
get_object_or_None(Foo, bar=baz)

回答 4

给Foo 自定义经理。这很容易-只需将代码放入自定义管理器的函数中,在模型中设置自定义管理器,然后使用即可调用Foo.objects.your_new_func(...)

如果您需要通用函数(不仅要在自定义管理器中使用它,还可以在任何模型上使用它),请编写自己的函数并将其放在python路径上并导入,而不是再麻烦了。

Give Foo its custom manager. It’s pretty easy – just put your code into function in custom manager, set custom manager in your model and call it with Foo.objects.your_new_func(...).

If you need generic function (to use it on any model not just that with custom manager) write your own and place it somewhere on your python path and import, not messy any more.


回答 5

无论是通过管理器还是通过通用函数执行操作,您都可能希望在TRY语句中捕获“ MultipleObjectsReturned”,因为如果kwarg检索了多个对象,则get()函数将引发此问题。

基于通用功能:

def get_unique_or_none(model, *args, **kwargs):
    try:
        return model.objects.get(*args, **kwargs)
    except (model.DoesNotExist, model.MultipleObjectsReturned), err:
        return None

并在经理中:

class GetUniqueOrNoneManager(models.Manager):
    """Adds get_unique_or_none method to objects
    """
    def get_unique_or_none(self, *args, **kwargs):
        try:
            return self.get(*args, **kwargs)
        except (self.model.DoesNotExist, self.model.MultipleObjectsReturned), err:
            return None

Whether doing it via a manager or generic function, you may also want to catch ‘MultipleObjectsReturned’ in the TRY statement, as the get() function will raise this if your kwargs retrieve more than one object.

Building on the generic function:

def get_unique_or_none(model, *args, **kwargs):
    try:
        return model.objects.get(*args, **kwargs)
    except (model.DoesNotExist, model.MultipleObjectsReturned), err:
        return None

and in the manager:

class GetUniqueOrNoneManager(models.Manager):
    """Adds get_unique_or_none method to objects
    """
    def get_unique_or_none(self, *args, **kwargs):
        try:
            return self.get(*args, **kwargs)
        except (self.model.DoesNotExist, self.model.MultipleObjectsReturned), err:
            return None

回答 6

这是helper函数的一种变体QuerySet,如果您希望从除模型all对象的查询集以外的查询集中获取唯一的对象(如果存在)(例如,从属于父实例):

def get_unique_or_none(model, queryset=None, *args, **kwargs):
    """
        Performs the query on the specified `queryset`
        (defaulting to the `all` queryset of the `model`'s default manager)
        and returns the unique object matching the given
        keyword arguments.  Returns `None` if no match is found.
        Throws a `model.MultipleObjectsReturned` exception
        if more than one match is found.
    """
    if queryset is None:
        queryset = model.objects.all()
    try:
        return queryset.get(*args, **kwargs)
    except model.DoesNotExist:
        return None

可以通过两种方式使用它,例如:

  1. obj = get_unique_or_none(Model, *args, **kwargs) 如前所述
  2. obj = get_unique_or_none(Model, parent.children, *args, **kwargs)

Here’s a variation on the helper function that allows you to optionally pass in a QuerySet instance, in case you want to get the unique object (if present) from a queryset other than the model’s all objects queryset (e.g. from a subset of child items belonging to a parent instance):

def get_unique_or_none(model, queryset=None, *args, **kwargs):
    """
        Performs the query on the specified `queryset`
        (defaulting to the `all` queryset of the `model`'s default manager)
        and returns the unique object matching the given
        keyword arguments.  Returns `None` if no match is found.
        Throws a `model.MultipleObjectsReturned` exception
        if more than one match is found.
    """
    if queryset is None:
        queryset = model.objects.all()
    try:
        return queryset.get(*args, **kwargs)
    except model.DoesNotExist:
        return None

This can be used in two ways, e.g.:

  1. obj = get_unique_or_none(Model, *args, **kwargs) as previosuly discussed
  2. obj = get_unique_or_none(Model, parent.children, *args, **kwargs)

回答 7

我认为在大多数情况下,您可以使用:

foo, created = Foo.objects.get_or_create(bar=baz)

仅在不关键要在Foo表中添加新条目的情况下(其他列将具有None / default值)

I think that in most cases you can just use:

foo, created = Foo.objects.get_or_create(bar=baz)

Only if it is not critical that a new entry will be added in Foo table ( other columns will have the None/default values )