我有很多模型类,它们之间有关系,需要编辑CRUD接口。问题是某些对象无法删除,因为有其他对象引用它们。有时我可以设置ON DELETE规则来处理这种情况,但在大多数情况下,我不希望自动删除相关对象,直到它们被手动解除绑定。无论如何,我想向编辑器呈现一个引用当前查看对象的对象列表,并突出显示那些因FOREIGN KEY约束而无法删除的对象。是否有自动发现引用的现成解决方案?
更新
任务似乎很常见(例如django ORM显示所有依赖项),所以我想知道它还没有解决方案。
有两个方向建议:
backref
。但无法保证所有关系都已定义backref
。此外,在某些情况下backref
毫无意义。虽然我可以在任何地方定义它,但我不喜欢这样做而且它不可靠。MetaData
对象的所有表并从foreign_keys
属性中收集依赖项(sqlalchemy_schemadisplay的代码可以作为示例使用,感谢stephan的评论)。这将允许捕获表之间的所有依赖关系,但我需要的是模型类之间的依赖关系。一些外键在中间表中定义,并且没有与它们对应的模型(在关系中用作secondary
)。当然,我可以走得更远并找到相关的模型(必须找到一种方法来做到这一点),但它看起来太复杂了。解决方案
下面是我用作解决方案的基本模型类(为声明性扩展而设计)的方法。它并不完美,不符合我的所有要求,但它适用于我项目的当前状态。结果被收集为字典字典,因此我可以通过对象及其属性显示它们。我还没有决定这是否是个好主意,因为引用者名单有时是巨大的,我被迫将其限制在一些合理的数字。
def _get_referers(self):
db = object_session(self)
cls, ident = identity_key(instance=self)
medatada = cls.__table__.metadata
result = {}
# _mapped_models is my extension. It is collected by metaclass, so I didn't
# look for other ways to find all model classes.
for other_class in medatada._mapped_models:
queries = {}
for prop in class_mapper(other_class).iterate_properties:
if not (isinstance(prop, PropertyLoader) and \
issubclass(cls, prop.mapper.class_)):
continue
query = db.query(prop.parent)
comp = prop.comparator
if prop.uselist:
query = query.filter(comp.contains(self))
else:
query = query.filter(comp==self)
count = query.count()
if count:
queries[prop] = (count, query)
if queries:
result[other_class] = queries
return result
感谢所有帮助我的人,尤其是斯蒂芬和范。
答案 0 :(得分:6)
SQL:我绝对不同意S.Lott'answer。
我不知道开箱即用的解决方案,但是绝对可能来发现对给定表具有ForeignKey约束的所有表。一个人需要正确使用INFORMATION_SCHEMA
视图,例如REFERENTIAL_CONSTRAINTS
,KEY_COLUMN_USAGE
,TABLE_CONSTRAINTS
等。请参阅SQL Server example。通过一些限制和扩展,大多数新版本的关系数据库都支持INFORMATION_SCHEMA
标准。当您拥有表中的所有FK信息和对象(行)时,只需运行少量SELECT
语句即可获取其他表中引用给定行的所有其他行并防止其被删除。
SqlAlchemy:正如 stephan 在评论中所指出的那样,如果您使用orm
与backref
进行关系,则应该非常容易为了获得父对象的列表,这些对象保留对您要删除的对象的引用,因为这些对象基本上是对象的映射属性(child1.Parent
)。
如果你使用sql炼金术的Table
个对象(或者不总是使用backref
来表示关系),那么你必须为所有表获得foreign_keys
的值,然后对于所有这些ForeignKey
的调用references(...)
方法,将您的表作为参数提供。通过这种方式,您将找到所有引用您的对象映射到的表的FK(和表)。然后,您可以通过构造每个FK的查询来查询所有引用您的对象的对象。
答案 1 :(得分:1)
通常,无法在关系数据库中“发现”所有引用。
在某些数据库中,它们可能以显式外键或检查约束的形式使用声明性引用完整性。
但没有要求这样做。它可能不完整或不一致。
任何查询都可以包含未声明的FK关系。如果没有所有查询的范围,您就无法知道所使用但未声明的关系。
要查找“referers”,您必须真正了解数据库设计并拥有所有查询。
答案 2 :(得分:0)
对于每个模型类,只需在每种情况下询问列表并查看它包含的条目数,就可以轻松查看其所有一对多关系是否为空。 (对于COUNT,可能还有一种更有效的方法。)如果有任何与该对象相关的外键,并且您正确设置了对象关系,那么这些列表中至少有一个将是非零的长度。