Django如何检查相关对象是否存在错误:RelatedObjectDoesNotExist

129

我的模型中有一个方法has_related_object,需要检查是否存在相关的对象。

class Business(base):
      name =  models.CharField(max_length=100, blank=True, null=True)

  def has_related_object(self):
        return (self.customers is not None) and (self.car is not None)


class Customer(base):
      name =  models.CharField(max_length=100, blank=True, null=True)
      person = models.OneToOneField('Business', related_name="customer")

但我收到了以下错误:

Business.has_related_object()

RelatedObjectDoesNotExist: Business没有客户。


8
我无法相信 Django 没有提供这个方法。 - etlds
1
正如@mrts的答案所示,有一种很好的方法可以做到这一点,即hasattr(self, 'customers')。 Django不需要实现现有功能。 - Akaisteph7
4个回答

236
使用hasattr(self, 'customers')来避免异常检查,如Django文档推荐的那样
def has_related_object(self):
    return hasattr(self, 'customers') and self.car is not None

6
通常情况下,在Python中采用EAFP编程风格。具体解释请参考此链接:https://docs.python.org/3/glossary.html#term-eafp - Dustin Wyatt
13
除了在这种情况下请求许可同样容易外,将所有内容都置于try: except子句中往往会掩盖无关的错误,使问题更难以调试。 - kloddant
1
@kloddant 我认为不需要使用“except”。像你和Guido(https://mail.python.org/pipermail/python-dev/2014-March/133118.html)一样,我认为EAFP并不*正确*,但我认为这是写Python的常见方式。虽然如你所说,EAFP通常是*错误的*,但这与Python中常用的习惯用法无关。 - Dustin Wyatt

98

这是因为ORM需要去数据库检查customer是否存在。由于它不存在,所以会引发异常。

您需要将方法更改为以下内容:

def has_related_object(self):
    has_customer = False
    try:
        has_customer = (self.customers is not None)
    except Customer.DoesNotExist:
        pass
    return has_customer and (self.car is not None)

我不知道self.car的情况,如果需要调整,就留给你自己去处理。

顺便提一下: 如果你正在对一个拥有ForeignKeyFieldOneToOneFieldModel进行操作,你可以使用以下方法来避免进行数据库查询。

def has_business(self):
    return self.business_id is not None

2
请注意,根据文档(https://docs.djangoproject.com/en/1.9/ref/models/fields/#database-representation),"[...] 除非您编写自定义 SQL,否则您的代码不应该处理数据库列名。您将始终处理模型对象的字段名称。"。 - Antoine Pinsard
1
这种方法比其他答案更快,因为它不需要与数据库交互。 - Dan
4
在这种情况下使用列名会更快,因为Django不会尝试在底层查询中进行联接。 Django鼓励采用这些实践以进行必要的优化。https://docs.djangoproject.com/en/2.1/topics/db/optimization/#use-foreign-key-values-directly - Bobort
4
如果您尝试查询一个对象的关系之一,为什么Django不只是返回“None”呢?抛出异常似乎有些过度。 - mecampbellsoup
2
很可能是为了覆盖可为空字段的情况。当允许为空时,返回None。当不允许为空时,则会引发异常。 - schillingt
1
@Dan,我认为这个(尝试 self.customers 并捕获 DoesNotExist)确实会查询客户。Django 无法知道关联的客户是否存在,因为外键列在客户而不是业务上。 - David Winiecki

9

虽然这是一个老问题,但我认为这可能对正在寻找处理此类异常的人有所帮助,特别是当您想要检查 OneToOne 关系时。

我的解决方案是使用 django.core.exceptions 中的 ObjectDoesNotExist 异常:

from django.core.exceptions import ObjectDoesNotExist

class Business(base):
      name =  models.CharField(max_length=100, blank=True, null=True)

    def has_related_object(self):
        try:
            self.customers
            self.car
            return True
        except ObjectDoesNotExist:
            return False


class Customer(base):
      name =  models.CharField(max_length=100, blank=True, null=True)
      person = models.OneToOneField('Business', related_name="customer")


0

你可能在调试时已经创建了用户,但是没有配置文件,因此即使现在编写了自动化代码,他们仍然没有配置文件。请尝试在signal.py文件中使用以下代码,然后创建超级用户,以超级用户身份登录,然后从那里添加第一个帐户的配置文件。这对我有用...

@receiver(post_save, sender=User, dispatch_uid='save_new_user_profile')
def save_profile(sender, instance, created, **kwargs):
    user = instance
    if created:
        profile = UserProfile(user=user)
        profile.save()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接