Should I create mapper objects or use the declarative syntax in SQLAlchemy?

Viewed 9959

There are two (three, but I'm not counting Elixir, as its not "official") ways to define a persisting object with SQLAlchemy:

Explicit syntax for mapper objects

from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
from sqlalchemy.orm import mapper

metadata = MetaData()

users_table = Table('users', metadata,
    Column('id', Integer, primary_key=True),
    Column('name', String),
)

class User(object):
    def __init__(self, name):
        self.name = name

    def __repr__(self):
       return "<User('%s')>" % (self.name)

mapper(User, users_table) # &lt;Mapper at 0x...; User&gt;

Declarative syntax

from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

class User(Base):
     __tablename__ = 'users'
     id = Column(Integer, primary_key=True)
     name = Column(String)

     def __init__(self, name):
         self.name = name

     def __repr__(self):
         return "<User('%s')>" % (self.name)

I can see that while using the mapper objects, I separate completely the ORM definition from the business logic, while using the declarative syntax, whenever I modify the business logic class, I can edit right there the database class (which ideally should be edited little).

What I'm not completely sure, is which approach is more maintainable for a business application?

I haven't been able to find a comparative between the two mapping methods, to be able to decide which one is a better fit for my project.

I'm leaning towards using the "normal" way (i.e. not the declarative extension) as it allows me to "hide", and keep out of the business view all the ORM logic, but I'd like to hear compelling arguments for both approaches.

4 Answers

as of current (2019), many years later, sqlalchemy v1.3 allows a hybrid approach with the best of both worlds

https://docs.sqlalchemy.org/en/13/orm/extensions/declarative/table_config.html#using-a-hybrid-approach-with-table

metadata = MetaData()

users_table = Table('users', metadata,
  Column('id', Integer, primary_key=True),
  Column('name', String),
)

# possibly in a different file/place the orm-declaration
Base = declarative_base(metadata)

class User(Base):
  __table__ = Base.metadata.tables['users']
  def __str__(): 
    return "<User('%s')>" % (self.name)
Related