Flask-SQLAlchemy creating schema before creating tables - python

I am trying to configure a MySQL schema using Flask-SQLAlchemy. I have a schema called testdb and some tables. I will list one table, User.
This code, so far, creates all of the tables needed but only when testdb already exists. Is there a way to check and create testdb before I connect?
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:password#localhost/testdb'
db = SQLAlchemy(app)
class User(db.Model):
userid = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(16), unique=True, nullable=False)
password = db.Column(db.String(16), unique=False, nullable=False)
email = db.Column(db.String(80), unique=True, nullable=False)
createdDate = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
lastUpdated = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
db.create_all()
Desired command:
CREATE SCHEMA IF NOT EXISTS `testdb` ;

I solved this thanks to #hygorxaraujo
See the code below:
import sqlachemy
engine = sqlalchemy.create_engine('mysql://root:password#localhost') # connect to server
engine.execute("CREATE SCHEMA IF NOT EXISTS `testdb`;") #create db
engine.execute("USE testdb;") # select new db
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mypassword#localhost/testdb'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False #Turn off annoying message
db = SQLAlchemy(app)

Related

SQLalchemy creates Database, but not tables

I'm trying to connect my FastAPI project to 2 databases, one is gonna be local and the other one is located in an IP address. I think I managed to connect to both. However, when I try to create the local db, I get the file of the file, but is not pulling the models that I created for that db.
my code for database.py is the following:
SQLALCHEMY_DATABASE_URL = "credentials and address"
AUTH_DATABASE_URL = "sqlite:///./users.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
engine2 = create_engine(AUTH_DATABASE_URL, connect_args={
"check_same_thread": False})
Base = declarative_base()
BaseB = declarative_base()
SessionLocal = sessionmaker(autocommit=False, autoflush=False)
SessionLocal.configure(binds={Base: engine, BaseB: engine2})
The models I created for that base are the following:
class User(BaseB):
__tablename__ = "users"
Id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True)
hashed_password = Column(String)
##Constraints##
leads = relationship("Lead", back_populates="owner")
def verify_password(self, password: str):
return hash.bcrypt.verify(password, self.hashed_password)
class Lead(BaseB):
__tablename__ = "leads"
Id = Column(Integer, primary_key=True, index=True)
owner_id = Column(Integer, ForeignKey("users.Id"))
first_name = Column(String, index=True)
last_name = Column(String, index=True)
email = Column(String, index=True)
company = Column(String, index=True, default="")
notes = Column(String, default="")
date_created = Column(String, default=datetime.utcnow)
date_last_update = Column(String, default=datetime.utcnow)
##Constraints##
owner = relationship("User", back_populates="leads")
Also, I created a services.py file, which I use to run the code to create the database. It's creating the users.db file, but when I try to open it, I don't get the tables I created:
from database import BaseB, engine2, SessionLocal
def create_database():
return BaseB.metadata.create_all(bind=engine2)
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
This is causing me problems, because I need to post data to the table users. However, when I try to do it, I get an error saying there is no such table created. I've tried even to run the code to generate the db automatically (without running services.py on python) but still I get the same error.
I would appreciate if someone can take a look at my code and check what I may be missing.
Thanks!!
Thank you!
I think I have figured out what was wrong. I post this solution in case anyone else might get trapped as I was. My error was that I wasn't importing the models, neither declaring it in the services.py route. I changed my code and now I can see the two tables when I create the database from python
from database import engine2, SessionLocal
import models
def create_database():
return models.BaseB.metadata.create_all(bind=engine2)
Hope it helps anyone having the same problem :)

Tables create using Flask-SQLAlchemy, but they are not shown on sqlite command line (shell)

I am developing a flask application using Flask-SQLAlchemy with the following structure files. When I create the database (db.sqlite3) and write on the sqlite command line sqlite> .tables , the table (columns name) creates into the db.py file is not shown in the shell. There isn't any messagge error. It's only the shell doesn't show anything when I write this command. I have been tried different options I don't know what to do anymore. How can I get the shell show the columns of the tables?
File Tree:
|-PROBATINAS_2 (proyect name)
|-probatina
|- __init__.py
|- db.py
|- db.sqlite3 (database)
|-venv
|- Include
|- Lib
|- Scripts
|-.env
|-app.py
|-config.py
The code written for these files is as follows:
init.py:
from flask import Flask
app = Flask(__name__, instance_relative_config=True)
app.config.from_object('config')
db.py:
from probatina import app
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime, timedelta
SQLALCHEMY_DATABASE_URI = app.config['SQLALCHEMY_DATABASE_URI']
SQLALCHEMY_TRACK_MODIFICATIONS = app.config['SQLALCHEMY_TRACK_MODIFICATIONS']
db = SQLAlchemy(app)
db.create_all()
#db.init_app(app)
class Customer(db.Model):
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(50), nullable=False)
last_name = db.Column(db.String(50), nullable=False)
address = db.Column(db.String(500), nullable=False)
city = db.Column(db.String(50), nullable=False)
postcode = db.Column(db.String(50), nullable=False)
email = db.Column(db.String(50), nullable=False, unique=True)
orders = db.relationship('Order', backref='customer')
order_product = db.Table('order_product',
db.Column('order_id', db.Integer, db.ForeignKey('order.id'), primary_key=True),
db.Column('product_id', db.Integer, db.ForeignKey('product.id'), primary_key=True)
)
class Order(db.Model):
id = db.Column(db.Integer, primary_key=True)
order_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
shipped_date = db.Column(db.DateTime)
delivered_date = db.Column(db.DateTime)
coupon_code = db.Column(db.String(50))
customer_id = db.Column(db.Integer, db.ForeignKey('customer.id'), nullable=False)
products = db.relationship('Product', secondary=order_product)
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False, unique=True)
price = db.Column(db.Integer, nullable=False)
.env:
FLASK_APP=app.py
FLASK_ENV=development
app.py:
from probatina import app
if __name__ == '__main__':
app()
config.py:
SQLALCHEMY_DATABASE_URI = 'sqlite:///C:/Users/ferna/Documents/Curso Aprender a programar desde cero/probatinas_2/probatina/db.sqlite3'
SQLALCHEMY_TRACK_MODIFICATIONS = False

How to add table to database?

I am trying to use this code to add a table to a database in a Flask app on localhost - but it does not work. What should I do?
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI']='postgresql://postgres:123#localhost:5432/postgres'
db = SQLAlchemy(app)
class Person(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(), nullable=False)
db.create_all()
I changed my app name from "flask-hello-app" to "app"
and typed these 3 commands in terminal:
python
from app import db
db.create_all()
and it worked for me.
db.session.commit()
Good luck.
I just try your code using both Postgres and MySQL
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://root:55665566#localhost:5432/test'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
# from yourapplication import db
db.create_all()
Since I have created the table successfully,
I suggest you check some details below
Check the role attribute for the account.
Check the connection to the database, using command \du to confirm your accounts info, suppose you need to create a user 'postgres' which should show up in the table above.

alembic autogenerate get the metadata for a Flask-SQLAlchemy bind

My flask application has a single database(db1) before, now I bind a new database(db2) to it, both has 10 tables.
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root#localhost:3306/db1'
SQLALCHEMY_BINDS = {
'test': 'mysql+pymysql://root#localhost:3306/db2'
}
db = SQLAlchemy()
class table1(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
.......
class table10(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
class table11(db.Model):
__bind_key__ = 'db2'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
......
class table20(db.Model):
__bind_key__ = 'db2'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
I want to use alembic autogenerate function to auto detecting and generating migrations for db 1 and db2 separately, but db.metadata will get all tables metadata, but how to just get bind db metadata?
Thanks #davidism help! I can use include_symbol to make it.
def include_symbol(tablename, schema):
return tablename in ('table1', 'table2'.......'table10') # for db1
 # return tablename not in ('table1', 'table2'.......'table10') # for db2
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
include_symbol=include_symbol
)
You can't because that feature doesn't exist yet. Currently, there is one metadata instance for all models across all binds. As long as all the models have unique names, this isn't a huge problem.
When we apply this patch and make a new release, each bind will have its own metadata. You will then be able to access it with db.get_metadata(bind='db2').

Migrate Flask models.py to MySQL

I'm new. Bear with me.
I'm developing a Flask application using SQLAlchemy as an ORM and up until today I have been using SQLite for convenience. I'm now putting the application live on Digital Ocean and want to use MySQL instead of SQLite.
I have MySQL installed on my ubuntu VPS on Digital Ocean and it seems like it is configured properly. However, obviously I have to create the database tables, so I can save the data inside.
Question: Is there a way for me to migrate my models.py, so the database tables are created from what I have written in models.py or do I have to create all the database tables myself manually in MySQL?
You can see the application live here: http://workflowforum.dk/ and I have made a small test to see if there is a database connection here: http://workflowforum.dk/testdb
Models.py (Only user model):
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.script import Manager
from flask.ext.migrate import Migrate, MigrateCommand
from datetime import datetime, date
from hashlib import md5
from bcrypt import hashpw, gensalt
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:password#localhost/database'
db = SQLAlchemy(app)
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
slug = db.Column(db.String(80))
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(80))
password = db.Column(db.String(80), unique=False)
admin = db.Column(db.Boolean(), default=False)
join_date = db.Column(db.DateTime)
last_seen = db.Column(db.DateTime)
topics = db.relationship('Topic')
posts = db.relationship('Post')
picture = db.Column(db.Boolean(), default=False)
title = db.Column(db.String(80))
company = db.Column(db.String(80))
summary = db.Column(db.String(80))
class Category(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), unique=True)
description = db.Column(db.String(180), unique=False)
topics = db.relationship('Topic', backref="category")
class Topic(db.Model):
id = db.Column(db.Integer, primary_key=True)
slug = db.Column(db.String(255), unique=True)
title = db.Column(db.String(80), unique=False)
description = db.Column(db.Text, unique=False)
pub_date = db.Column(db.DateTime)
last_update = db.Column(db.DateTime)
user_id = db.Column(db.String(80), db.ForeignKey('user.id'))
category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
views = db.Column(db.Integer, default=0)
locked = db.Column(db.Boolean(), default=False)
pinned = db.Column(db.Boolean(), default=False)
user = db.relationship('User')
posts = db.relationship('Post')
Views.py (Only database test):
#app.route('/testdb')
def testdb():
if db.session.query("1").from_statement("SELECT 1").all():
return 'It works.'
else:
return 'Something is broken.'
UPDATE after Lukas comment:
When trying to db.create_all() I get this traceback:
sqlalchemy.exc.OperationalError: (_mysql_exceptions.OperationalError) (1005, "Can't create table 'pwforum.topic' (errno: 150)") [SQL: u'\nCREATE TABLE topic (\n\tid INTEGER NOT NULL AUTO_INCREMENT, \n\tslug VARCHAR(255), \n\ttitle VARCHAR(80), \n\tdescription TEXT, \n\tpub_date DATETIME, \n\tlast_update DATETIME, \n\tuser_id VARCHAR(80), \n\tcategory_id INTEGER, \n\tviews INTEGER, \n\tlocked BOOL, \n\tpinned BOOL, \n\tPRIMARY KEY (id), \n\tUNIQUE (slug), \n\tFOREIGN KEY(user_id) REFERENCES user (id), \n\tFOREIGN KEY(category_id) REFERENCES category (id), \n\tCHECK (locked IN (0, 1)), \n\tCHECK (pinned IN (0, 1))\n)\n\n']
The db.create_all suggestion in the comments is usually what you do when you don't use a migration framework. But it looks like you are using Flask-Migrate as a database migration framework here. The problem with doing create_all is that your migration scripts are skipped, so any fixes that you need to make to convert your sqlite models to MySQL will not be reflected in the migration scripts.
My recommendation is that you create an empty MySQL database, configure it in your Flask app, and then generate the MySQL tables simply by calling:
$ ./manage.py db upgrade
When you do this, Flask-Migrate will start running the migration scripts one by one and in order.
If you get failures, that it is probably because some of your migration scripts have changes that are compatible with sqlite but not with MySQL. You will need to fix all these problems in your migration scripts, until you get all of them to run cleanly, at which point you will have a complete MySQL database to use in your application.

Categories