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()
Related
I have an existing model that I can't change, written in Flask-SQLAlchemy.
I'm writing another app that uses the same model, but without the need for Flask, therefore I'm working with the regular SQLAlchemy module.
Unfortunately, I'm getting a lot of:
'AttributeError: module 'DB' has no attribute 'Model'
for all kind of attributes - such as Column, Integer, etc
Is there a way to use Flask-SQLAlchemy with a regular SQLAlchemy app?
There is an example of one of my Model Class:
class Table_name(Model):
__tablename__ = 'table_name'
id = db.Column(db.INTEGER, primary_key=True)
field1 = db.Column(db.INTEGER, db.ForeignKey('table1.id'), nullable=False)
field2 = db.Column(db.TEXT, nullable=False)
field3 = db.Column(db.INTEGER, db.ForeignKey('table2.id'), nullable=False)
time = db.Column(db.TIMESTAMP, nullable=False)
Unfortunately I can't change them
I've had the same dilemma. If it's a small or one-off, you can hack in a Flask app object without really using it, like so:
from flask_sqlalchemy import SQLAlchemy
throw_away_app = Flask(__name__)
db = SQLAlchemy(throw_away_app)
with self.throw_away_app.app_context():
(perform your db operation)
That works relatively well for simple things like scripts. But if you're sharing a model across multiple projects and you simply cannot alter the existing Flask project, it's unfortunately probably not a good solution.
If that's the case, and you simply cannot alter the existing codebase at all, it probably makes sense to create a new model class and connect to the existing database using vanilla SQLAlchemy.
BTW, for any future programmers wondering how to get some of the benefits of Flask-SQLAlchemy without Flask, consider: sqlalchemy-mixins.
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, Text, TIMESTAMP, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
# connect in memory sqlite database or you can connect your own database
engine = create_engine('sqlite:///:memory:', echo=True)
# create session and bind engine
Session = sessionmaker(bind=engine)
class Table_name(Base):
__tablename__ = 'table_name'
id = Column(Integer, primary_key=True)
field1 = Column(Integer, ForeignKey('table1.id'), nullable=False)
field2 = Column(Text, nullable=False)
field3 = Column(Integer, ForeignKey('table2.id'), nullable=False)
time = Column(TIMESTAMP, nullable=False)
table = Table_name(field1=1, fi....)
session.add(table)
Now you can use your ORM as usual like flask-sqlalchemy .
Docs: https://docs.sqlalchemy.org/en/13/orm/tutorial.html
I'm working on a flask application where I'm trying to isolate my unit tests. I'm using flask-sqlalchemy, and I'm trying to use the create_all and drop_all methods to clean my database after running a test.
However, it appears my create_all and drop_all methods do not actually create/drop the tables as the documentation states. I have my models imported in the application before calling create_all, like most other answers say.
This is the error I'm getting with the code below:
psycopg2.ProgrammingError: relation "tasks" does not exist
Here's my relevant code
/app.py
import os
import configparser
from flask import Flask
from src.router import router
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
if not os.path.exists(os.path.join(app.root_path, 'config.ini')):
raise Exception(f'config.ini not found in the {app.root_path}')
config = configparser.ConfigParser()
config.read('config.ini')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = config[os.environ['APP_ENV']]['DATABASE_URI']
app.register_blueprint(router)
db = SQLAlchemy(app)
migrate = Migrate(app, db)
if __name__ == "__main__":
app.run()
/tests/test_router.py
from unittest import TestCase
from flask import Flask
from app import app, db
from src.models import Task
class TestRouter(TestCase):
def setUp(self):
db.create_all()
def tearDown(self):
db.drop_all()
def test_adds_task(self):
task = Task(task_id='task_1', name='my task')
db.session.add(task)
db.session.commit()
I think I was a little quick to post the question, but I hope this might help others come up with other ideas on how to troubleshoot a similar issue.
In my src/models.py file where I keep my models, you must make sure that your models are defined correctly. Since Flask-SQLAlchemy is a wrapper around the SQLAlchemy you must use the data types under the db object.
Essentially, I had my models defined as such:
class Task(db.Model):
__tablename__ = 'tasks'
id = Column(Integer, primary_key=True)
task_id = Column(String)
name = Column(String)
created_at = Column(DateTime, default=datetime.datetime.now)
As you can see, I was inheriting from db.Model instead of the return value of declarative_base(). I also needed to add the db. in front of all the data types, including Column, Integer, String, Float, DateTime, relationship, and ForeignKey.
So, I was able to fix my issue by changing my model to something like:
class Task(db.Model):
__tablename__ = 'tasks'
id = db.Column(db.Integer, primary_key=True)
task_id = db.Column(db.String)
name = db.Column(db.String)
created_at = db.Column(db.DateTime, default=datetime.datetime.now)
See: Documentation on declaring Flask-SQLAlchemy models
i'm using sqlalchemy + alembic + Flask and i can't map circular classes.
apps/users/models.py:
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
email = Column(String)
password = Column(String)
session = relationship("Session", back_populates='user', cascade='all,delete', lazy='dynamic')
notes = relationship('Note2User', back_populates='user', cascade='all,delete', lazy='dynamic')
apps/notes/models.py:
class Note2User(Base):
__tablename__ = 'notes_users_m2m'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.id', ondelete='CASCADE'), nullable=False)
user = relationship('User', back_populates='notes')
note_id = Column(Integer, ForeignKey('notes.id', ondelete='CASCADE'), nullable=False)
note = relationship('Note', back_populates='users')
Table Note2User made for m2m relationship User <-> Notes, but when i start app and done some request, gets error:
InvalidRequestError: When initializing mapper Mapper|User|users,
expression 'Note2User' failed to locate a name ("name 'Note2User' is
not defined"). If this is a class name, consider adding this
relationship() to the class after
both dependent classes have been defined.
Initializing db in db/init.py: (dunder name)
from sqlalchemy import create_engine, MetaData
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session
engine = create_engine('postgresql+psycopg2://server:12345#localhost:5432/test')
Base = declarative_base()
meta = MetaData()
meta.reflect(bind=engine)
db_session = Session(bind=engine)
Add an import for Note2User class in apps/users/models.py file so this model gets defined first before initializing that relatioship in User class which refrences it.
like this
# file: apps/users/models.py
from ..notes.models import Note2User
You need to import the user.models module into the notes.model module and vice versa. It would look something like this:
# file app/users/models.py
import app.notes.models as notes
# use it like this
notes.Notes2User()
# file app/notes/models.py
import app.users.models as users
users.User()
The advantage to this is that you will avoid circular dependency problems as your program inevitably grows. I had so many problems with circular dependencies when I was creating an app with your same stack. The only solution was to ditch the
from . import Foo
and only use
import bar.foo as foo
It is considered best practice to use the import syntax for this reason.
Reference.
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.
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.