Using same name of tables with different binds in Flask - python

I have two tables sharing the same name but located in different databases:
class Lcn(db.Model):
__tablename__ = 'lcn'
class LcnRemote(db.Model):
__bind_key__ = 'remote'
__tablename__ = 'lcn'
It seems SQLAlchemy doesn't like that. It says:
sqlalchemy.exc.InvalidRequestError: Table 'lcn' is already defined for this MetaData instance. Specify 'extend_existing=True' to redefine options and columns on an existing Table object.
Is there a way to solve this without having to rename one of my tables?

Use separate declarative base classes for different databases with the same name, to prevent sharing of SQLAlchemy metadata. You'll have to create two flask_sqlalchemy.SQLAlchemy() instances:
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/database1.db'
app.config['SQLALCHEMY_BINDS'] = {'remote': 'sqlite:////tmp/database1.db'}
db1 = SQLAlchemy(app)
class Lcn(db1.Model):
__tablename__ = 'lcn'
db2 = SQLAlchemy(app)
class LcnRemote(db2.Model):
__bind_key__ = 'remote'
__tablename__ = 'lcn'
This is a limitation of Flask-SQLAlchemy, it really should allow you to create declarative bases per bind. The way the SQLAlchemy() class currently is designed limits it to just one such base; it proxies various SQLAlchemy metadata calls through the db.Model class it generates at the start. By creating two instances of flask_sqlalchemy.SQLAlchemy() you work around this issue.

Related

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

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?

Flask-Sqlalchemy multiple databases (binds) with the same model (class DB.Model)

I'm a beginner with python/Flask/SQLAlchemy so sorry if my questions are dumb.
I want to create an API with Flask using Flask-SQLAlchemy as following:
one sqlite database for users/passwords
SQLALCHEMY_DATABASE_URI = 'sqlite:////path/to/users.db'
class User(DB.Model):
__tablename__ = 'users'
id = DB.Column(DB.Integer, primary_key=True)
username = DB.Column(DB.String(64), index=True)
password = DB.Column(DB.String(128))
Lets say I have multiple "customers" witch a user can create using
$ http POST http://localhost:5000/api/customers/ name=customer1
class Customer(DB.Model):
__tablename__ = 'customer'
customer_id = DB.Column(DB.Integer, primary_key=True)
customer_name = DB.Column(DB.String, unique=True, index=True)
I need to create a separate sqlite file for each "customers" :
SQLALCHEMY_BINDS = {
'customer1' = 'sqlite:////path/customer1.db',
'customer2' = 'sqlite:////path/customer2.db',
...
}
My questions are:
I do not have fixed number of "customers" so I cannot create a model class for each and specify the "bind_key" for each. Is it possible to do this with Flask-SQLAlchemy or I need to use plain SQLAlchemy?
I have 3 "customers" in data/ as customer1.db, customer2.db and customer3.db.
I would start the application and create SQLALCHEMY_BINDS dictionary listing the files in data/ and then DB.create_all() on a request for a specific "customer" .
how can I bind to the right .db file using the Flask-SQLAlchemy
DB.session?
I've read Using different binds in the same class in Flask-SQLAlchemy
Why exactly do you want entirely separate DB files for each customer?
In any case this is easier with straight SQLAlchemy. You can create a getter function which returns a session pointing to your db file.
def get_session(customer_id):
sqlite_url = 'sqlite:////path/customer%s.db' % customer_id
engine = create_engine(sqlite_url)
# initialize the db if it hasn't yet been initialized
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
return session
You can then use and close that session.
But without knowing your specific use case, it is difficult to understand why you would want to do this instead of just using a single SQLite database.

How to choose database binds in flask-sqlalchemy

I have two database binds in Flask - 'default' and 'sus'. I used bind_key in Model, it worked OK.
class Person(db.Model):
__tablename__ = 'persons'
__bind_key__ = 'sus'
id = Column(Integer, primary_key=True)
name = Column(Unicode)
Person.query.get(5)
But now i need to execute that from 'sus' bind:
from flask.ext.sqlalchemy import SQLAlchemy
from sqlalchemy import func
db = SQLAlchemy(app)
db.session.query(func.do_something(some_params)).first()
db.session.commit()
And i have got the 'default' bind, not 'sus'. What should i do?
Your db.session query is not using the Person model at all, so it doesn't know anything about the __bind_key__
Try to refactor your query so you can use Person.query.filter(...).first()

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.

Categories

Resources