Это было немного сложно и с использованием зла eval
, но, наконец, я нашел общий способ обновить многие ко многим отношениям, используя внешние ключи.Моя цель состояла в том, чтобы обновить мой объект, получив данные из запроса PUT
, и в этом запросе я получаю только внешние ключи для связи с другими данными.
Пошаговое решение:
1- Найти отношения в объекте, я нахожу их, используя __mapper__.relationships
2- Найти ключ, который представляет отношение.
for rel in Object.__mapper__.relationships:
key = str(rel).rsplit('.',1)[-1]
в случае, если он возвращает 'tags'
в качестверезультат.
3- Найти модель для другой стороны отношения (в этом примере Tag
).3-1 Найдите название таблицы.3-2 Преобразуйте имя таблицы в camleCase, потому что sqlalchemy
использует подчеркивание для имени таблицы и camelCase для модели.3-3 Используйте eval
, чтобы получить модель.
if key in data:
table = eval(convert_to_CamelCase(rel.table.name))
temp = table.query.filter(table.id.in_(data[key])).all() # this line convert ids to sqlacemy objects
Все вместе
def convert_to_CamelCase(word):
return ''.join(x.capitalize() or '_' for x in word.split('_'))
def update_relationship_withForeingkey(Object, data):
for rel in Object.__mapper__.relationships:
key = str(rel).rsplit('.',1)[-1]
if key in data:
table = eval(convert_to_CamelCase(rel.table.name))
temp = table.query.filter(table.id.in_(data[key])).all() # this line convert ids to sqlacemy objects
data[key] = temp
return data
data
- это то, что я получаю из запроса, а Object
- это sqlalchemy
Модель, которую я хочу обновить.
Запуск этого обновления в несколько строк дает мне результат:
item = Object.query.filter_by(id=data['id'])
data = update_relationship_withForeingkey(Object,data)
for i,j in data.items():
setattr(item,i,j)
db.session.commit()
Я не уверен насчет предостережений этого подхода, но он работает для меня.Любые улучшения и предложения приветствуются.