如果 Django 中存在该对象,我如何获取该对象;如果该对象不存在,我如何获取 None?

发布于 2024-09-06 16:39:18 字数 213 浏览 10 评论 0原文

当我要求模型管理器获取一个对象时,如果没有匹配的对象,它会引发 DoesNotExist

go = Content.objects.get(name="baby")

我怎样才能让 go 变成 None 而不是 DoesNotExist 呢?

When I ask the model manager to get an object, it raises DoesNotExist when there is no matching object.

go = Content.objects.get(name="baby")

Instead of DoesNotExist, how can I have go be None instead?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(24

何其悲哀 2024-09-13 16:39:18

没有“内置”方法可以做到这一点。 Django 每次都会引发 DoesNotExist 异常。
在 python 中处理这个问题的惯用方法是将其包装在 try catch 中:

try:
    go = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
    go = None

我所做的是子类 models.Manager,创建一个 safe_get 就像上面的代码并将该管理器用于我的模型。这样你就可以编写:SomeModel.objects.safe_get(foo='bar')

There is no 'built in' way to do this. Django will raise the DoesNotExist exception every time.
The idiomatic way to handle this in python is to wrap it in a try catch:

try:
    go = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
    go = None

What I did do, is to subclass models.Manager, create a safe_get like the code above and use that manager for my models. That way you can write: SomeModel.objects.safe_get(foo='bar').

够钟 2024-09-13 16:39:18

从 Django 1.6 开始,您可以使用 first() 方法,如下所示:

Content.objects.filter(name="baby").first()

如果没有对象符合条件,则返回 None。如果多个对象符合条件,则返回第一个匹配项(不会引发错误)。

Since Django 1.6 you can use first() method like so:

Content.objects.filter(name="baby").first()

If no objects match the criteria, then None is returned. If more than one object match the criteria, then the first match is returned (no error is raised).

喜爱纠缠 2024-09-13 16:39:18

您可以为此创建一个通用函数。

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

使用如下所示:

go = get_or_none(Content,name="baby")

如果没有条目匹配,则 go 将为 None,否则将返回内容条目。

注意:如果 name="baby" 返回多个条目,则会引发异常 MultipleObjectsReturned

您应该在数据模型上处理它以避免这种错误,但您可能更喜欢在运行时记录它,如下所示:

def get_or_none(classmodel, **kwargs):
    try:
        return classmodel.objects.get(**kwargs)
    except classmodel.MultipleObjectsReturned as e:
        print('ERR====>', e)

    except classmodel.DoesNotExist:
        return None

You can create a generic function for this.

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

Use this like below:

go = get_or_none(Content,name="baby")

go will be None if no entry matches else will return the Content entry.

Note:It will raises exception MultipleObjectsReturned if more than one entry returned for name="baby".

You should handle it on the data model to avoid this kind of error but you may prefer to log it at run time like this:

def get_or_none(classmodel, **kwargs):
    try:
        return classmodel.objects.get(**kwargs)
    except classmodel.MultipleObjectsReturned as e:
        print('ERR====>', e)

    except classmodel.DoesNotExist:
        return None
吃→可爱长大的 2024-09-13 16:39:18

来自 django 文档

如果未找到给定参数的对象,

get() 会引发 DoesNotExist 异常。这个异常也是模型类的一个属性。 DoesNotExist 异常继承自 django.core.exceptions.ObjectDoesNotExist

您可以捕获异常并分配 None 去。

from django.core.exceptions import ObjectDoesNotExist
try:
    go  = Content.objects.get(name="baby")
except ObjectDoesNotExist:
    go = None

From django docs

get() raises a DoesNotExist exception if an object is not found for the given parameters. This exception is also an attribute of the model class. The DoesNotExist exception inherits from django.core.exceptions.ObjectDoesNotExist

You can catch the exception and assign None to go.

from django.core.exceptions import ObjectDoesNotExist
try:
    go  = Content.objects.get(name="baby")
except ObjectDoesNotExist:
    go = None
贵在坚持 2024-09-13 16:39:18

你可以这样做:

go  = Content.objects.filter(name="baby").first()

现在 go 变量可以是你想要的对象,也可以是 None

参考: https://docs.djangoproject.com/en/1.8/ref/models/querysets/#django.db.models.query.QuerySet.first

You can do it this way:

go  = Content.objects.filter(name="baby").first()

Now go variable could be either the object you want or None

Ref: https://docs.djangoproject.com/en/1.8/ref/models/querysets/#django.db.models.query.QuerySet.first

最美的太阳 2024-09-13 16:39:18

为了使事情变得更容易,这里是我编写的代码片段,基于此处精彩回复的输入:

class MyManager(models.Manager):

    def get_or_none(self, **kwargs):
        try:
            return self.get(**kwargs)
        except ObjectDoesNotExist:
            return None

然后在您的模型中:

class MyModel(models.Model):
    objects = MyManager()

就是这样。
现在你有了 MyModel.objects.get() 以及 MyModel.objetcs.get_or_none()

To make things easier, here is a snippet of the code I wrote, based on inputs from the wonderful replies here:

class MyManager(models.Manager):

    def get_or_none(self, **kwargs):
        try:
            return self.get(**kwargs)
        except ObjectDoesNotExist:
            return None

And then in your model:

class MyModel(models.Model):
    objects = MyManager()

That's it.
Now you have MyModel.objects.get() as well as MyModel.objetcs.get_or_none()

攀登最高峰 2024-09-13 16:39:18

您可以将 exists 与过滤器一起使用:

Content.objects.filter(name="baby").exists()
#returns False or True depending on if there is anything in the QS

如果您只想知道它是否存在,这只是一个替代方案

you could use exists with a filter:

Content.objects.filter(name="baby").exists()
#returns False or True depending on if there is anything in the QS

just an alternative for if you only want to know if it exists

断肠人 2024-09-13 16:39:18

这是您可能不想重新实现的烦人的函数之一:

from annoying.functions import get_object_or_None
#...
user = get_object_or_None(Content, name="baby")

It's one of those annoying functions that you might not want to re-implement:

from annoying.functions import get_object_or_None
#...
user = get_object_or_None(Content, name="baby")
我还不会笑 2024-09-13 16:39:18

也许你使用更好:

User.objects.filter(username=admin_username).exists()

Maybe is better you use:

User.objects.filter(username=admin_username).exists()
诠释孤独 2024-09-13 16:39:18

在视图中的不同点处理异常可能真的很麻烦。在 models.py 文件中定义自定义模型管理器怎么样,

class ContentManager(model.Manager):
    def get_nicely(self, **kwargs):
        try:
            return self.get(kwargs)
        except(KeyError, Content.DoesNotExist):
            return None

然后将其包含在内容模型类中

class Content(model.Model):
    ...
    objects = ContentManager()

这样就可以在视图中轻松处理它IE

post = Content.objects.get_nicely(pk = 1)
if post:
    # Do something
else:
    # This post doesn't exist

Handling exceptions at different points in your views could really be cumbersome..What about defining a custom Model Manager, in the models.py file, like

class ContentManager(model.Manager):
    def get_nicely(self, **kwargs):
        try:
            return self.get(kwargs)
        except(KeyError, Content.DoesNotExist):
            return None

and then including it in the content Model class

class Content(model.Model):
    ...
    objects = ContentManager()

In this way it can be easily dealt in the views i.e.

post = Content.objects.get_nicely(pk = 1)
if post:
    # Do something
else:
    # This post doesn't exist
落在眉间の轻吻 2024-09-13 16:39:18

我认为使用 get_object_or_404()

from django.shortcuts import get_object_or_404

def my_view(request):
    my_object = get_object_or_404(MyModel, pk=1)

这个例子相当于:

from django.http import Http404

def my_view(request):
    try:
        my_object = MyModel.objects.get(pk=1)
    except MyModel.DoesNotExist:
        raise Http404("No MyModel matches the given query.")

您可以阅读有关 get_object_or_404()

I think it isn't bad idea to use get_object_or_404()

from django.shortcuts import get_object_or_404

def my_view(request):
    my_object = get_object_or_404(MyModel, pk=1)

This example is equivalent to:

from django.http import Http404

def my_view(request):
    try:
        my_object = MyModel.objects.get(pk=1)
    except MyModel.DoesNotExist:
        raise Http404("No MyModel matches the given query.")

You can read more about get_object_or_404() in django online documentation.

橘味果▽酱 2024-09-13 16:39:18

如果您想要一个简单的单行解决方案,不涉及异常处理、条件语句或 Django 1.6+ 的要求,请改为执行以下操作:

x = next(iter(SomeModel.objects.filter(foo='bar')), None)

If you want a simple one-line solution that doesn't involve exception handling, conditional statements or a requirement of Django 1.6+, do this instead:

x = next(iter(SomeModel.objects.filter(foo='bar')), None)
呆萌少年 2024-09-13 16:39:18

从 django 1.7 开始,您可以这样做:

class MyQuerySet(models.QuerySet):

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


class MyBaseModel(models.Model):

    objects = MyQuerySet.as_manager()


class MyModel(MyBaseModel):
    ...

class AnotherMyModel(MyBaseModel):
    ...

“MyQuerySet.as_manager()”的优点是以下两者都可以工作:

MyModel.objects.filter(...).get_or_none()
MyModel.objects.get_or_none()

From django 1.7 onwards you can do like:

class MyQuerySet(models.QuerySet):

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


class MyBaseModel(models.Model):

    objects = MyQuerySet.as_manager()


class MyModel(MyBaseModel):
    ...

class AnotherMyModel(MyBaseModel):
    ...

The advantage of "MyQuerySet.as_manager()" is that both of the following will work:

MyModel.objects.filter(...).get_or_none()
MyModel.objects.get_or_none()
他是夢罘是命 2024-09-13 16:39:18

我使用 Django 2.2.16。这就是我解决这个问题的方法:

from typing import Any

from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.db.models.base import ModelBase
from django.db.models.manager import Manager


class SManager(Manager):
    def get_if_exist(self, *args: Any, **kwargs: Any):
        try:
            return self.get(*args, **kwargs)
        except ObjectDoesNotExist:
            return None


class SModelBase(ModelBase):
    def _prepare(cls):
        manager = SManager()
        manager.auto_created = True
        cls.add_to_class("objects", manager)

        super()._prepare()

    class Meta:
        abstract = True


class SModel(models.Model, metaclass=SModelBase):
    managers = False

    class Meta:
        abstract = True

之后,在每个模型中,您只需要导入:

from custom.models import SModel


class SUser(SModel):
    pass

views 中,您可以像这样调用:

SUser.objects.get_if_exist(id=1)

I use Django 2.2.16. And this is how I solve this problem:

from typing import Any

from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.db.models.base import ModelBase
from django.db.models.manager import Manager


class SManager(Manager):
    def get_if_exist(self, *args: Any, **kwargs: Any):
        try:
            return self.get(*args, **kwargs)
        except ObjectDoesNotExist:
            return None


class SModelBase(ModelBase):
    def _prepare(cls):
        manager = SManager()
        manager.auto_created = True
        cls.add_to_class("objects", manager)

        super()._prepare()

    class Meta:
        abstract = True


class SModel(models.Model, metaclass=SModelBase):
    managers = False

    class Meta:
        abstract = True

And after that, in every models, you just need to import in:

from custom.models import SModel


class SUser(SModel):
    pass

And in views, you can call like this:

SUser.objects.get_if_exist(id=1)
南笙 2024-09-13 16:39:18

这是 Django 的 get_object_or_404 的模仿者,只不过该方法返回 None 。当我们必须使用 only() 查询来仅检索某些字段时,这非常有用。此方法可以接受模型或查询集。

from django.shortcuts import _get_queryset


def get_object_or_none(klass, *args, **kwargs):
    """
    Use get() to return an object, or return None if object
    does not exist.
    klass may be a Model, Manager, or QuerySet object. All other passed
    arguments and keyword arguments are used in the get() query.
    Like with QuerySet.get(), MultipleObjectsReturned is raised if more than
    one object is found.
    """
    queryset = _get_queryset(klass)
    if not hasattr(queryset, 'get'):
        klass__name = klass.__name__ if isinstance(klass, type) else klass.__class__.__name__
        raise ValueError(
            "First argument to get_object_or_none() must be a Model, Manager, "
            "or QuerySet, not '%s'." % klass__name
        )
    try:
        return queryset.get(*args, **kwargs)
    except queryset.model.DoesNotExist:
        return None

This is a copycat from Django's get_object_or_404 except that the method returns None. This is extremely useful when we have to use only() query to retreive certain fields only. This method can accept a model or a queryset.

from django.shortcuts import _get_queryset


def get_object_or_none(klass, *args, **kwargs):
    """
    Use get() to return an object, or return None if object
    does not exist.
    klass may be a Model, Manager, or QuerySet object. All other passed
    arguments and keyword arguments are used in the get() query.
    Like with QuerySet.get(), MultipleObjectsReturned is raised if more than
    one object is found.
    """
    queryset = _get_queryset(klass)
    if not hasattr(queryset, 'get'):
        klass__name = klass.__name__ if isinstance(klass, type) else klass.__class__.__name__
        raise ValueError(
            "First argument to get_object_or_none() must be a Model, Manager, "
            "or QuerySet, not '%s'." % klass__name
        )
    try:
        return queryset.get(*args, **kwargs)
    except queryset.model.DoesNotExist:
        return None
风和你 2024-09-13 16:39:18

这是辅助函数的变体,如果您想从模型的 all< 之外的查询集中获取唯一对象(如果存在),它允许您选择传入 QuerySet 实例。 /code> 对象查询集(例如,来自属于父实例的子项子集):

def get_unique_or_none(model, queryset=None, **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(**kwargs)
    except model.DoesNotExist:
        return None

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

  1. obj = get_unique_or_none(Model, **kwargs) 如前所述
  2. obj = get_unique_or_none(模型,parent.children,**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, **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(**kwargs)
    except model.DoesNotExist:
        return None

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

  1. obj = get_unique_or_none(Model, **kwargs) as previosuly discussed
  2. obj = get_unique_or_none(Model, parent.children, **kwargs)
栀子花开つ 2024-09-13 16:39:18

无例外:

if SomeModel.objects.filter(foo='bar').exists():
    x = SomeModel.objects.get(foo='bar')
else:
    x = None

使用异常:

try:
   x = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
   x = None

关于何时应该在 python 中使用异常存在一些争论。一方面,“请求原谅比请求许可更容易”。虽然我同意这一点,但我相信例外应该保留,好吧,例外,并且“理想情况”应该运行而不会遇到例外。

Without exception:

if SomeModel.objects.filter(foo='bar').exists():
    x = SomeModel.objects.get(foo='bar')
else:
    x = None

Using an exception:

try:
   x = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
   x = None

There is a bit of an argument about when one should use an exception in python. On the one hand, "it is easier to ask for forgiveness than for permission". While I agree with this, I believe that an exception should remain, well, the exception, and the "ideal case" should run without hitting one.

梦途 2024-09-13 16:39:18

我们可以使用 Django 内置异常,它附加到名为 .DoesNotExist 的模型上。因此,我们不必导入 ObjectDoesNotExist 异常。

相反,

from django.core.exceptions import ObjectDoesNotExist

try:
    content = Content.objects.get(name="baby")
except ObjectDoesNotExist:
    content = None

我们可以这样做:

try:
    content = Content.objects.get(name="baby")
except Content.DoesNotExist:
    content = None

We can use Django builtin exception which attached to the models named as .DoesNotExist. So, we don't have to import ObjectDoesNotExist exception.

Instead doing:

from django.core.exceptions import ObjectDoesNotExist

try:
    content = Content.objects.get(name="baby")
except ObjectDoesNotExist:
    content = None

We can do this:

try:
    content = Content.objects.get(name="baby")
except Content.DoesNotExist:
    content = None
最丧也最甜 2024-09-13 16:39:18

我也面临着同样的问题。当您想从模型中获取元素时,每次都很难编写和读取 try- except ,就像 @Arthur Debert 的答案一样。所以,我的解决方案是创建一个由模型继承的 Getter 类:

class Getter:
    @classmethod
    def try_to_get(cls, *args, **kwargs):
        try:
            return cls.objects.get(**kwargs)
        except Exception as e:
            return None

class MyActualModel(models.Model, Getter):
    pk_id = models.AutoField(primary_key=True)
    ...

通过这种方式,我可以获得 MyActualModelNone 的实际元素代码>:

MyActualModel.try_to_get(pk_id=1)

I was facing with the same problem too. It's hard to write and read try-except for each time when you want to get an element from your model as in @Arthur Debert's answer. So, my solution is to create an Getter class which is inherited by the models:

class Getter:
    @classmethod
    def try_to_get(cls, *args, **kwargs):
        try:
            return cls.objects.get(**kwargs)
        except Exception as e:
            return None

class MyActualModel(models.Model, Getter):
    pk_id = models.AutoField(primary_key=True)
    ...

In this way, I can get the actual element of MyActualModel or None:

MyActualModel.try_to_get(pk_id=1)
星光不落少年眉 2024-09-13 16:39:18

简单的方法:

if query.exists():
做某事...

或者

如果 query.exists() 为 False:
做某事...

Simple way:

if query.exists():
do something....

or

if query.exists() is False:
do something...

情归归情 2024-09-13 16:39:18

我更喜欢这种不使用异常的方法。它还可以处理多个对象以及不处理任何对象。

go_list = Content.objects.filter(name="baby")
if (len(go_list) == 1):
    go = go_list[0]
else:
    go = None # optionally do other things if there are multiple objects / no objects.

I prefer this method without using exceptions. It also handles multiple objects as well as no objects.

go_list = Content.objects.filter(name="baby")
if (len(go_list) == 1):
    go = go_list[0]
else:
    go = None # optionally do other things if there are multiple objects / no objects.
变身佩奇 2024-09-13 16:39:18

如果有这样的事情怎么办?

go = (Content.objects.filter(name="value") or [None])[0]

What if something like this?

go = (Content.objects.filter(name="value") or [None])[0]
痴情 2024-09-13 16:39:18

正如其他答案中提到的,您可以使用

filter(**kwargs).first()

此方法的问题是,如果查询返回多个对象。这可能并不总是令人满意的。假设您有以下数据库表

IDfirst_namelast_name
1KeenenWayans
2MarlonWayans
3ShawnWayans

Person.objects.filter(last_name="Wayans").first()

将始终返回 Keenen Wayans 。用户永远不会知道还有其他“Wayans”

如果你不喜欢这个,下面是我对 Django 快捷方法的重新实现 get_object_or_404。如果没有找到对象,则返回 None,但如果查询返回多个对象,则抛出 MultipleObjectsReturned 异常。我宁愿处理 MultipleObjectsReturned 异常,而不是向用户返回虚假值。

在名为 shortcuts.py 的单独文件中,创建一个名为 get_object_or_none 的方法。

def get_object_or_none(klass, *args, **kwargs):
    """
    Use get() to return an object, or returns None if the object
    does not exist instead of throwing an exception.
    klass may be a Model, Manager, or QuerySet object. All other passed
    arguments and keyword arguments are used in the get() query.
    Like with QuerySet.get(), MultipleObjectsReturned is raised if more than
    one object is found.
    """
    queryset =  klass._default_manager.all() if hasattr(klass, "_default_manager") else klass
    if not hasattr(queryset, "get"):
        klass__name = (
            klass.__name__ if isinstance(klass, type) else klass.__class__.__name__
        )
        raise ValueError(
            "First argument to get_object_or_none() must be a Model, Manager, "
            "or QuerySet, not '%s'." % klass__name
        )
    try:
        return queryset.get(*args, **kwargs)
    except queryset.model.DoesNotExist:
        return None

然后在views.py中

from myapp.shortcuts import get_object_or_none

person = get_object_or_none(Person, first_name='Shawn', last_name='Wayans')
#person is 'Shawn Wayans'

person = get_object_or_none(Person, last_name='Hendrix')
#person is None as database has no person with last name 'Hendrix'

person = get_object_or_none(Person, last_name='Wayans')
#throws 'MultipleObjectsReturned' error since multiple persons returned.

As it has been mentioned in other answers, you can use

filter(**kwargs).first()

The issue with this method is it never throws a MultipleObjectsReturned error if the query returns multiple objects. This may not always be desirable. Assume you have the following database table

idfirst_namelast_name
1KeenenWayans
2MarlonWayans
3ShawnWayans

Person.objects.filter(last_name="Wayans").first()

will always return Keenen Wayans. The user will never know there are other 'Wayans'

If you don't like this, below is my reimplementation of Django's shortcut method get_object_or_404. If no object is found, it returns None, but if the query returns multiple objects, it throws a MultipleObjectsReturned exception. I would rather handle MultipleObjectsReturned exception, instead of returning a bogus value to the user.

In a separate file called shortcuts.py, create a method called get_object_or_none.

def get_object_or_none(klass, *args, **kwargs):
    """
    Use get() to return an object, or returns None if the object
    does not exist instead of throwing an exception.
    klass may be a Model, Manager, or QuerySet object. All other passed
    arguments and keyword arguments are used in the get() query.
    Like with QuerySet.get(), MultipleObjectsReturned is raised if more than
    one object is found.
    """
    queryset =  klass._default_manager.all() if hasattr(klass, "_default_manager") else klass
    if not hasattr(queryset, "get"):
        klass__name = (
            klass.__name__ if isinstance(klass, type) else klass.__class__.__name__
        )
        raise ValueError(
            "First argument to get_object_or_none() must be a Model, Manager, "
            "or QuerySet, not '%s'." % klass__name
        )
    try:
        return queryset.get(*args, **kwargs)
    except queryset.model.DoesNotExist:
        return None

Then in views.py

from myapp.shortcuts import get_object_or_none

person = get_object_or_none(Person, first_name='Shawn', last_name='Wayans')
#person is 'Shawn Wayans'

person = get_object_or_none(Person, last_name='Hendrix')
#person is None as database has no person with last name 'Hendrix'

person = get_object_or_none(Person, last_name='Wayans')
#throws 'MultipleObjectsReturned' error since multiple persons returned.
灯下孤影 2024-09-13 16:39:18

切片怎么样?它将解析到限制 1。

go = Content.objects.filter(name="baby")[0]

How about a slice? It will parse to a limit 1.

go = Content.objects.filter(name="baby")[0]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文