Creating database via flask in postgreSQL - python

I m trying a tutorial, to make a database connection with flask, and postgreSQL database using json.
This is the code lines in models.py
from app import db
from sqlalchemy.dialects.postgresql import JSON
class Result(db.Model):
_tablename_= 'results'
id =db.Column(db.Integer, primary_key=True)
url = db.Column(db.String())
result_all = db.Column(JSON)
result_no_stop_words = db.Column(JSON)
def __init__(self, url, result_all, result_no_stop_words):
self.url = url
self.result_all = result_all
self.result_no_stop_words = result_no_stop_words
def __repr__(self):
return '<id {}>'.format(self.id)
Code in config.py
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config(object):
DEBUG = False
TESTING = False
CSRF_ENABLED = True
SECRET_KEY = 'this-really-needs-to-be-changed'
SQLALCHEMY_DATABASE_URI = os.environ['postgresql://postgresql:bat123#localhost/DatabaseFirst']
class ProductionConfig(Config):
DEBUG = False
class StagingConfig(Config):
DEVELOPMENT = True
DEBUG = True
class DevelopmentConfig(Config):
DEVELOPMENT = True
DEBUG = True
class TestingConfig(Config):
TESTING = True
Code in manage.py
import os
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from app import app, db
app.config.from_object(os.environ['APP_SETTINGS'])
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
code in app.py
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
import os
app = Flask(__name__)
app.config.from_object(os.environ['APP_SETTINGS'])
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
from models import Result
#app.route('/')
def hello():
return "Hello World!"
#app.route('/<name>')
def hello_name(name):
return "Hello {}!".format(name)
if __name__ == "__main__":
app.run()
I want to know before running this code lines should the database be created in postgreSQL, alone with the table, and columns,
Or these code lines creating the table, and columns in postgreSQL
class Result(db.Model):
_tablename_= 'results'
id =db.Column(db.Integer, primary_key=True)
url = db.Column(db.String())
result_all = db.Column(JSON)
result_no_stop_words = db.Column(JSON)
Basically i want to know the function or purpose served by the above set of code lines.(5 code lines)

manager.add_command('db', MigrateCommand) this piece adds a command called db so that you can run flask db which will create the tables and columns.
Note: inorder to use this command first you need to define FLASK_APP in the environment variables.
Eg:
export FLASK_APP=app.py
flask db
Also the model
class Result(db.Model): _tablename_= 'results' id =db.Column(db.Integer, primary_key=True) url = db.Column(db.String()) result_all = db.Column(JSON) result_no_stop_words = db.Column(JSON)
This defines the class representation of the table. It won't create table in database, it's just the representation. The MigrationCommand is responsible for the creation of tables in database.

class Result(db.Model):
__tablename__ = 'results'
id =db.Column(db.Integer, primary_key=True)
class Result(db.Model):
This code line is creating a class instance of Result in front end of Flask application and to pass those values to the Database postgreSQL or whatever respective database you will be using.
__tablename__ = 'results':
Here we are creating a table called results in the database in my case DatabaseFirst
id = db.Column(db.Integer, primary_key=True):
Here we are creating a column called id, in our table called results, which can hold only data of integer type and id column is assigned the primary key of the results table.
Here by the 3 code lines I mentioned above, the database tables and columns are created via the Flask application, and we can see the respective results on postgreSQL database.

Related

db.create_all() not generating db

I'm trying to test Flask with SQLAlchemy and I stumbeld accross this problem. First, I have to note that I read all of the related threads and none of them solves my problem. I have a problem that db.create_all() doesn't generate the table I defined. I have model class in file person.py:
from website import db
class Person(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String, nullable=False)
password = db.Column(db.String)
width = db.Column(db.Integer)
height = db.Column(db.Integer)
agent = db.Column(db.String)
user_data_dir = db.Column(db.String)
And in my website.py which is the file from where I launch the app:
from flask import Flask, jsonify, render_template, request
from flask_sqlalchemy import SQLAlchemy
# create the extension
db = SQLAlchemy()
def start_server(host, port, debug=False):
from person import Person
# create the app
app = Flask(__name__,
static_url_path='',
static_folder='web/static',
template_folder='web/templates')
# configure the SQLite database, relative to the app instance folder
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///database0.db"
# initialize the app with the extension
db.init_app(app)
print('initialized db')
print('creating tables...')
with app.app_context():
db.create_all()
db.session.add(Person(username="example33"))
db.session.commit()
person = db.session.execute(db.select(Person)).scalar()
print('persons')
print(person.username)
if __name__ == '__main__':
start_server(host='0.0.0.0', port=5002, debug=True)
I think the problem might be that the Person class is not importing properly, because when I put the class inside the start_server function it executes fine and creates the table, but I don't know why this is happening. I followed all the advice and imported it before everything, and also I share the same db object between the 2 files
There is probably a better way to do this but this is the only way I could get this to work. You need to create a models.py file or w.e you wanna call it. Then all your database stuff goes in there. The db engine, ALL your models and a function to initialize it all. The reason is, you are having import issues where Person is imported but not fully and so the db doesn't have it in its metadata.
models.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Person(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String, nullable=False)
password = db.Column(db.String)
width = db.Column(db.Integer)
height = db.Column(db.Integer)
agent = db.Column(db.String)
user_data_dir = db.Column(db.String)
# All other models
def initialize_db(app: Flask):
db.init_app(app)
with app.app_context():
db.create_all()
main.py
from flask import Flask
import models
def start_server(host, port, debug=False):
app = Flask(__name__)
# configure the SQLite database, relative to the app instance folder
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///database0.db"
# initialize the app with the extension
models.initialize_db(app)
db = models.db
with app.app_context():
db.session.add(models.Person(username="example33"))
db.session.commit()
person = db.session.execute(db.select(models.Person)).scalar()
print('persons')
print(person.username)
if __name__ == '__main__':
start_server(host='0.0.0.0', port=5002, debug=True)
I am reading the documentation,
which explains that the function will
Create all tables stored in this metadata.
That leads me to believe Person is not associated with the db metadata.
You mentioned
when I put the class inside the start_server function it ... creates the table
Your from person import Person is nice enough,
but I suspect we wanted a simple import person.
In many apps the idiom would be import models.
Failing that, you may be able to point
create_all in the right direction
with this optional parameter:
tables – Optional list of Table objects, which is a subset of the total tables in the MetaData
Please let us know
what technical approach worked for you.

Flask_SQLAlchemy modularization issues due ORM

I am trying to build an API using Flask. For database actions I use flask_sqlalchemy.
In my main file, the flask app is initalized. I pass the resulting instance to another file where the configuration is set and to my database module that handles database operations.
main.py:
app = flask.Flask(__name__) # initialize flask app
#initialize modules with app
config.init(app)
database.init(app)
The problem is, the relations I use in the database are in a seperate file and it needs the db object to declare the classes for ORM.
My idea was to declare db and initialize it later in an init function, but that doesn't work in this case, because the db object is undefined when the pythonfile is loaded by an import.
relations.py
db: SQLAlchemy
def init(db):
Relations.db = db
class Series(db.Model):
"""Representation of a series
"""
id = db.Column(db.String(255), primary_key=True)
title = db.Column(db.String(255))
class User(db.Model):
"""Representation of a user
"""
id = db.Column(db.INT, primary_key=True)
name = db.Column(db.String(255))
class Subscription(db.Model):
"""Representation of a subscription
"""
series_id = db.Column(db.INT, primary_key=True)
user_id = db.Column(db.String(255), primary_key=True)
My database module uses the way and it works fine(init.py file):
db: SQLAlchemy
def init(app):
database.db = SQLAlchemy(app)
# handle database operations...
One approach to solve the issue is just using another instance in the relations.py like that:
app = flask.Flask(__name__)
db = SQLAlchemy(app)
# declare classes...
I tried it out and it workes, but that is not a nice way to solve this and leads to other problems.
Importing it from main does also not work because of circular import.
I have no idea how to smoothly solve this without removing modularization. I would be thankful for any inputs. If I should add any further information, just let me know.
I would create the app variable in your main.py file but leave out the initializing part. From there you call a function from init.py to basically set up the database. That is what I did for my last flask project.
Main.py:
from init import create_app
app = create_app()
if __name__ == '__main__':
app.run(debug=True)
Init.py:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
DB_NAME = "database.db"
def create_app():
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
db.init_app(app)
create_database(app)
#Other operations ...
return app
Relations.py
from init import db
#all your classes ...
db.create_all()
So now you can import the db object to your relations.py file from the init.py.

How can I create a table if not exist on Flask with SQLAlchemy?

I am using SQLAlchemy and I have the following code:
Model:
class User(db.Model):
__tablename__ = 'user'
__table_args__ = {'schema': 'task', 'useexisting': True}
id = Column(Integer, primary_key=True, autoincrement=True)
firstname = Column(String)
.env
SQLALCHEMY_DATABASE_URI = os.getenv('SQLALCHEMY_DATABASE_URI')
app.py
def create_app(config_file):
"""Create a Flask application using the app factory pattern."""
app = Flask(__name__)
"""Load configuration."""
app.config.from_pyfile(config_file)
"""Init app extensions."""
from .extensions import db
db.init_app(app)
This creates the SQLite file if it does not exist, but not the tables of each model.
The question is what can I do in order to create the tables for each model?
Just add:
db.create_all()
in app.py at the end of create_app().
create_all() will create the tables only when they don't exist and would not change the tables created before.
If you want to create the database and the tables from the command line you can just type:
python
from app.py import db
db.create_all()
exit()
The working example:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.secret_key = "Secret key"
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///my_database.sqlite3"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
class Data(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(50))
email = db.Column(db.String(50))
phone = db.Column(db.String(50))
db.create_all()
# add a row
# comment out after the 1st run
table_row = Data(name="My Name", email="myemail#mail.com", phone="123456")
db.session.add(table_row)
db.session.commit()
print "A row was added to the table"
# read the data
row = Data.query.filter_by(name="My Name").first()
print "Found:", row.email, row.phone
if __name__ == "__main__":
app.run(debug=True)
This is for Python 2.7, to run with Python 3.x just change the the print statements to call the print() function.
NOTE:
When using automatic model class constructor the arguments passed to model class constructor must be keyword arguments or there will be an error. Otherwise you can override the __init__() inside Data() class like this:
def __init__(self, name, email, phone, **kwargs):
super(Data, self).__init__(**kwargs)
self.name = name
self.email = email
self.phone = phone
In that case you don't have to use keyword arguments.
you need first to use Shell Context Processor to load automatically all Model objects
in app.py add
# import all models from all blueprints you have
from .users.models import User
#app.shell_context_processor
def make_shell_context():
return { 'db': db, 'User': User .. }
and then use Flask shell command
(venv) $ flask shell
>>> db
<SQLAlchemy engine=sqlite:///data-dev.sqlite> # something similar to that
>>>
>>> User
<class 'api.users.models.User'>
>>>
>>> # to create database if not exists and all tables, run the command below
>>> db.create_all()
maybe you'll need Flask-Migrate for advanced operations (migrations) on your database: create new table, update tables / fields ...

Why does my database get reset after each deployment?

I am new to deploying to aws as well as flask. Basically I have a simple Flask app but every time I make a change and deploy the new code to aws elastic beanstalk, the db gets reset.
from dateutil import parser
from datetime import datetime
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from flask_cors import CORS
import os
application = app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'db.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
ma = Marshmallow(app)
cors = CORS(app)
#app.route('/')
def hello():
return 'hello'
.
.
.
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
weight = db.Column(db.Float)
workouts = db.relationship('Workout', backref='user', lazy=True)
def __init__(self, name, weight):
self.name = name
self.weight = weight
class UserSchema(ma.Schema):
class Meta:
fields = ('id', 'name', 'weight')
user_schema = UserSchema(strict=True)
users_schema = UserSchema(many=True, strict=True)
.
.
.
db.create_all()
if __name__ == '__main__':
app.run(debug=True)
I expect that each time I
eb deploy flask-env my db wouldnt get reset but it does. For instance if i create a user and then later change something in the code and deploy, that user is gone.
You should:
Create an EBS Volume
Load the database into that volume
Attach the EBS Volume to your Beanstalk app with an .ebextension. An example can be found here.
With all that being said, this is not a highly available, well architected solution and will deteriorate at scale rapidly.
You will want to replace SQLite with an RDS instance at some point in the future before it becomes a problem.

using Flask-Migrate together with Flask-Security

I'm trying to get a basic Flask-Security app working with Flask-Migrate. I have two main py files: app.py and db_migrate.py
app.py:
from flask import Flask, render_template, request, session
from flask.ext.babel import Babel
from flask.ext.mail import Mail
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.security import Security, SQLAlchemyUserDatastore, UserMixin, RoleMixin
import os
basedir = os.path.abspath(os.path.dirname(__file__)) #should be __ file __ with no spaces
# Create app
app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SECRET_KEY'] = 'super-secret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'app.db')
app.config['DEFAULT_MAIL_SENDER'] = 'info#site.com'
app.config['SECURITY_REGISTERABLE'] = True
app.config['SECURITY_CONFIRMABLE'] = True
app.config['SECURITY_RECOVERABLE'] = True
app.config.from_object('config.email')
# Setup mail extension
mail = Mail(app)
# Setup babel
babel = Babel(app)
#babel.localeselector
def get_locale():
override = request.args.get('lang')
if override:
session['lang'] = override
rv = session.get('lang', 'en')
return rv
# Create database connection object
db = SQLAlchemy(app)
# Setup Flask-Security
from db_manager import User, Role #THIS IS PROBABLY WRONG!
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)
#db.create_all()
# Views
#app.route('/')
def home():
return render_template('index.html')
if __name__ == '__main__':
app.run()
db_migrate.py:
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.script import Manager
from flask.ext.migrate import Migrate, MigrateCommand
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.security import Security, SQLAlchemyUserDatastore, UserMixin, RoleMixin
import os
basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'app.db')
db = SQLAlchemy(app)
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
# Define models
roles_users = db.Table('roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
description = db.Column(db.String(255))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
active = db.Column(db.Boolean())
confirmed_at = db.Column(db.DateTime())
favcolor = db.Column(db.String(255))
roles = db.relationship('Role', secondary=roles_users,
backref=db.backref('users', lazy='dynamic'))
def __str__(self):
return '<User id=%s email=%s>' % (self.id, self.email)
if __name__ == '__main__':
manager.run()
I have run the migration tool to initialize and migrate the db once, to create a new db, and it worked:
python db_manager.py db init
python db_manager.py db migrate
I tried to run app.py. It serves correctly on localhost, but then when I try to log a user in, I get the following OperationalError:
OperationalError: (OperationalError) no such table: user u'SELECT user.id AS user_id, user.email AS user_email, user.password AS user_password, user.active AS user_active, user.confirmed_at AS user_confirmed_at, user.favcolor AS user_favcolor \nFROM user \nWHERE lower(user.email) LIKE lower(?)\n LIMIT ? OFFSET ?' (u'xxx#xxx.com', 1, 0)
Basically, I doubt that I'm creating user_datastore and security correctly, as I probably shouldn't be importing User and Role in that way -- but I'm not sure how to access them properly.
EDIT:
I added this final command, thanks to suggestion:
python db_manager.py db ugrade
But, now I get this error when I try to confirm a user registration via email:
(InvalidRequestError: Object '' is already attached to session '1' (this is '3')
The workflow with Flask-Migrate/Alembic is as follows:
db init
This you do once when you create the migration repository and never again.
db migrate
You run this to generate a migration script. The output of the command tells you where the migration script was created, and shows a summary of what was put in it. Your database has not been modified at this stage.
review the migration script
This is very important. Automatic migrations are not perfect, you have to review the generated script and make any corrections that are necessary.
db upgrade
This applies the migration to your database, effectively making the necessary schema changes.
You can now use your database. When you make more changes to your models return to Step 2 and repeat the cycle.
From your description you maybe missed step 4, the upgrade call.
As a side note, you have some duplication between your two scripts, you should try to consolidate them. Take a look at how people build Flask applications split across multiple modules or packages.

Categories