How do I add functions to auto-mapped SqlAlchemy classes? - python

I was wondering if it is possible to use SqlAlchemy's automap_base() in the following way:
from sqlalchemy.ext.automap import automap_base
from sqlalchemy import create_engine
# automap base
Base = automap_base()
# pre-declare User for the 'user' table
class User(Base):
__tablename__ = 'user'
def __str__(self):
return self.name
def greet(self):
return 'Hello {}!'.format(self.name)
def add_address(self, address):
'''Utilizes the auto reflected relationship to add
a new address with a proper user_id to table "addresses"'''
self.address_collection.append(address)
# reflect
engine = create_engine("sqlite:///mydatabase.db")
# only to generate attributes and relationships
Base.prepare(engine, reflect=True)
So I would like to reflect the data and the relationships from the database, but extend the auto-generated class with additional functionality. Is it possible?

Related

How to create a single table using SqlAlchemy declarative_base

To create the User table I have to use drop_all and then create_all methods. But these two functions re-initiate an entire database. I wonder if there is a way to create the User table without erasing (or dropping) any existing tables in a database?
import sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
name = sqlalchemy.Column(sqlalchemy.String)
def __init__(self, code=None, *args, **kwargs):
self.name = name
url = 'postgresql+psycopg2://user:pass#01.02.03.04/my_db'
engine = sqlalchemy.create_engine(url)
session = sqlalchemy.orm.scoped_session(sqlalchemy.orm.sessionmaker())
session.configure(bind=engine, autoflush=False, expire_on_commit=False)
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
You can create/drop individual tables:
User.__table__.drop(engine)
User.__table__.create(engine)
from app import db
from models import User
User.__table__.create(db.engine)
User.__table__.drop(db.engine)
Another way to accomplish the task:
Base.metadata.tables['users'].create(engine)
Base.metadata.tables['users'].drop(engine)

How to query with raw SQL using Session or engine

With Parent and Child tables:
from sqlalchemy import Column, ForeignKey, String, create_engine, desc, asc
from sqlalchemy.ext.declarative import declarative_base
import uuid
Base = declarative_base()
class Parent(Base):
__tablename__ = 'parents'
uuid = Column(String(64), primary_key=True, unique=True)
def __init__(self):
self.uuid = uuid.uuid4()
class Child(Base):
__tablename__ = 'children'
uuid = Column(String(64), primary_key=True, unique=True)
parent_uuid = Column(String(64), ForeignKey('parents.uuid'))
def __init__(self, parent_uuid=None):
self.uuid = uuid.uuid4()
self.parent_uuid = parent_uuid
I can go ahead and create a Parent entity:
engine = create_engine('mysql://root:pass#localhost/dbname', echo=False)
session = scoped_session(sessionmaker())
session.remove()
session.configure(bind=engine, autoflush=False, expire_on_commit=False)
parent = Parent()
session.add(parent)
session.commit()
session.close()
The resulting parent variable is a regular Python ORM object.
If I would query a database instead of creating one the result of query would be a list of ORM objects:
result = session.query(Parent).order_by(desc(Parent.uuid)).all()
But there are times when we need to query database using a raw Sql command.
Is there a way to run a raw SQL command using session object so to ensure that the resulting query return is a ORM object or a list of objects?
You can use the execute() method of Session:
session.execute('select * from table')
The execute method's documentation can be found here:
http://docs.sqlalchemy.org/en/latest/orm/session_api.html#sqlalchemy.orm.session.Session.execute
Please note this does not protect against SQL Injection.
With SQLAlchemey 1.4/2.0, you need to wrap the SQL string in an Executable.
from sqlalchemy import text
session.execute(text("select * from table"))

What is the difference between the declarative_base() and db.Model?

The quickstart tutorial for the Flask-SQLAlchemy plugin instructs users to create table models inheriting the db.Model class, e.g.
app = Flask(__main__)
db = SQLAlchemy(app)
class Users(db.Model):
__tablename__ = 'users'
...
However, the SQLAlchemy tutorial and the bottle-SQLAlchemy README both suggest that table models inherit a Base instantiated from declarative_base().
Base = declarative_base()
class Users(Base):
__tablename__ = 'users'
...
What is the difference between these two approaches?
Looking in the Flask-SQLAlchemy source code the db.Model class is initialized as follows:
self.Model = self.make_declarative_base()
And here is the make_declarative_base() method:
def make_declarative_base(self):
"""Creates the declarative base."""
base = declarative_base(cls=Model, name='Model',
metaclass=_BoundDeclarativeMeta)
base.query = _QueryProperty(self)
return base
The _BoundDeclarativeMeta metaclass is a subclass of SQLAlchemy's DeclarativeMeta, it simply adds support for computing a default value for __tablename__ (the table name) and also to handle binds.
The base.query property enables Flask-SQLAlchemy based models to access a query object as Model.query instead of SQLAlchemy's session.query(Model).
The _QueryProperty query class is also subclassed from SQLAlchemy's query. The Flask-SQLAlchemy subclass adds three additional query methods that do not exist in SQLAlchemy: get_or_404(), first_or_404() and paginate().
I believe these are the only differences.

How to inherit the declarative in SQLAlchemy without setting the __tablename__?

Using flask-sqlalchemy, I want to create some class to inherit the declarative class and add the __bind_key__. So that I can create some tables and inherit these binded class.
from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Model1(db.Model):
__bind_key__ = 'db2'
class Table1(Model1):
__tablename__ = 'table1'
name = db.Column(db.String(100))
But I got some troubles:
sqlalchemy.exc.InvalidRequestError: Class <class '__main__.Model1'>
does not have a __table__ or __tablename__ specified
and does not inherit from an existing table-mapped class.
How could I solve it?
You can also use the __abstract__ flag:
from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Model1(db.Model):
__abstract__ = True
__bind_key__ = 'db2'
class Table1(Model1):
__tablename__ = 'table1'
name = db.Column(db.String(100))
Classes with __abstract__ set to True are ignored by SQLAlchemy declarative (docs here). As a bonus, this enables you to add SQLAlchemy specific attributes (for example columns) to your Model1.

sqlalchemy REST serialization

Reading the doc of sqlalchemy, i saw the serialization part.
I'm wondering about a possibility to use an xml serializer for matching sa models with Rest webservices like Jax-RS
There is a django extension which deal with that : django_roa
Do you know if that kind of thing has already been developped for sqlalchemy or if is it possible to do it??
Thanks
Its a long way till full RFC2616 compliance, but for a prototype, I do something like this:
from sqlalchemy import create_engine, Table, Column, Integer, String, ForeignKey, UniqueConstraint
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relation, backref, sessionmaker
from sqlalchemy.sql.expression import desc
import web
import json
DB_PATH = 'sqlite:////tmp/test.db'
Base = declarative_base()
class LocalClient(Base):
__tablename__ = 'local_clients'
__jsonexport__ = ['id', 'name', 'password']
id = Column(Integer, primary_key=True)
name = Column(String, unique=True, nullable=False)
password = Column(String)
def __init__(self, name, password):
self.name = name
self.password = password
def __repr__(self):
return "<LocalClient('%s', '%s')>" % (self.name, self.password)
urls = (
'/a/LocalClient', 'LocalClientsController'
)
class Encoder(json.JSONEncoder):
'''This class contains the JSON serializer function for user defined types'''
def default(self, obj):
'''This function uses the __jsonexport__ list of relevant attributes to serialize the objects that inherits Base'''
if isinstance(obj, Base):
return dict(zip(obj.__jsonexport__, [getattr(obj, v) for v in obj.__jsonexport__]))
return json.JSONEncoder.default(self, obj)
class LocalClientsController:
'''The generic RESTful Local Clients Controller'''
def GET(self):
'''Returns a JSON list of LocalClients'''
engine = create_engine(DB_PATH, echo=False)
Session = sessionmaker(bind=engine)
session = Session()
clis = session.query(LocalClient)
return json.dumps([c for c in clis], cls=Encoder)
sqlalchemy.ext.serializer exists to support pickling (with pickle module) of queries, expressions and other internal SQLAlchemy objects, it doesn't deal with model objects. In no way it will help you to serialize model objects to XML. Probably something like pyxser will be useful for you.

Categories

Resources