Hi Mike,
I'm using your variant on the 'unique object' recipe (see previous
posting http://goo.gl/I1buRz) with some composite association proxies.
Recently, the data I've been working with introduced a duplicate in the
property I've been using with attribute_mapped_collection(), so I'm trying
to modify the collection class such that the key is based on a column in
the association object instead of a column in the 'right' table. My
modified mapping results in a FlushError when attempting to update a
UserCourse object because it conflicts with a persistent instance.
*Basic model:*
class User(Base):
id = Column(Integer, primary_key=True)
name = Column(Text)
class Course(Base):
id = Column(Integer, primary_key=True)
title = Column(Text, unique=True)
class UserCourse(Base):
user_id = Column(Integer, ForeignKey(User.id), primary_key=True)
course_id = Column(Integer, ForeignKey(Course.id), primary_key=True)
grade = Column(Integer)
*Original use:*
user.courses['math'] = 100 # user.courses[course.name] = grade
*Desired use:*
user.courses['1'] = 100 # user.courses[course.id] = grade
*Original model:*
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(Text)
courses = association_proxy('user_courses', 'grade',
creator=lambda k, v: UserCourse(course_title=k, grade=v))
def __init__(self, name):
self.name = name
class Course(Base):
__tablename__ = 'courses'
id = Column(Integer, primary_key=True)
title = Column(Text, unique=True)
def __init__(self, title):
self.title = title
class UserCourse(Base):
__tablename__ = 'user_courses'
user_id = Column(Integer, ForeignKey(User.id), primary_key=True)
course_id = Column(Integer, ForeignKey(Course.id), primary_key=True)
grade = Column(Integer)
user = relationship(
User,
backref=backref(
'user_courses',
collection_class=attribute_mapped_collection('course_title'),
cascade='all, delete-orphan'
)
)
course = relationship(Course)
def __init__(self, course_title, grade):
self._course_title = course_title
self.grade = grade
@property
def course_title(self):
if self.course is not None:
return self.course.title
else:
return self._course_title
@event.listens_for(Session, "after_attach")
def after_attach(session, instance):
if isinstance(instance, UserCourse):
with session.no_autoflush:
course =
session.query(Course).filter_by(title=instance._course_title).first()
if course is None:
course = Course(title=instance._course_title)
instance.course = course
*Error-producing model modified for desired use:*
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(Text)
courses = association_proxy('user_courses', 'grade',
creator=lambda k, v: UserCourse(course_id=k, grade=v))
def __init__(self, name):
self.name = name
class Course(Base):
__tablename__ = 'courses'
id = Column(Integer, primary_key=True)
title = Column(Text, unique=True)
def __init__(self, title):
self.title = title
class UserCourse(Base):
__tablename__ = 'user_courses'
user_id = Column(Integer, ForeignKey(User.id), primary_key=True)
course_id = Column(Integer, ForeignKey(Course.id), primary_key=True)
grade = Column(Integer)
user = relationship(
User,
backref=backref(
'user_courses',
collection_class=attribute_mapped_collection('course_id'),
cascade='all, delete-orphan'
)
)
course = relationship(Course)
def __init__(self, course_id, grade):
self._course_id = course_id
self.grade = grade
@event.listens_for(Session, "after_attach")
def after_attach(session, instance):
if isinstance(instance, UserCourse):
with session.no_autoflush:
course = session.query(Course).filter_by
(id=instance._course_id).first()
# no way to create to Course object by id alone, but I
don't need that capability
# new UserCourse objects are limited to existing courses
instance.course = course
Seems like there's a simple way to accomplish this as the dictionary
collection is now coming directly from the association object instead of
having to hop across it to the 'courses' table. Could you point me in the
right direction? Thanks.
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.