Вопрос

Я пытаюсь использовать прокси-сервер ассоциации для тегов по сценарию, очень похожему на пример в документации.Вот подмножество моей схемы (это блог), использующее декларативный подход:

class Tag(Base):
    __tablename__ = 'tags'
    id            = Column(Integer, primary_key=True)
    tag           = Column(Unicode(255), unique=True, nullable=False)

class EntryTag(Base):
    __tablename__ = 'entrytags'
    entry_id      = Column(Integer, ForeignKey('entries.id'), key='entry', primary_key=True)
    tag_id        = Column(Integer, ForeignKey('tags.id'), key='tag', primary_key=True)

class Entry(Base):
    __tablename__ = 'entries'
    id            = Column(Integer, primary_key=True)
    subject       = Column(Unicode(255), nullable=False)
    # some other fields here
    _tags         = relation('Tag', backref='entries', secondary=EntryTag.__table__)
    tags          = association_proxy('_tags','tag')

Вот как я пытаюсь его использовать:

>>> e = db.query(Entry).first()
>>> e.tags
[u'foo']
>>> e.tags = [u'foo', u'bar']  # really this is from a comma-separated input
db.commit()
Traceback (most recent call last):
[...]
sqlalchemy.exc.IntegrityError: (IntegrityError) duplicate key value violates unique constraint "tags_tag_key"
 'INSERT INTO tags (id, tag) VALUES (%(id)s, %(tag)s)' {'tag': 'bar', 'id': 11L}
>>> map(lambda t:(t.id,t.tag), db.query(Tag).all())
[(1, u'foo'), (2, u'bar'), (3, u'baz')]

Тег u'bar' уже существовал с идентификатором 2;почему SQLAlchemy просто не прикрепил его вместо того, чтобы пытаться создать?Моя схема как-то неправильная?

Это было полезно?

Решение

Отказ от ответственности:Прошло много времени с тех пор, как я использовал SQLAlchemy, так что это скорее предположение, чем что-либо еще.

Похоже, вы ожидаете, что SQLAlchemy волшебным образом возьмет строку «bar» и найдет для нее соответствующий тег при выполнении вставки в таблицу «многие ко многим».Я ожидаю, что это неверно, поскольку рассматриваемое поле («тег») не является первичным ключом.

Представьте себе аналогичную ситуацию, когда ваша таблица тегов на самом деле представляет собой комментарий, также с идентификатором и текстовым полем.Вы ожидаете, что сможете добавлять комментарии к записи с тем же синтаксисом e.comments = ['u'Foo', 'u'Bar'], который вы использовали выше, но вы бы хотели, чтобы он просто выполнялся INSERT, а не проверка существующих комментариев с тем же содержанием.

Вероятно, именно это он и делает здесь, но он достигает ограничения уникальности вашего имени тега и терпит неудачу, предполагая, что вы пытаетесь сделать неправильную вещь.

Как это исправить?Сделать tags.tag первичным ключом, пожалуй, правильно, хотя я не знаю, насколько это эффективно и насколько хорошо SQLAlchemy с этим справляется.В противном случае попробуйте запросить объекты тегов по имени, прежде чем назначать их записи.Возможно, вам придется написать небольшую служебную функцию, которая принимает строку в Юникоде и либо возвращает существующий тег, либо создает для вас новый.

Другие советы

Я еще никогда не использовал SQLAlchemy 0.5 (мое последнее приложение, использующее его, было на основе версии 0.4), но я вижу одну особенность в вашем коде:вам следует изменить объект Association_proxy, а не переназначать его.

Попробуйте сделать что-то вроде:

e.tags.append(u"bar")

Вместо

e.tags = ...

Если это не сработает, попробуйте вставить полный рабочий пример для этих таблиц (включая импорт, пожалуйста!), и я дам вам еще несколько советов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top