0

I was wondering whether it is possible (and good practice) to implement a default SQLAlchemy Model class that provides basic CRUD functionality to its subclasses. I would like to use this base class in order to avoid code duplication amongst different database models.

An example for such functionality would be creating (and saving) an instance of the corresponding model in the DB. I am aware that such methods should only be used for non-interdependent transactions in order to comply with the atomicity principle. Is there any built-in mechanism or workaround for doing this?

Here is an example that obviously does not work (its only purpose is to get the idea across):

import flask
import flask_sqlalchemy
import sqlalchemy
from flask import Flask
from flask_sqlalchemy import SQLAlchemy


app = Flask(__name__)

# app.config['SQLALCHEMY_DATABASE_URI'] = ...
db = SQLAlchemy(app)

class DefaultModel(db.Model):
    def create(self, **attributes):
        try:
            # should be considered pseudocode
            instance = self._init_(attributes) 
            db.session.add(instance)
            db.session.commit()
            return instance
        except sqlalchemy.exc.SQLAlchemyError:
            db.session.rollback()
            return None

class MyModel(DefaultModel):
    __tablename__ =  'mytable'

    id = db.Column(db.BigInteger(), primary_key=True)
    # ...

The following Exception is raised since there is no primary key attribute definition in the DefaultModel class:

sqlalchemy.exc.ArgumentError: Mapper Mapper|DefaultModel|default_model could not          assemble any primary key columns for mapped table 'default_model'
Jerry
  • 23
  • 5
  • In general I'd recommend against this since it does not play well with how the session is usually used, as you've noted yourself. But if you must, then what you're looking for is an [abstract Base class or a mixin](http://docs.sqlalchemy.org/en/latest/orm/extensions/declarative/mixins.html). – Ilja Everilä Oct 26 '17 at 08:18
  • Possible duplicate of [Sqlalchemy: avoiding multiple inheritance and having abstract base class](https://stackoverflow.com/questions/9606551/sqlalchemy-avoiding-multiple-inheritance-and-having-abstract-base-class), [How do I declare a base model class in Flask-SQLAlchemy?](https://stackoverflow.com/questions/22976445/how-do-i-declare-a-base-model-class-in-flask-sqlalchemy) – Ilja Everilä Oct 26 '17 at 08:30
  • @llja Everilä: Many thanks! The `__abstract__` directive solves the problem! – Jerry Oct 27 '17 at 15:05

1 Answers1

0

Thanks to the hints @llja Everilä gave me I came up with this simple solution:

class DefaultModel(db.Model):
    __abstract__ = True

    def __init__(self, persist=False, **kvargs):
        super(DefaultModel, self).__init__(**kvargs)
        try:
            if persist:
                db.session.add(self)
                db.session.commit()
        except sqlalchemy.exc.SQLAlchemyError as error:
            db.session.rollback()
            raise error
Jerry
  • 23
  • 5