I first followed this tutorial: https://python-adv-web-apps.readthedocs.io/en/latest/flask_db1.html Which worked (I got a website with the output 'It Works')
I then tried to follow the subsequent tutorial: https://python-adv-web-apps.readthedocs.io/en/latest/flask_db2.html
However, I am now getting the error: '((sqlite3.OperationalError) no such table:)'
Which stems from the following code:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
#from sqlalchemy.sql import text
app=Flask(__name__)
db_name='Monsters.db'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + db_name
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# this variable, db, will be used for all SQLAlchemy commands
db = SQLAlchemy(app)
class Creature(db.Model):
__tablename__ = 'Creatures'
ID = db.Column(db.Integer, primary_key=True)
Name = db.Column(db.Text)
AC = db.Column(db.Integer)
HP = db.Column(db.Integer)
@app.route('/')
def index():
try:
Creatures = Creature.query.order_by(Creature.Name).all()
print(Creatures)
sock_text = '<ul>'
for Monster in Creatures:
sock_text += '<li>' + Creatures.Name + '</li>'
sock_text += '</ul>'
return sock_text
except Exception as e:
# e holds description of the error
error_text = "<p>The error:<br>" + str(e) + "</p>"
hed = '<h1>Something is off.</h1>'
return hed + error_text
if __name__ == '__main__':
app.run(debug=True, port=5000)
I checked my table in DB Browser (SQLite) and all the names are correct. I also looked at the instance folder generated by the code. It also had a Monsters.db file in it but using DB Browser to open this gives just an empty folder; while replacing this with the actual Monsters.db file gives the error "'list' object has no attribute 'Name'" but this feels like something I shouldn't have to do.
Update: I have updated my code using the following guide - https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/quickstart/#create-the-tables
However I am unsure if I am calling SQLAlchemy.create_all() correctly, as it doesn't give a lot of context for where it should be used. Additionally, it does now create this database in my instance fiolder but it is empty which does mean I no longer have an error but my webpage is blank.
So, how do I call SQLAlchemy.create_all() in a way that gives me a populated database in my instance folder?
Update 2 - Final Update:
I realised by reading the documentation that to read from a database table already containing data the reflect() method is required as described here: https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/models/
This led me to find this useful answer, describing how to do just that: How to build a flask application around an already existing database?
Which I was able to combine with the code from the outdated tutorial to get the expected result. The final code is shown below:
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
db_name='Monsters.db'
engine=create_engine('sqlite:///' + db_name, echo=False)
Base=declarative_base()
Base.metadata.reflect(engine)
class Creatures(Base):
__table__ = Base.metadata.tables['Creatures']
from sqlalchemy.orm import scoped_session, sessionmaker
from flask import Flask
app=Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + db_name
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
@app.route('/')
def index():
try:
db_session=scoped_session(sessionmaker(bind=engine))
Creature=db_session.query(Creatures.ID, Creatures.Name, Creatures.HP, Creatures.AC)
sock_text = '<ul>'
for Monster in Creature:
sock_text += '<li>' + Monster.Name + '</li>'
sock_text += '</ul>'
return sock_text
except Exception as e:
# e holds description of the error
error_text = "<p>The error:<br>" + str(e) + "</p>"
hed = '<h1>Something is off.</h1>'
return hed + error_text
if __name__ == '__main__':
app.run(debug=True, port=5000)
while replacing this with the actual Monsters.db file gives the error "'list' object has no attribute 'Name'"
for Monster in Creatures:
sock_text += '<li>' + Creatures.Name + '</li>'
Presumably that is supposed to be Monster.Name
, not Creatures.Name
.