简体   繁体   English

如果 object 存在,我如何获取它?如果 Django 中不存在,我如何获取 None?

[英]How do I get the object if it exists, or None if it does not exist in Django?

When I ask the model manager to get an object, it raises DoesNotExist when there is no matching object.当我要求 model 经理获取DoesNotExist时,如果没有匹配的 object,它会引发 DoesNotExist。

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

Instead of DoesNotExist , how can I have go be None instead?而不是DoesNotExist ,我怎么能让go变成None呢?

There is no 'built in' way to do this.没有“内置”方法可以做到这一点。 Django will raise the DoesNotExist exception every time. Django 每次都会引发 DoesNotExist 异常。 The idiomatic way to handle this in python is to wrap it in a try catch:在 python 中处理此问题的惯用方法是将其包装在 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.我所做的是继承models.Manager,像上面的代码一样创建一个safe_get ,并将该管理器用于我的模型。 That way you can write: SomeModel.objects.safe_get(foo='bar') .这样你就可以写: SomeModel.objects.safe_get(foo='bar')

从 django 1.6 开始,您可以像这样使用first()方法:

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

From django docs 来自 django 文档

get() raises a DoesNotExist exception if an object is not found for the given parameters.如果未找到给定参数的对象, get()将引发DoesNotExist异常。 This exception is also an attribute of the model class.这个异常也是模型类的一个属性。 The DoesNotExist exception inherits from django.core.exceptions.ObjectDoesNotExist DoesNotExist异常继承自django.core.exceptions.ObjectDoesNotExist

You can catch the exception and assign None to go.您可以捕获异常并分配None去。

from django.core.exceptions import ObjectDoesNotExist
try:
    go  = Content.objects.get(name="baby")
except ObjectDoesNotExist:
    go = 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.如果没有条目匹配,则go将为None ,否则将返回 Content 条目。

Note:It will raises exception MultipleObjectsReturned if more than one entry returned for name="baby" .注意:如果name="baby"返回多个条目,则会引发异常MultipleObjectsReturned

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

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现在 go 变量可以是你想要的对象,也可以是 None

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

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()现在你有 MyModel.objects.get() 以及 MyModel.objetcs.get_or_none()

you could use exists with a filter:您可以将exists与过滤器一起使用:

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如果您只想知道它是否存在,只是一种选择

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")

也许你使用更好:

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

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在视图中的不同点处理异常可能真的很麻烦..在 models.py 文件中定义自定义模型管理器怎么样,比如

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 ie通过这种方式,它可以很容易地在视图中处理,即

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

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

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

I think it isn't bad idea to use get_object_or_404()我认为使用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.您可以在 django 在线文档中阅读有关get_object_or_404()的更多信息。

From django 1.7 onwards you can do like:从 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):
    ...

The advantage of "MyQuerySet.as_manager()" is that both of the following will work: “MyQuerySet.as_manager()”的优点是以下两个都可以工作:

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

This is a copycat from Django's get_object_or_404 except that the method returns None.这是 Django 的 get_object_or_404 的复制品,只是该方法返回 None。 This is extremely useful when we have to use only() query to retreive certain fields only.当我们必须使用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

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 (eg from a subset of child items belonging to a parent instance):这是帮助函数的一个变体,它允许您有选择地传入QuerySet实例,以防您想从模型的all对象查询集以外的查询集(例如,从属于的子项的子集)获取唯一对象(如果存在)到父实例):

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, eg:这可以通过两种方式使用,例如:

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

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.关于何时应该在 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.虽然我同意这一点,但我认为应该保留一个例外,好吧,例外,并且“理想情况”应该运行而不会碰到一个。

We can use Django builtin exception which attached to the models named as .DoesNotExist .我们可以使用附加到名为.DoesNotExist的模型的 Django 内置异常。 So, we don't have to import ObjectDoesNotExist exception.因此,我们不必导入ObjectDoesNotExist异常。

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

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.很难编写和阅读try-except每次您想从模型中获取元素,如@Arthur Debert 的回答。 So, my solution is to create an Getter class which is inherited by the models:所以,我的解决方案是创建一个由模型继承的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)
    ...

In this way, I can get the actual element of MyActualModel or None :这样,我可以获得MyActualModelNone的实际元素:

MyActualModel.try_to_get(pk_id=1)

I use Django 2.2.16.我使用 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:views中,你可以这样调用:

SUser.objects.get_if_exist(id=1)

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.

What if something like this?如果是这样怎么办?

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

How about a slice?切片怎么样? It will parse to a limit 1.它将解析到限制 1。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如果存在的话,如何注释相关对象到queryset,否则如何注释None? (Django) - How to annotate a related object to queryset, in cases it exists, and None otherwise? (Django) 如何编辑对象(如果存在)或创建Django中不存在的对象? - How do I edit an object if it exist or create an object that doesn't exist in Django? 如何在Django模板中使用“不是不是”? - How do I use 'is not None' in Django Templates? django 南 - 列 none 不存在 - django south - column none does not exist 在Django中使用callproc()时,为什么我不存在PROCEDURE? - Why do I get PROCEDURE does not exist when using callproc() in Django? 我如何让python接受元素0和1(如果存在)而取元素0(如果元素1不存在)呢? - How do I get python to take element 0 and 1 if they exist and take element 0 if element 1 does not exist? 如何在我的 Django 工作中在 mongoengine 中搜索 null 或 none? - how do I search null or none in mongoengine in my django work? 如何在 Django Mako 模板中显示 ${'None'}? - How do I display ${'None'} in a Django Mako template? (Django)如何使“objects.get()”与存在的参数一起工作? - (Django) How do I make 'objects.get()' to work with an argument that exists? 使用 Heroku 进行部署时,如何克服“'django_content_type' 不存在”错误? - How can I get past this “'django_content_type' does not exist” error when deploying with Heroku?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM