如果Django ORM需要处理坏的主键值,是否有必要自定义ForeignKey子类?

2 投票
1 回答
576 浏览
提问于 2025-04-16 13:31

我正在做的项目中,数据库里有一些脏数据。简单来说,最初设计这个数据库的人创建了外键字段,但没有强制执行参照完整性。现在有一些外键值是无效的,实际上并没有指向存在的记录。通常我会直接删除这些无效的外键值,但这个数据库上的应用程序还使用了存储在这些外键字段中的数字0来表示其他信息。实际上并没有主键为0的记录。

我把这个有问题的表设计封装在Django的ORM类和外键字段里,但不出所料,当找不到外键字段另一端的记录时,它会抛出很多DoesNotExist异常。我一直在想办法,在这个项目中安静地捕获这个异常,而不是到处在代码里加try/except块来处理可能抛出的异常。在这种情况下,我只是想阻止Django ORM抛出这个错误。

我试图通过自定义管理器来实现这一点,覆盖get()方法,并使用use_for_related_field=True这个类属性。不过,在外键有无效键值的情况下,自定义管理器的get()方法似乎并没有被使用。

class FWManager(models.Manager):
    """
    FW's data is "dirty".  Primarily it isn't enforcing referential integrity on 
    many of it's foreign key fields leading to oprphaned records.  Django throws a
    DoesNotExist exception in this case which is troublesome  having to catch it for
    any fk field access.

    Custom FWManager will silently "eat" the DoesNotExist error and return None
    instead.
    """

    use_for_related_fields=True

    def get(self, *args, **kwargs):

        #init
        retval = None

        try:
            retval = super(FWManager, self).get(*args, **kwargs)
        except:
            # silently eat errors
            pass

        return retval

我需要一种方法来捕获并处理可能出现在自定义外键上的DoesNotExist错误,我在寻找如何处理这个问题的例子。或者,也许有人能推荐更好的方法。

1 个回答

1

我觉得应该有更好的方法来解决这个问题,因为你的方案并没有让数据库变得更完整。可以考虑以下几种方法:

  • 改变你的模型:把外键的参数设置为 null=True,然后把零改成 None
  • 把所有外键为'0'的值改成其他值,并创建一个相关的'虚拟对象',用来表示'已删除'的对象

如果在遇到错误时选择默默忽略所有异常,这可能会给你带来很多麻烦,因为你可能会遇到其他问题却不知道原因……

撰写回答