A quick tip,
If you want your data models to autoload their contents as you create them, you can use the following idiom:
I generally use three python modules in my database related (thus using SQLAlchemy) applications, one for the declarative Base (declarative.py), one for the database url, session, query and engine (db.py) and a last one for the models (models.py).
In the declarative.py:
In the db.py:
Setting up the database becomes db.setup(), easy enough.
In the model.py:
In the above example the __init__ method is unnecessarily included to show how to skip the __init__ when there is an instance retrieved from the database.
The key in the above example is the usage of __new__ and using the super to hand the class creation to Type as shown above, this will trigger __init__. We can not just return because the class will not be initialized and we should skip the __init__ for instances returned from the database.
So by using this idiom, you should be able to restore an instance without querying it:
Thats all, easy and smooth...
Edit: Now I need to note that SQLAlchemy also uses __new__ to create new instances, but we prevent it doing another query again inside __new__ by checking the name argument, which is not used by SQLAlchemy when restoring from database.
If you want your data models to autoload their contents as you create them, you can use the following idiom:
I generally use three python modules in my database related (thus using SQLAlchemy) applications, one for the declarative Base (declarative.py), one for the database url, session, query and engine (db.py) and a last one for the models (models.py).
In the declarative.py:
from sqlalchemy.ext.declarative import declarative_base Base = declarative_base()
In the db.py:
from declarative import Base engine = None session = None query = None metadata = Base.metadata database_url = None def setup(url="sqlite:///:memory:"): global engine global session global query global metadata global database_url # to let my models to register them selfs # and fill the Base.metadata import models database_url = url engine = sqlalchemy.create_engine(database_url, echo=False) # create the tables metadata.create_all(engine) # create the Session class Session = sqlalchemy.orm.sessionmaker(bind=engine) # create and save session object to session session = Session() query = session.query return session
Setting up the database becomes db.setup(), easy enough.
In the model.py:
import db from declarative import Base class MyClass(Base): __tablename__ = "MyClasses" id = Column(Integer, primary_key=True) name = Column(String(256), unique=True, nullable=False) description = Column(String) def __new__(cls, name): if name: # get the instance from the db if db.session is None: # create the session first db.setup() obj_db = db.query(MyClass).\ filter_by(name=name).first() if obj_db is not None: # return the database instance # skip the __init__ obj_db.__skip_init__ = None return obj_db # if we are here, # it means that there is no instance # in the database with the given name # so just create one normally # And SQLAlchemy queries will use this part return super(MyClass, cls).__new__(cls, name) def __init__(self, name): # do not initialize if it is created from the DB if hasattr(self, "__skip_init__"): return self.name = name
In the above example the __init__ method is unnecessarily included to show how to skip the __init__ when there is an instance retrieved from the database.
The key in the above example is the usage of __new__ and using the super to hand the class creation to Type as shown above, this will trigger __init__. We can not just return because the class will not be initialized and we should skip the __init__ for instances returned from the database.
So by using this idiom, you should be able to restore an instance without querying it:
from model import MyClass import db db.setup() myC1 = MyClass(name="Test") myC1.description = "To show the instance retrieved correctly" db.session.add(myC1) db.session.commit() myC2 = MyClass(name="Test") print myC2.description # this should print: # To show the instance retrieved correctly
Thats all, easy and smooth...
Edit: Now I need to note that SQLAlchemy also uses __new__ to create new instances, but we prevent it doing another query again inside __new__ by checking the name argument, which is not used by SQLAlchemy when restoring from database.
Comments