2009-12-14 4 views
4

the example in the docs과 매우 유사한 시나리오에서 태그에 연관 프록시를 사용하려고합니다. 여기 내 스키마 (이 블로그의)의 부분 집합은 선언적인 사용이다 :SQLAlchemy/associativeproxy가 내 태그를 복제하는 이유는 무엇입니까?

여기
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')] 

이미 ID 2에 존재하는 태그 u'bar'; SQLAlchemy가 왜 SQLAlchemy를 만들지 않고 첨부 만 했습니까? 어떻게 든 내 스키마가 잘못 되었나요?

답변

3

면책 조항 : SQLAlchemy를 사용한 이후로 여러 해가되었습니다. 그래서 이것은 무엇보다도 추측입니다.

SQLAlchemy가 마술로 'bar'문자열을 가져 와서 many-to-many 테이블에 삽입을 수행 할 때 관련 태그를 찾길 기대하는 것처럼 보입니다. 문제의 필드 ('태그')가 기본 키가 아니기 때문에 이것이 유효하지 않다고 생각합니다.

Tag 테이블이 실제로 Comment이고 id 및 텍스트 필드와 유사한 상황을 상상해보십시오. 위에서 사용한 것과 동일한 e.comments = [ 'u'Foo', 'u'Bar'] 구문을 사용하여 항목에 주석을 추가 할 수 있기를 기대하지만, 단지 수행하기를 원할 것입니다 INSERT, 동일한 내용의 기존 주석을 확인하지 않습니다.

아마도 여기에있는 것처럼 보이지만 태그 이름의 고유성 제약 조건에 부딪쳐 잘못된 작업을 시도한다고 가정하면 실패합니다.

문제를 해결하는 방법은 무엇입니까? tags.tag를 기본 키로 만드는 것은 논란의 여지는 있지만, SQLAlchemy가 얼마나 효율적인지, SQLAlchemy가이를 얼마나 효율적으로 처리하는지 모릅니다. 태그 개체를 항목에 할당하기 전에 이름으로 태그 개체를 쿼리 해보십시오. 유니 코드 문자열을 취하고 기존 태그를 반환하거나 새 태그를 생성하는 작은 유틸리티 함수를 작성해야 할 수 있습니다.

+0

글쎄, 내가 링크 된 예는 그것이 작동한다는 것을 암시하는 것처럼 보인다. 적어도,이 멋진 프록시를 정의하여 문자열 목록으로 태그를 표시하는 것은 어리석은 짓이며, 사용하기 전에 수동으로 태그 ID를 찾아야한다고 말하기 만하면됩니다. 그들의 예에 대한 한가지 이상한 점은'Tag.tag'에 대한 유일한 제약이 실제로 없다는 것입니다. 아마도 그들의 예제는 많은 중복 태그로 끝날 것입니다. 그 시점에서'Tag' 객체를 버리고'EntryTag'에 직접 태그를 넣을 수 있습니다. 하지만 그때 나는 멋진 backref'entries'를 가질 능력을 잃을 것입니다, 그렇지 않습니까? –

+0

사실, 당신 말이 맞아요. 그들은 FAQ에 넣기조차했다 : http://www.sqlalchemy.org/trac/wiki/FAQ# 자동적으로 유일한 키워드 또는 다른 키워드와 키워드를 포함하는 키워드와 그 제안 된 수정을 포함하는 키워드에 대한 쿼리를 제외하고는 자동적으로 키워드를 유지한다 : http : //www.sqlalchemy.org/trac/wiki/UsageRecipes/UniqueObject –

+0

동일한 키워드가 동일한 인스턴스로 해석 될 것으로 예상 할 수 있으므로 해당 예제가 모호하다는 데 동의합니다. 유일성에 대한 제안이 적은 두 번째 테이블을 선택하는 것이 좋습니다. – Kylotan

0

저는 SQLAlchemy 0.5를 사용한 적이 없습니다. (마지막 응용 프로그램은 0.4 버전을 사용했습니다.) 코드에서 하나의 버크를 볼 수 있습니다. association_proxy 객체를 수정하고 다시 할당하지 않아야합니다.

같은 일을보십시오 : (!, 수입을 포함하십시오)

e.tags.append(u"bar") 

대신 문제가 해결되지 않는 경우, 해당 테이블에 대한 전체 작업 예제를 붙여 시도

e.tags = ... 

및 좀 더 조언 해 줄게.

+0

좋은 생각이지만,'append'는 같은 결과를줍니다 (커밋시 중복 키). 내가 직장에 없을 때이 예를 완성 할 것입니다 (이것은 직장 프로젝트가 아닙니다). –

관련 문제