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.

Reply via email to