Как обновить отношения многие ко многим, используя id с sqlalchemy? - PullRequest
0 голосов
/ 13 февраля 2019

Я знаю, что могу просто обновить отношения многие ко многим, как это:

tags = db.Table('tags',
    db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'), primary_key=True),
    db.Column('page_id', db.Integer, db.ForeignKey('page.id'), primary_key=True)
)

class Page(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    tags = db.relationship('Tag', secondary=tags, lazy='subquery',
        backref=db.backref('pages', lazy=True))

class Tag(db.Model):
    id = db.Column(db.Integer, primary_key=True)

tag1 = Tag()
tag2 = Tag()
page = Page( tags=[tag1])

и позже для обновления:


page.append(tag2)

, но я хочу обновить их только по идентификатору тега, Предположим, мне нужно создать общую функцию, которая принимает только person и id s для адресов, и обновлять ее.Я хочу что-то вроде этого:

page = Page(tags=[1,2]) # 1 and 2 are primary keys of (tag)s

или в функции

def update_with_foreignkey(page, tags=[1,2]):
 # dosomething to update page without using Tag object
 return  updated page

1 Ответ

0 голосов
/ 13 февраля 2019

Это было немного сложно и с использованием зла 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()

Я не уверен насчет предостережений этого подхода, но он работает для меня.Любые улучшения и предложения приветствуются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...