this has been added to the wiki at:

https://bitbucket.org/zzzeek/sqlalchemy/wiki/UsageRecipes/WriteableTuple



On 05/30/2016 12:21 PM, Mike Bayer wrote:


On 05/30/2016 04:57 AM, 'Pankaj Gupta' via sqlalchemy wrote:
I'm facing exactly same issue.

It worked in past very well (below 1.0) and was very useful to update
attribute or add new attributes (temporarily), now i can neither update
not add new attributes.

I'm wondering if someone can help us to port to later release or give
some guidance for us to make it work.


The Query object is subclassable, here's a naive implementation of a
wrapper for that tuple:


from sqlalchemy.orm.query import Query


class WritableKeyedTuple(object):
    def __init__(self, elem):
        self._elem = elem

    # TODO: this is slow, come up with a faster object
    # that is still writable.
    def __getattr__(self, key):
        return getattr(self._elem, key)

    def __repr__(self):
        inner = [
            (key, getattr(self._elem, key))
            for key in self._elem.keys()
        ]
        outer = [
            (key, getattr(self, key))
            for key in dir(self) if not key.startswith("_")
        ]
        return "WritableKeyedTuple(%s)" % (
            ", ".join(
                "%s=%s" % (key, value) for
                (key, value) in inner + outer
            )
        )


class WritableTupleQuery(Query):
    def __iter__(self):
        it = super(WritableTupleQuery, self).__iter__()

        cdesc = self.column_descriptions
        if len(cdesc) > 1 or not isinstance(cdesc[0]['type'], type):
            return (
                WritableKeyedTuple(elem)
                for elem in it
            )
        else:
            return it

if __name__ == '__main__':

    from sqlalchemy import create_engine, Column, Integer
    from sqlalchemy.orm import sessionmaker
    from sqlalchemy.ext.declarative import declarative_base

    Base = declarative_base()

    class A(Base):
        __tablename__ = 'a'
        id = Column(Integer, primary_key=True)
        x = Column(Integer)
        y = Column(Integer)

    e = create_engine("sqlite://", echo=True)
    Base.metadata.create_all(e)

    Session = sessionmaker(bind=e, query_cls=WritableTupleQuery)

    s1 = Session()
    s1.add_all([A(x=1, y=2), A(x=3, y=4)])
    s1.commit()

    for im_an_entity in s1.query(A):
        print im_an_entity

    for im_a_tuple in s1.query(A.x, A.y):
        im_a_tuple.supplementary = 'hi'
        print im_a_tuple

    for im_a_tuple in s1.query(A.x):
        im_a_tuple.supplementary = 'hi'
        print im_a_tuple


Thanks,
-Pankaj

On Friday, May 15, 2015 at 7:26:16 PM UTC+5:30, Antoine Leclair wrote:

    Hi all,

    I recently tried to update SQLAlchemy from 0.9.4 to 1.0.4 in a
    client's project. However, I run into an error that is not there
    with 0.9.4.

    It happens for this type of query:

        q = DBSession.query(User) \
                     .filter(User.profile_id.in_(profile_ids)) \
                     .join(Profile)
        q = q.outerjoin(
            CouplePhoto,
            and_(
                User.profile_id==CouplePhoto.profile_id,
                CouplePhoto.avatar==True
            )
        )
        q = q.with_entities(User.profile_id, User.given_name,
User.zipcode,
                            CouplePhoto.filename, User.gender,
Profile.sex)
        users_data = q.all()
        for u in users_data:
            if u.filename:
                *# the next line causes the error in 1.0.4*
    *            u.filename = 'something'*

    In 0.9.4, the type of "u" was "KeyedTuple" and in 1.0.4, it's
    "result". The error is "AttributeError: can't set attribute".

    The goal of this assignation is to recompute the filename according
    to the original filename (to show a thumb instead of original). It
    is not saved in the database.

    Now, I know this is not necessarily good design and I would not have
    done it that way myself. But the code base is probably full of this
    type of thing, mixed with business logic, and trying to fix them is
    clearly not doable in the short term.

    And we have to update SQLAlchemy, because some circular reference
    issue was fixed when using Alembic somewhere between 0.9.4 and 1.0.4.

    Is there anything I should be aware of to help with this?

    Thanks in advance.

--
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 sqlalchemy+unsubscr...@googlegroups.com
<mailto:sqlalchemy+unsubscr...@googlegroups.com>.
To post to this group, send email to sqlalchemy@googlegroups.com
<mailto:sqlalchemy@googlegroups.com>.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

--
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to