Если предположить, что в sqlalchemy с помощью mysql модель отношений «многие ко многим», как обновить данные, игнорируя дубликаты? - PullRequest
1 голос
/ 01 июля 2011

Я немного застрял в sqlalchemy, пытаясь обновить некоторые данные.

У меня отношение ко многим и отношение один ко многим . Первый - это связь между автором и возможными написаниями его имени. Второе - это связь авторов с их письменной литературой. Статья может иметь несколько авторов и наоборот.

Предполагается, что автор "Питер Шоу" уже хранит 4 статьи и связан с ним в базе данных. Нет, я хочу «добавить» новый комплект из 6 работ для «Питера Шоу». К сожалению, 4 из 6 документов уже хранятся в базе данных. Вот почему session.commit() приводит к дублированию ошибки.

Есть ли общий способ избежать повторяющихся ошибок и сказать sqlalchemy просто заполнить дыры вместо того, чтобы жаловаться на дубликаты? Ни docus sqlalchemy, ни google не смогли бы просветить меня четким ответом / подходом, поэтому любые предложения хорошо ценятся.

Вот модели, с которыми я тестирую:

class NameSpelling(Base):
    __tablename__ = 'name_spellings'

    id = Column(Integer, primary_key=True)
    name = Column(String(255), nullable=False, unique=True, index=True)
    authors_id = Column(Integer, ForeignKey('authors.id'))

    def __init__(self, name=None):
        self.name = name

    def __repr__(self):
        return "NameSpelling(%r)" % (self.name)

class Author(Base):
    __tablename__ = 'authors'

    id = Column(Integer, primary_key=True)
    name = Column(String(255), nullable=True, unique=True, index=True)

    papers = relationship('Paper',
                          secondary=author_paper,
                          backref='authors')

    name_spellings = relationship(NameSpelling,
                                  order_by=NameSpelling.id,
                                  backref="author",
                                  cascade="all, delete, delete-orphan")

    def __init__(self, name=None):
        self.name = name

    def __repr__(self):
        return "Authors(%r, %r)" % (self.name_spellings, self.name)


class Paper(Base):
    __tablename__ = 'papers'

    id = Column(Integer, primary_key=True)
    title = Column(String(1500), nullable=False, index=True)
    url = Column(String(255), nullable=False, unique=True, index=True)
    date = Column(Date(), nullable=True)

    def __init__(self, title=None, url=None, date=None):
        self.title = title
        self.url = url
        self.date = date

    def __repr__(self):
        return "Paper(%r)" % (self.title)

1 Ответ

0 голосов
/ 30 марта 2012

У меня точно такая же проблема с проектом SQLAlchemy.То, что я в итоге сделал (и что, вероятно, является плохим способом решения проблемы), это проверка коллекций отношений перед добавлением нового экземпляра в сеанс и заменой связанных экземпляров на результат session.merge (), если таковой имеется.

Это выглядит примерно так:

def add_instance_to_session(instance, session):
    '''
    Add instance to session, while checking for existing child instances in
    the relationship collection instance.child_list.
    '''
    def _merge_and_replace(child):
        with session.no_autoflush:
            merged_child = session.merge(child)
            if id(merged_child) != id(child):
                try:
                    session.expunge(child)
                except sqlalchemy.exc.InvalidRequestError:
                    # child wasn't in the session to begin with
                    pass
                return merged_child
            else:
                return child
    instance.child_list = map(_merge_and_replace, instance.child_list)
    session.add(instance)

Мне кажется, это работает, но выглядит довольно плохо с точки зрения производительности, особенно если у вас много детей.Возможно, есть лучший способ использовать идиому ON DUPLICATE KEY, которую предлагает mySQL, или аналогичные конструкции.

[править] Сеанс session.expunge (), вероятно, не нужен, если для добавления экземпляров в метод используется только описанный вышесеанс, так как дети не могут быть в сеансе в этот момент.По крайней мере, я так думаю ...

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