发现SQLAlchemy对象的引用

Den*_*ach 8 python orm sqlalchemy

我有很多模型类,它们之间有关系,需要编辑CRUD接口.问题是某些对象无法删除,因为有其他对象引用它们.有时我可以设置ON DELETE规则来处理这种情况,但在大多数情况下,我不希望自动删除相关对象,直到它们被手动解除绑定.无论如何,我想向编辑器呈现一个引用当前查看对象的对象列表,并突出显示那些因FOREIGN KEY约束而无法删除的对象.是否有自动发现引用的现成解决方案?

更新

这个任务似乎很常见(例如django ORM显示所有依赖关系),所以我想知道它还没有解决方案.

建议有两个方向:

  1. 枚举当前对象的所有关系并通过它们backref.但并不能保证所有关系都已backref定义.而且,有些情况下backref毫无意义.虽然我可以在任何地方定义它,但我不喜欢这样做而且它不可靠.
  2. (由van和stephan建议)检查所有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
Run Code Online (Sandbox Code Playgroud)

感谢所有帮助过我的人,尤其是斯蒂芬和范.

van*_*van 6

SQL:我绝对不同意S.Lott的回答.我不知道开箱即用的解决方案,但绝对有可能发现所有具有ForeignKey约束的表到给定的表.人们需要用正确的INFORMATION_SCHEMA观点,如REFERENTIAL_CONSTRAINTS,KEY_COLUMN_USAGE,TABLE_CONSTRAINTS,等见的SQL Server实例.有了一些限制和扩展,大多数版本的新关系数据库都支持INFORMATION_SCHEMA标准.当您拥有表中的所有FK信息和对象(行)时,需要运行一些SELECT语句来获取其他表中引用给定行的所有其他行并防止其被删除.

SqlAlchemy:正如stephan在他的评论中指出的那样,如果你使用ormwith backreffor relationship,那么你应该很容易得到对象的列表,这些对象继续引用你想要删除的对象,因为这些对象基本上是映射的对象的属性(child1.Parent).

如果你使用Tablesql炼金术的对象(或者不总是backref用于关系),那么你必须获得foreign_keys所有表的值,然后对于所有那些ForeignKey调用references(...)方法,将表作为参数.通过这种方式,您将找到所有引用您的对象映射到的表的FK(和表).然后,您可以通过为每个FK构建查询来查询所有引用对象的对象.