class Tag(BaseModel):__tablename__ = 'tag'id = Column(types.Integer, primary_key=True)table_name = Column(types.String(64))user_id = Column(types.Integer)row_id = Column(types.Integer)name = Column(types.String, nullable=False)Index('tag_backref_idx', Tag.table_name, Tag.user_id, Tag.row_id, Tag.name, unique=True)Index('tag_name_idx', Tag.table_name, Tag.user_id, Tag.name)
@declared_attrdef tags(cls):return orm.relationship(Tag,primaryjoin=and_(Tag.table_name==cls.__tablename__,Tag.user_id==None,Tag.row_id==cls.id,),foreign_keys=[Tag.table_name, Tag.user_id, Tag.row_id],)
f = Session.query(Foo).get(1)f.tags # == [list of global Tag objects applied on object f]
--
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To post to this group, send email to sqlal...@googlegroups.com.
To unsubscribe from this group, send email to sqlalchemy+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
> So if I understand correctly,
>
> You would choose the (1) assoc_id/type secondary table approach that you outline in the blog post over having (2) redundant schema per-table with direct FKs (FooTag, BarTag, etc)? Why? (I have a feeling I'm misparsing what you're saying.)
I might actually do FooTag, BarTag, but each of those would have its own table alone (i.e. concrete table style). That way each object has a collection of "tags" thats entirely portable from the rest. Only if you need to query across "all tags" or otherwise correlate different types would I deal with an intermediary table. it depends on what kind of queries you want to do.
>
> (1) worries me because I would need approximately one extra row in the secondary table per row in other tables, plus the extra join. I'd need to test this but I imagine the performance implications would be significant. With (2) I get more tables, but at least it's a reasonably compact and simple representation.
>
> I do agree that the hackish rails-style association is not ideal.
if the table is under a million rows and you're not on MySQL most differences would be negligible. The comparison of an index of (int, string) versus (int, int) comes into play as well.
@Taggableclass User(BaseModel)__tablename__ = "user"
Looks like this almost-sorta works:class TagMixin(object):@declared_attrdef TagClass(cls):
class Tag(BaseModel):__tablename__ = "tag_%s" % cls.__tablename__
id = Column(types.Integer, primary_key=True)time_created = Column(types.DateTime, default=datetime.now, nullable=False)row_id = Column(types.Integer, ForeignKey(cls.id), index=True)name = Column(types.String, nullable=False, index=True)# This part breaks with... sqlalchemy.exc.InvalidRequestError: Table 'tag_user' is already defined for this MetaData instance.# @declared_attr# def tags(cls):# return orm.relationship(cls.TagClass, backref='tagged')
class User(BaseModel, TagMixin):__tablename__ = 'user'id = Column(types.Integer, primary_key=True)...
InvalidRequestError: Table 'tag_user' is already defined for this MetaData instance. Specify 'extend_existing=True' to redefine options and columns on an existing Table object.
class TagMixin(object):@declared_attrdef tags(cls):
class Tag(BaseModel):__tablename__ = "tag_%s" % cls.__tablename__
id = Column(types.Integer, primary_key=True)time_created = Column(types.DateTime, default=datetime.now, nullable=False)row_id = Column(types.Integer, ForeignKey(cls.id), index=True)name = Column(types.String, nullable=False, index=True)
cls.TagClass = Tagreturn orm.relationship(Tag, backref='tagged')
--
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To view this discussion on the web visit https://groups.google.com/d/msg/sqlalchemy/-/rSjfceG4OQEJ.
To unsubscribe from this group, send email to sqlalchemy+unsubscribe@googlegroups.com.