I've come into the following error:
sqlalchemy.exc.OperationalError
OperationalError: (OperationalError) no such table: user u'SELECT user.id AS user_id, user.name AS user_name, user.password AS user_password \nFROM user \nWHERE user.id = ?' (1,)
I'm not sure how to debug this but I think it must be coming because its not loading the db file that I already generated using my models.py file. I've loaded that db file and made sure that the users table exists, and it does with data, but I can't figure out how to connect my flask application to the database.
Here's my models.py that I ran beforehand to generate the tables (I haven't included the declarations above it):
from datetime import datetime
import os
from sqlalchemy import Column, ForeignKey
from sqlalchemy import Boolean, DateTime, Integer, String, Text
from sqlalchemy.orm import relationship, synonym, backref
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
""" User """
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(200))
password = Column(String(100))
def __init__(self, name, password):
self.name = name
self.password = password
def __repr__(self):
return '<User %r>' % self.name
if __name__ == '__main__':
from datetime import timedelta
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
PWD = os.path.abspath(os.curdir)
engine = create_engine('sqlite:///{}/arkaios.db'.format(PWD), echo=True)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
# Add a sample user
user = User(name='Philip House', password="test")
session.add(user)
session.commit()
Here's app.py:
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask import render_template
from arkaios.models import Base, User
from arkaios import config
app = Flask(__name__)
app.config.from_object(config)
db = SQLAlchemy(app)
db.Model = Base
#app.route('/admin/large-group')
def largeGroupOverview():
user = db.session.query(User).filter_by(id=1)
return render_template('largegroup/overview.html', user=user)
#app.route('/admin/large-group/<int:event_id>')
def largeGroupAttendance(event_id):
return render_template('largegroup/attendance.html')
#app.route('/focus')
def largegroup():
return 'Focus work'
And finally, app.py refers to config.py which is below:
import os
PWD = os.path.abspath(os.curdir)
DEBUG=True
SQLALCHEMY_DATABASE_URI = 'sqlite:///{}/arkaios.db'.format(PWD)
SECRET_KEY = 'thisissecret'
SESSION_PROTECTION = 'strong'
I can post the stack trace as well if need be! There must be something missing conceptually about how I'm thinking about how to connect Flask and SQLAlchemy, but I can't figure it out.
Thanks for any help :)
Are you running python models.py before python app.py app to create the database? The if __name__ == "__main__" will keep that part of the code from running when you import the file from app.py.
I would also make sure the db is valid using sqlite3 and run the .tables command.
Related
Help!
I'm really new to flask and I've been muddling along with all the tutorials I could find but I've run into a problem I can't figure out.
Here's my error:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: User
[SQL: SELECT "User"."userId" AS "User_userId", "User".email AS "User_email", "User".password AS "User_password", "User".username AS "User_username", "User".lastlogin AS "User_lastlogin", "User".isauthenticated AS "User_isauthenticated"
FROM "User"
WHERE "User".email = ?
LIMIT ? OFFSET ?]
[parameters: ('test#example.com', 1, 0)]
(Background on this error at: http://sqlalche.me/e/13/e3q8)
So I'm working on the signup form and I've solved all the other bugs. But here what I can make out from this error is that my database or table isn't being created.
Here's my code:
init.py:
import os
from flask import Flask, render_template, redirect, session
from flask_login import LoginManager
from flask_bcrypt import Bcrypt
from flask_sqlalchemy import SQLAlchemy
from werkzeug.utils import import_string
from complete.app import redirect_url
db = SQLAlchemy()
login_manager = LoginManager()
def create_app():
"""Create Flask application."""
app = Flask(__name__, instance_relative_config=False)
#app.context_processor
def inject_global_vars():
return dict(appname="Ebay Listing Viewer")
app.config.from_pyfile('configfile.py')
db.init_app(app)
login_manager.init_app(app)
with app.app_context():
from .userauth.auth import auth_bp
app.register_blueprint(auth_bp)
db.create_all()
from .models import User
#login_manager.user_loader
def load_user(user_id):
return User.get(user)
return app
models.py:
"""Data Models"""
from flask_login import UserMixin
from . import db
class User(UserMixin, db.Model):
__tablename__ = 'User'
userid = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(100), unique=True)
password = db.Column(db.String(200))
username = db.Column(db.String(1000))
lastlogin = db.Column(db.DateTime)
isauthenticated = db.Column(db.Boolean, default=False)
def is_active(self):
return True
def get_id(self):
return chr(self.userId)
def is_authenticated(self):
return self.isauthenticated
def is_anonymous(self):
return False
def __repr__(self):
return '<User> {}'.format(self.username)
def set_password(self, password):
self.password = generate_password_hash(
password,
method='sha256'
)
def check_password(self, password):
return check_password_hash(self.password, password)
config.py:
class Config(object):
"""Base config."""
SECRET_KEY = environ.get('SECRET_KEY')
STATIC_FOLDER = 'static'
TEMPLATES_FOLDER = 'templates'
class DevelopmentConfig(Config):
FLASK_ENV = 'development'
SQLALCHEMY_DATABASE_URI = environ.get('DEV_DATABASE_URI')
.env:
#among other things...
DEV_DATABASE_URI=sqlite:///db.sqlite
There is a file called db.sqlite in my root folder (ie the same directory as init.py) but I'm not sure it's got anything in it. When I try to open it, it shows The file is not displayed in the editor because it is either binary or uses an unsupported text encoding. (I'm using VSCode).
I'm not quite sure how the database uri works - I've had a lot of looks around Google and everyone seems to think it's completely obvious. Is it the file path to my database file? Do I create the database file or is it automatically created?
I'm thinking the problem is likely to be that the database uri is wrong, but I dunno, I haven't got enough experience so maybe it's something completely different.
Thank you for taking the time to read and help!
So Im trying to create a website using flask and SQLAlchemy for database storage but I keep getting the two aforementioned errors
Here is my app.py code
import os
from flask import Flask, session,render_template, request
from flask_session import Session
from sqlalchemy import create_engine,Column, Integer, String
from sqlalchemy.orm import scoped_session, sessionmaker
from flask_sqlalchemy import SQLAlchemy
from models import *
app = Flask(__name__)
#app.config["DATABASE_URL"] = "sqlite:////plz_work.db"
app.config["SQLALCHEMY_DATABASE_URI"] = os.getenv("DATABASE_URL")
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db.init_app(app)
# Check for environment variable
#if not os.getenv("DATABASE_URL"):
# raise RuntimeError("DATABASE_URL is not set")
# Configure session to use filesystem
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
# Set up database
engine = create_engine(os.getenv("DATABASE_URL"))
db = scoped_session(sessionmaker(bind=engine))
class User:
def __init__(self,username,password):
self.username = username
self.password = password
#app.route("/")
def index():
return render_template('index.html')
#app.route("/registration.html")
def registration():
return render_template('registration.html')
#app.route("/send", methods = ['GET','POST'])
def send():
username = request.form['username']
password = request.form['password']
users = User(username,password)
db.session.add(users)
db.session.commit()
return render_template('index.html')
if __name__ == "__main__":
app.run(debug = True)
db.create_all()
and here is my models.py file
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class USERS(db.Model):
__tablename__ = "Users"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String)
password = db.Column(db.String)
def __repr__(self):
value = "USER:({}, {})".format(self.username, self.password)
return value
I have been looking online for a soloution for so long but I can not find anything that works for me, and I have spent 2 days just on this problem, any help will be appreciated.
Thank You !!
I guess you're overriding your database object within your models.py file.
I suggest you to use sqlalchemy itself or flask-sqlalchemy not using them together. In my opinion things get complicated if you use them together.
You can achive that like this:
in your app.py
...your_other_imports...
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from .models import *
app = Flask(__name__)
...your_other_configs...
# Set up database
engine = create_engine(os.getenv("DATABASE_URL"))
db = scoped_session(sessionmaker(bind=engine))
#NOW db carries your database session
#Do not define your database models in app.py remove User class from here.
#You should define your database model and also your query method (not necessary)
#if you're used to query with flask-sqlalchemy. Would make queries look similar to you
dbModel = declarative_base()
dbModel.query = db.query_property()
# define the function which will create your tables
def init_db():
from .models import *
dbModel.metadata.create_all(bind=engine)
...your_routes...
if __name__ == "__main__":
app.run(debug = True)
# now call the function to create your tables
init_db()
in your models.py
from .app import dbModel
from sqlalchemy import Column, Integer, String
class User(dbModel):
__tablename__ = "users"
id = Columnn(Integer, primary_key=True)
username = Column(String)
password = Column(String)
def __repr__(self):
value = "USER:({}, {})".format(self.username, self.password)
return value
Using query_property you can now query your data from your database and use your session to put data in your database like this:
User.query.filter_by(username=...).first()
newUser = User(
username=...,
password=...
)
db.add(newUser)
db.commit()
I have a Flask application that I am using with SQLAlchemy. I don't want to use the Flask-SQLAlchemy extension. If I use a "real" database for testing and just set up environment variables that point to the test instance of the database, everything works well.
However, I've run into a problem if I want to point to an in-memory sqlite database for testing. In that case I can set up the data in my test, but when I use the test_client to execute a given route in my application, it can't find my database tables on the "server side" as it were - i.e. in the hello.py code shown further down. There must be a way to configure the test_client for this to work, but I can't seem to quite figure out how to do it.
Here are the snippets of code that may be relevant (db.py):
import os
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
engine = create_engine(os.environ['SQLALCHEMY_URL'])
Session = scoped_session(sessionmaker(bind=engine))
Here I am setting up the scoped_session so that my database access will be thread-local.
The code that bootstraps my application (__init__.py):
from flask import Flask
from .db import Session
from .hello import hello_blueprint
app = Flask(__name__)
app.register_blueprint(hello_blueprint)
#app.teardown_appcontext
def cleanup(resp_or_exc):
Session.remove()
Here I'm setting up my app and registering the cleanup callback each time Flask pops the application context.
An example route in a blueprint (hello.py):
import json
from flask import Blueprint
from .db import Session
from .models import Message
hello_blueprint = Blueprint('hello', __name__)
#hello_blueprint.route('/messages')
def messages():
values = Session.query(Message).all()
results = []
for value in values:
results.append({ 'message': value.message })
return (json.dumps(results), 200, { 'content_type': 'application/json' })
Here I'm using the scoped session to get some data from the database.
The definition of my Message model is just vanilla SQLAlchemy (models.py):
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
Base = declarative_base()
class Message(Base):
__tablename__ = 'messages'
id = Column(Integer, primary_key=True)
message = Column(String)
def __repr__(self):
return "<Message(message='%s')>" % (self.message)
Below is a very raw pytest unit test just to demonstrate the problem all in one place (test_hello.py):
import os
import json
import pytest
import app
from .models import Message
#pytest.fixture
def client():
client = app.app.test_client()
return client
def test_hello(client):
response = client.get('/')
data = json.loads(response.data.decode('utf-8'))
assert data == { 'message': "Hello friend!" }
def test_messages(client):
with app.app.app_context():
from sqlalchemy import create_engine
from sqlalchemy import MetaData
engine = create_engine('sqlite://')
from .models import Base
Base.metadata.create_all(engine)
print('***metadata tables***')
print(Base.metadata.tables.keys())
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
Session = scoped_session(sessionmaker(bind=engine))
message = Message(message='Hello there!')
Session.add(message)
Session.commit()
values = Session.query(Message).all()
results = []
for value in values:
results.append({ 'message': value.message })
# This works, prints : [{"message": "Hello there!"}]
print('*** result***')
print(json.dumps(results))
# The code below doesn't work. Flask's app.py throws an exception
# with the following at its root:
# sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table:
# messages [SQL: 'SELECT messages.id AS messages_id, messages.message AS messages_message, messages.new_field
# AS messages_new_field \nFROM messages'] (Background on this error at: http://sqlalche.me/e/e3q8)
response = client.get('/messages')
data =json.loads(response.data.decode('utf-8'))
assert data == [{'message': 'Hello there!'}]
I'm not quite sure what I was doing wrong before, but I'm managed to get my test passing.
The modified version of the unit test is below (test_hello.py):
import os
import json
import pytest
import app
from .db import engine
from .db import Session
from .models import Base
from .models import Message
#pytest.fixture
def client():
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
client = app.app.test_client()
return client
def test_messages(client):
message = Message(message='Hello there!')
Session.add(message)
Session.commit()
response = client.get('/messages')
data = json.loads(response.data.decode('utf-8'))
assert data == [{'message': 'Hello there!'}]
URI:
SQLALCHEMY_DATABASE_URI = "mssql+pymssql://user:password123#127.0.0.1/DbOne"
SQLALCHEMY_BINDS = {
"sql_server": "mysql+pymysql://user:password123#127.0.0.1/DbTwo"
}
Models.py
class CrimMappings(db.Model):
__tablename__ = "crim_mappings"
id = db.Column(db.Integer, primary_key=True)
date_mapped = db.Column(db.Date)
county_id = db.Column(db.Integer)
state = db.Column(db.String(20))
county = db.Column(db.String(100))
AgentID = db.Column(db.String(100), unique=True)
CollectionID = db.Column(db.String(100))
ViewID = db.Column(db.String(100))
class LicenseType(db.Model):
__bind_key__ = "sql_server"
__table__ = db.Model.metadata.tables["sbm_agents"]
however it throws me a KeyError saying the 'sbm_agents' table is not found which it should be there because I've specified the bind key to point to the sql_server bind.
__init__.py
from os.path import join,dirname,abspath
from flask_admin import Admin
from project.apps.flask_apps.user_app.forms import UserAdminForm
from flask_admin.contrib.sqla import ModelView
from project import app_factory, db
from project.apps.flask_apps.admin_own.views import AdminHome, Utilities
from project.apps.flask_apps.admin_own.models import CredentCheckMappings, AllAgents, LicenseTypes
from project.apps.flask_apps.admin_own.forms import MasterAgentForm, AgentMappingsModelView, AllLicenseForm
from project.apps.flask_apps.user_app.models import Users
def create_application():
config_path = join(dirname(abspath(__file__)), "config", "project_config.py")
app = app_factory(config_path=config_path)
admin = Admin(app, template_mode="bootstrap3", base_template="base_templates/admin_base.html",
index_view=AdminHome())
with app.app_context():
db.create_all()
db.Model.metadata.reflect(db.engine)
admin.add_view(MasterAgentForm(AllAgents, db.session))
admin.add_view(UserAdminForm(Users, db.session))
admin.add_view(Utilities(name="Utilities", endpoint="utilities"))
admin.add_view(AgentMappingsModelView(CredentCheckMappings, db.session))
admin.add_view(AllLicenseForm(LicenseTypes, db.session))
return app
application = create_application()
if __name__ == "__main__":
application.run(host="0.0.0.0", port=5000, debug=True)
what am I missing here?
I've tried this:
flask sqlalchemy example around existing database
but im getting the KeyError
did something change or im missing a step?
Edit:
For people wanting to know how I got around this.
I went straight to SqlAlchemy and did this
from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.automap import automap_base
from urllib.parse import quote_plus
engine = create_engine("mssql+pyodbc:///?odbc_connect="+ quote_plus("DRIVER={FreeTDS};SERVER=172.1.1.1;PORT=1433;DATABASE=YourDB;UID=user;PWD=Password"))
metadata = MetaData(engine)
Session = scoped_session(sessionmaker(bind=engine))
LicenseType= Table("sbm_agents", metadata, autoload=True)
that way im not reflecting the entire database and only choose to reflect certain tables. because it turns out that reflecting the entire database is slow.
although this approach is a little tougher because you have to configure FREETDS but its doable just a little tedious and confusing at first
Use db.reflect() instead of db.Model.metadata.reflect(db.engine).
I'm trying to integrate PostgreSQL and SQLAlchemy but SQLAlchemy.create_all() is not creating any tables from my models.
My code:
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://login:pass#localhost/flask_app'
db = SQLAlchemy(app)
db.create_all()
db.session.commit()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return '<User %r>' % self.username
admin = User('admin', 'admin#example.com')
guest = User('guest', 'guest#example.com')
db.session.add(admin)
db.session.add(guest)
db.session.commit()
users = User.query.all()
print users
But I get this error: sqlalchemy.exc.ProgrammingError: (ProgrammingError) relation "user" does not exist
How can I fix this?
You should put your model class before create_all() call, like this:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://login:pass#localhost/flask_app'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return '<User %r>' % self.username
with app.app_context():
db.create_all()
db.session.add(User('admin', 'admin#example.com'))
db.session.add(User('guest', 'guest#example.com'))
db.session.commit()
users = User.query.all()
print(users)
If your models are declared in a separate module, import them before calling create_all().
Say, the User model is in a file called models.py,
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://login:pass#localhost/flask_app'
db = SQLAlchemy(app)
# See important note below
from models import User
with app.app_context():
db.create_all()
db.session.add(User('admin', 'admin#example.com'))
db.session.add(User('guest', 'guest#example.com'))
db.session.commit()
users = User.query.all()
print(users)
Important note: It is important that you import your models after initializing the db object since, in your models.py you also need to import the db object from this module.
If someone is having issues with creating tables by using files dedicated to each model, be aware of running the "create_all" function from a file different from the one where that function is declared.
So, if the filesystem is like this:
Root
--app.py <-- file from which app will be run
--models
----user.py <-- file with "User" model
----order.py <-- file with "Order" model
----database.py <-- file with database and "create_all" function declaration
Be careful about calling the "create_all" function from app.py.
This concept is explained better by the answer to this thread posted by #SuperShoot
This is probably not the main reason why the create_all() method call doesn't work for people, but for me, the cobbled together instructions from various tutorials have it such that I was creating my db in a request context, meaning I have something like:
# lib/db.py
from flask import g, current_app
from flask_sqlalchemy import SQLAlchemy
def get_db():
if 'db' not in g:
g.db = SQLAlchemy(current_app)
return g.db
I also have a separate cli command that also does the create_all:
# tasks/db.py
from lib.db import get_db
#current_app.cli.command('init-db')
def init_db():
db = get_db()
db.create_all()
I also am using a application factory.
When the cli command is run, a new app context is used, which means a new db is used. Furthermore, in this world, an import model in the init_db method does not do anything, because it may be that your model file was already loaded(and associated with a separate db).
The fix that I came around to was to make sure that the db was a single global reference:
# lib/db.py
from flask import g, current_app
from flask_sqlalchemy import SQLAlchemy
db = None
def get_db():
global db
if not db:
db = SQLAlchemy(current_app)
return db
I have not dug deep enough into flask, sqlalchemy, or flask-sqlalchemy to understand if this means that requests to the db from multiple threads are safe, but if you're reading this you're likely stuck in the baby stages of understanding these concepts too.