Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQLAlchemy best way to define __repr__ for large tables

I have a bunch of tables in SQLAlchemy that I want to define __repr__.

The standard convention seems to look like this:

def __repr__(self):
    return "<TableName(id='%s')>" % self.id

This is all well and good for small tables. However, I have tables with 40+ columns. Is there a better way of constructing __repr__ such that I am not manually typing out a massive string?

My file housing all tables is called models.py. One solution I thought about was making a method _create_repr_string in models.py that takes care of auto-generating the string for __repr__ to return. I am wondering if there is a more standard way to create __repr__.

like image 379
Intrastellar Explorer Avatar asked Apr 16 '19 17:04

Intrastellar Explorer


People also ask

What is __ repr __ SQLAlchemy?

In Python, __repr__ is a special method used to represent a class's objects as a string. __repr__ is called by the repr() built-in function. You can define your own string representation of your class objects using the __repr__ method. Special methods are a set of predefined methods used to enrich your classes.

Should I use SQLAlchemy or psycopg2?

The psycopg2 is over 2x faster than SQLAlchemy on small table. This behavior is expected as psycopg2 is a database driver for postgresql while SQLAlchemy is general ORM library.

What is the difference between PyODBC and SQLAlchemy?

PyODBC allows you connecting to and using an ODBC database using the standard DB API 2.0. SQL Alchemy is a toolkit that resides one level higher than that and provides a variety of features: Object-relational mapping (ORM) Query constructions.

What is def __ repr __( self?

__repr__(self) : called by the repr() built-in function and by string conversions (reverse quotes) to compute the "official" string representation of an object. object. __str__(self) : called by the str() build-in function and by the print statement to compute the "informal" string representation of an object.


1 Answers

Having good __repr__ for complex objects can be incredibly useful when navigating log files and stacktraces, so it's great that you're trying to come up with a good pattern for it.

I like to have a little helper with a default (BaseModel gets set as the model_class when initializing flask-sqlalchemy in my case).

import typing
import sqlalchemy as sa

class BaseModel(Model):

    def __repr__(self) -> str:
        return self._repr(id=self.id)

    def _repr(self, **fields: typing.Dict[str, typing.Any]) -> str:
        '''
        Helper for __repr__
        '''
        field_strings = []
        at_least_one_attached_attribute = False
        for key, field in fields.items():
            try:
                field_strings.append(f'{key}={field!r}')
            except sa.orm.exc.DetachedInstanceError:
                field_strings.append(f'{key}=DetachedInstanceError')
            else:
                at_least_one_attached_attribute = True
        if at_least_one_attached_attribute:
            return f"<{self.__class__.__name__}({','.join(field_strings)})>"
        return f"<{self.__class__.__name__} {id(self)}>"

Now you can keep your __repr__ methods nice and neat:

class MyModel(db.Model):

    def __repr__(self):
        # easy to override, and it'll honor __repr__ in foreign relationships
        return self._repr(id=self.id,
                          user=self.user,
                          blah=self.blah)

Should produce something like:

<MyModel(id=1829,user=<User(id=21, email='[email protected]')>,blah='hi')>

like image 88
Stephen Fuhry Avatar answered Sep 22 '22 09:09

Stephen Fuhry