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'
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