У меня есть много классов моделей с соотношениями между ними с интерфейсом CRUD для редактирования. Проблема в том, что некоторые объекты не могут быть удалены, поскольку есть другие объекты, ссылающиеся на них. Иногда я могу настроить правило ON DELETE для обработки этого случая, но в большинстве случаев я не хочу автоматического удаления связанных объектов, пока они не будут связаны вручную. В любом случае, я хотел бы представить редактору список объектов, относящихся к текущему, и выделить те, которые препятствуют его удалению из-за ограничения FOREIGN KEY. Есть ли готовое решение для автоматического обнаружения рефереров?
Обновление
Задание кажется довольно распространенным (например, django ORM показывает все зависимости), поэтому мне интересно, что решения пока нет.
Предлагаются два направления:
- Перечислите все отношения текущего объекта и просмотрите их
backref
. Но нет гарантии, что все отношения имеют backref
определение. Более того, в некоторых случаях backref
не имеет смысла. Хотя я могу определить это везде, мне не нравится делать это так, и это ненадежно.
- (предложено van и stephan) Проверьте все таблицы объекта
MetaData
и соберите зависимости из их свойства foreign_keys
(например, код sqlalchemy_schemadisplay можно использовать, благодаря комментариям Стефана). Это позволит перехватывать все зависимости между таблицами , но мне нужны зависимости между модельными классами . Некоторые внешние ключи определены в промежуточных таблицах и не имеют моделей, соответствующих им (используется как 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
Спасибо всем, кто помог мне, особенно Стефану и Вану.