【问题标题】:How to check object relation is populated without catching DoesNotExist如何检查对象关系是否已填充而不捕获DoesNotExist
【发布时间】:2014-11-28 14:51:09
【问题描述】:

我在模型上定义了一对一的关系。我们称父模型 A 和相关模型 B。B 不会一直存在。当我与 A 的实例交互时,如何确定 B 是否存在而无需捕获 DoesNotExist?当我尝试访问 B 的实例(例如print a.b)时,我收到了一个 DoesNotExist 异常。当有对应于它的关系的数据库行时。这是在 django 1.5 上。

我想到的简化模型定义(未在此表单中测试):

class A:
    ...

class B:
    a = models.OneToOneField(A, related_name='a')
    name = models.TextField(...)

fields = ['b__name']
a = A.object.filter(pk=id).selected_related(*fields)
print(a.b)

表 B 有一个外键 a_id。

我提出这个问题的原因是确定是否有更简洁的方法可以通过 API 执行此操作,而不是捕获异常。

【问题讨论】:

  • 你能展示你的模型定义吗?
  • 你为什么不想抓住 B.DoesNotExist?这是非常标准的异常处理。
  • 您的 ForeignKey 字段是否允许空值?
  • 我的外键允许空值,正确。
  • "这是非常标准的异常处理。"这是导致丑陋代码的糟糕 API。异常捕获就是这样,一个例外情况。如果没有 API 来检查关系是否存在,那很好,只是希望有人确认。

标签: django


【解决方案1】:

如果我理解正确的话,首先属性“related_name”用于从反向外键对象引用当前对象,所以模型定义应该是这样的:

class A:
   ...

class B:
    a = models.OneToOneField(A, related_name='alias_for_b')
    name = models.TextField(...)

验证码可以很简单:

if hasattr(a, 'alias_for_b'):
    print(a.b) or print(a.alias_for_b)

希望对你有帮助!!

【讨论】:

    【解决方案2】:

    假设您有A a 的实例。正如您正确所说的,您可以使用 print(a.b) (Python 3 语法)之类的东西访问 B b 的相关实例。如果可能没有相关项目并且您不希望用户收到错误,那么您需要将该调用包装到 b 中。比如:

    try:
        print(a.b)
    except:
        print('Nothing to see here')
    

    它会在尝试呈现之前检查b 的存在,如果它不存在则不会这样做。

    或者,您可以从另一个方向处理此问题。给定实例a,您可以查找B.objects.filter(your_relation_name=a)。这种方式不会涉及任何错误捕获,如果不存在这样的b,则只是一个空白查询集。

    【讨论】:

    • 为什么捕获 Exception 会比捕获 DoesNotExist 更好?
    • 我不关心效率,它更容易出错,因为它可以捕获所有异常,甚至是意外异常。
    • 我的意图是不必捕获异常。我正在寻找一个 API。似乎很奇怪,如果不捕获异常,这是不可能的。
    • 明白,我添加了一种更接近您描述的不同方式来执行此操作。由于我不在我的开发机器上,因此尚未对其进行测试,但它应该可以工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-29
    • 1970-01-01
    • 2014-03-07
    • 1970-01-01
    • 1970-01-01
    • 2013-03-05
    • 2020-04-04
    相关资源
    最近更新 更多