Automagic __repr__ for SQLAlchemy entities with primary key columns with Declarative Base.

July 5th, 2013 by exhuma.twn

According to the Python documentation about __repr__, a call to repr() should give you a valid Python expression if possible. This is a very useful guideline. And it is also something I I like to implement in my Python projects as much as possible.

Now, for mapped database entities, you might argue that it makes sense to have a default constructor as long as it accepts the primary key columns.

By default, it is possible to create new instances by specifying column values in SQLAlchemy. For example:

user = User(name=u'John Doe', email=u'')

It should be possible to create such “repr” values automatically for primary keys. All the required meta info is available. Digging through the SA docs, I found that it is possible the customize Base in order to add behaviour to all mapped entities!

Here’s the result:

With this in place, all representations of DB entities will finally make sense and be copy/pasteable directly into your code.

Of course, by nature of ORMs, the new instances created this way will be detached from the session and need to be merged before you can do any DB related operations on them! A simple example:

from mymodel import User, Session

sess = Session()
user = User(name=u'John Doe', email=u'')
user = sess.merge(user)

Posted in Python | 6 Comments »

  • jkmacc

    This is great, thanks!

    One point, though; mapped tables have to have a primary key, but it doesn’t have to be defined in __table__. It can be specified in __mapper_args__ = {‘primary_key': [__table__.c.mycolumn]}. If done this way, this __repr__ won’t catch it. All primary keys, whether from __table__ or from __mapper_args__ show up in the __mapper__.primary_key attribute on the mapped table. And since all mapped tables must have primary keys, one doesn’t even have to check for them:
    pkeys = self.__mapper__.primary_key

  • exhuma

    You’re welcome :)

    I will test what you’ve said and include it in the post once I’m back from my holiday :)

  • exhuma

    Indeed, using `Class.__mapper__.primary_key` is a better solution. I’ll update the gist in a minute!

  • exhuma

    It’s done! Thanks for the insight! :)

  • elsdoerfer

    This fails when the column name in the table doesn’t match the property name in the mapper. I’ve adapted it to do this:

  • exhuma

    Thanks for noticing this. I have updated the original gist with your changes.


Recent Posts