Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 847
Esteban Küber Avatar asked Sep 21 '09 07:09

Esteban Küber


People also ask

What is declarative in SQLAlchemy?

The Declarative system is the typically used system provided by the SQLAlchemy ORM in order to define classes mapped to relational database tables. However, as noted in Classical Mappings, Declarative is in fact a series of extensions that ride on top of the SQLAlchemy mapper() construct.

What is mapper in SQLAlchemy?

Declarative MappingThe Declarative Mapping is the typical way that mappings are constructed in modern SQLAlchemy. The most common pattern is to first construct a base class using the declarative_base() function, which will apply the declarative mapping process to all subclasses that derive from it.

What is SQLAlchemy ext declarative?

function sqlalchemy.ext.declarative. has_inherited_table(cls) Given a class, return True if any of the classes it inherits from has a mapped table, otherwise return False. This is used in declarative mixins to build attributes that behave differently for the base class vs. a subclass in an inheritance hierarchy.

Should I use SQLAlchemy core or ORM?

If you want to view your data in a more schema-centric view (as used in SQL), use Core. If you have data for which business objects are not needed, use Core. If you view your data as business objects, use ORM. If you are building a quick prototype, use ORM.


2 Answers

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

Can't be answered in general.

However, consider this.

The Django ORM is strictly declarative -- and people like that.

SQLAlchemy does several things, not all of which are relevant to all problems.

  1. SQLAlchemy creates DB-specific SQL from general purpose Python. If you want to mess with the SQL, or map Python classes to existing tables, then you have to use explicit mappings, because your focus is on the SQL, not the business objects and the ORM.

  2. SQLAlchemy can use declarative style (like Django) to create everything for you. If you want this, then you are giving up explicitly writing table definitions and explicitly messing with the SQL.

  3. Elixir is an alternative to save you having to look at SQL.

The fundamental question is "Do you want to see and touch the SQL?"

If you think that touching the SQL makes things more "maintainable", then you have to use explicit mappings.

If you think that concealing the SQL makes things more "maintainable", then you have to use declarative style.

  • If you think Elixir might diverge from SQLAlchemy, or fail to live up to it's promise in some way, then don't use it.

  • If you think Elixir will help you, then use it.

like image 179
S.Lott Avatar answered Oct 07 '22 07:10

S.Lott


In our team we settled on declarative syntax.

Rationale:

  • metadata is trivial to get to, if needed: User.metadata.
  • Your User class, by virtue of subclassing Base, has a nice ctor that takes kwargs for all fields. Useful for testing and otherwise. E.g.: user=User(name='doe', password='42'). So no need to write a ctor!
  • If you add an attribute/column, you only need to do it once. "Don't Repeat Yourself" is a nice principle.

Regarding "keeping out ORM from business view": in reality your User class, defined in a "normal" way, gets seriously monkey-patched by SA when mapper function has its way with it. IMHO, declarative way is more honest because it screams: "this class is used in ORM scenarios, and may not be treated just as you would treat your simple non-ORM objects".

like image 29
Pavel Repin Avatar answered Oct 07 '22 06:10

Pavel Repin