Flask SQLALCHEMY_DATABASE_URI is not defined - python

I am having a problem setting up the skeleton of my Flask API, where I am getting an error regarding the URI for my database.
I have it set up like this
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlite3 import Connection as SQLite3Connection
from datetime import datetime
from sqlalchemy import event
from sqlalchemy.engine import Engine
from flask import Flask, request, jsonify
app = Flask(__name__)
app.config[SQLALCHEMY_DATABASE_URI] = "sqlite:///sqlitedb.file"
app.config[SQLALCHEMY_TRACK_MODIFICATIONS] = 0
but I am getting the error in my IDE that [SQLALCHEMY_DATABASE_URI] is not defined and I also get the same error when trying to execute the program.
The modules import fine, so I'm not sure what I'm missing.
Edit: RESOLVED. I didn't have quotes around my config dictionary entries.

From the docs:
The config is actually a subclass of a dictionary and can be modified
just like any dictionary
this is how you modify app.config:
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///sqlitedb.file"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = 0

A crucial step is how SQLAlchemy gets informed of configuration. That'll look something like:
app = Flask(__name__)
# ... configuration
db = SQLAlchemy()
db.init_app(app)

Related

Flask-Pymongo DB is returning as None

I am trying create a webapp with Flask-Pymongo, but it is saying that my database does not exist.
This is my __init__.py:
import os
from flask import Flask
from flask_pymongo import PyMongo
mongo = PyMongo()
def init_app():
app = Flask(__name__)
app.config.from_pyfile('config.py')
mongo.init_app(app)
with app.app_context():
from temp.routes.stage_routes import stage_route
app.register_blueprint(stage_route)
return app
This is my db.py (temp is the top level directory)
from temp.__init__ import mongo
db = mongo.db
and this is one of my blueprints with routes to query the database
from flask import Blueprint
from temp.db import db
stage_route = Blueprint('stage_route', __name__, url_prefix='/stages')
#stage_route.route('/')
def home():
return 'This is the home page for the stage blueprint'
#stage_route.route('/all')
def all():
stage = db.stages.find() # This is where the error is
print(stage)
For some reason I get the error saying that "NoneType does not have attribute 'stages'" because it is saying that the db variable is none. I can't figure out why this is is happening since the database and the collection does exist and the MONGO_URI string is loaded from the config file. I can see that it is connecting on the mongodb side, but i'm assuming it has something to do with my create_app() function in the init.py file. Do you see something that I am missing? Any help would be appreciated
The code is missing the connection URI string, as mentioned in the documentation -
from flask import Flask
from flask_pymongo import PyMongo
app = Flask(__name__)
# The missing URI
app.config["MONGO_URI"] = "mongodb://localhost:27017/myDatabase"
mongo = PyMongo(app)

How to use Flask app config while the app is being created (using an app factory)?

Suppose I have something like this in app/models.py:
from flask import current_app as app
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.sql import func
db = SQLAlchemy()
class LoginLink(db.Model):
...
expiration_date = db.Column(
db.DateTime(timezone=True), nullable=False,
server_default=func.now() + str(app.config["LOGIN_LINK_EXP_TIME"]) # Error here!!!
)
And this in app/__init__.py:
from flask import Flask
from config import CONFIG_OBJECT
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(CONFIG_OBJECT[config_name])
from app.models import db
db.init_app(app)
db.create_all(app=app)
return app
Finally, this is my config.py:
from datetime import timedelta
CONFIG_OBJECT = {
"dev": "config.DevConfig",
"prod": "config.ProdConfig"
}
class Config:
...
class DevConfig(Config):
LOGIN_LINK_EXP_TIME = timedelta(seconds=30)
class ProdConfig(Config):
LOGIN_LINK_EXP_TIME = timedelta(minutes=30)
I tried to use app.app_context() everywhere (believe me) and I'm still getting this error:
RuntimeError: Working outside of application context.
I'm just trying to do the following: in a development environment I want the login links to expire in 30 seconds (for testing and demonstration purposes), but login links will last 30 minutes in a production environment.
How to accomplish this using different config environments?
Note: this is intended to be a generic question.
I think I had a misconception about application factories. We have the following from the Flask documentation:
The downside is that you cannot use the application object in the blueprints at import time. You can however use it from within a request.
Additionally:
It’s preferable to create your extensions and app factories so that the extension object does not initially get bound to the application.
What is in bold is what I was doing wrong: using the application object outside a request and bounding the extension to the application.
Therefore, I only see two solutions:
Use the app.config object (or dict) only within requests (the best IMHO).
Don't include configs that require to be used outside of requests in the app.config object (although this may complicate testing a bit).

How to use an existing PostGIS database in a Flask web app

I'm building a web app using Flask and a PostGIS database I already created. I'm struggling to get Flask-SQLAlchemy to accept the geom column of my existing database. I declare db in an init.py file:
from flask import Flask, request, current_app
from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
import os, logging
db = SQLAlchemy()
migrate = Migrate()
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
db.init_app(app)
migrate.init_app(app, db)
My code for my models.py file looks like this:
from app import login, db
from datetime import datetime
from geoalchemy2 import Geometry
from time import time
from flask import current_app
class Streets(db.Model):
id = db.Column(db.Integer, primary_key=True)
street = db.Column(db.String(50))
geom = db.GeometryColumn(db.LineString(2))
The error I get is: AttributeError: 'SQLAlchemy' object has no attribute 'GeometryColumn'
And if I try to remove db. from the geom line, I get this error: NameError: name 'GeometryColumn' is not defined
Because Flask-SQLAlchemy wants you to declare a column using db.Column, it seems to override geoalchemy2. Has anyone found a solution to this?
It does not override GeoAlchemy2. You could use GeometryColumn as a column, if you were using the previous version of GeoAlchemy.
The first error is caused by the fact that the SQLAlchemy object from Flask-SQLAlchemy gives you access to functions etc. from sqlalchemy and sqlalchemy.orm. It does not include stuff from GeoAlchemy2 or such.
The second error is due to not having the name GeometryColumn in scope. You do import Geometry from geoalchemy2, but don't use it.
Reading the GeoAlchemy2 ORM tutorial you'd notice that geometry columns are defined as
geom = Column(Geometry('POLYGON'))
or in your case
geom = db.Column(Geometry('LINESTRING')) # dimension defaults to 2
Note that db.Column is sqlalchemy.schema.Column, just in another namespace.

How do I remove a circular dependency between a Flask blueprint and the application initialisation? [duplicate]

I want to structure my Flask app something like:
./site.py
./apps/members/__init__.py
./apps/members/models.py
apps.members is a Flask Blueprint.
Now, in order to create the model classes I need to have a hold of the app, something like:
# apps.members.models
from flask import current_app
from flaskext.sqlalchemy import SQLAlchemy
db = SQLAlchemy(current_app)
class Member(db.Model):
# fields here
pass
But if I try and import that model into my Blueprint app, I get the dreaded RuntimeError: working outside of request context. How can I get a hold of my app correctly here? Relative imports might work but they're pretty ugly and have their own context issues, e.g:
from ...site import app
# ValueError: Attempted relative import beyond toplevel package
The flask_sqlalchemy module does not have to be initialized with the app right away - you can do this instead:
# apps.members.models
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Member(db.Model):
# fields here
pass
And then in your application setup you can call init_app:
# apps.application.py
from flask import Flask
from apps.members.models import db
app = Flask(__name__)
# later on
db.init_app(app)
This way you can avoid cyclical imports.
This pattern does not necessitate the you place all of your models in one file. Simply import the db variable into each of your model modules.
Example
# apps.shared.models
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
# apps.members.models
from apps.shared.models import db
class Member(db.Model):
# TODO: Implement this.
pass
# apps.reporting.members
from flask import render_template
from apps.members.models import Member
def report_on_members():
# TODO: Actually use arguments
members = Member.filter(1==1).all()
return render_template("report.html", members=members)
# apps.reporting.routes
from flask import Blueprint
from apps.reporting.members import report_on_members
reporting = Blueprint("reporting", __name__)
reporting.route("/member-report", methods=["GET","POST"])(report_on_members)
# apps.application
from flask import Flask
from apps.shared import db
from apps.reporting.routes import reporting
app = Flask(__name__)
db.init_app(app)
app.register_blueprint(reporting)
Note: this is a sketch of some of the power this gives you - there is obviously quite a bit more that you can do to make development even easier (using a create_app pattern, auto-registering blueprints in certain folders, etc.)
an original app.py: https://flask-sqlalchemy.palletsprojects.com/en/2.x/quickstart/
...
app = flask.Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = flask.ext.sqlalchemy.SQLAlchemy(app)
class Person(db.Model):
id = db.Column(db.Integer, primary_key=True)
...
class Computer(db.Model):
id = db.Column(db.Integer, primary_key=True)
...
# Create the database tables.
db.create_all()
...
# start the flask loop
app.run()
I just splitted one app.py to app.py and model.py without using Blueprint. In that case, the above answer dosen't work. A line code is needed to work.
before:
db.init_app(app)
after:
db.app = app
db.init_app(app)
And, the following link is very useful.
http://piotr.banaszkiewicz.org/blog/2012/06/29/flask-sqlalchemy-init_app/

Unable to import db object more than once in flask and sqlalchemy

I have a couple of modules: start.py, user.py, projects.py
In start.py I have:
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'my_database_URI'
db = SQAlchemy(app)
db.createAll()
I need to use the db object from both user.py and projects.py. If I import it like so:
from start import db
then I get an error if I do this in both modules. If I only import it to user.py, for example - then it works fine. The error I'm getting is "ImportError: cannot import name db".
Is there a way to solve this?
Sounds like this is a circular import problem.
The way that I've gotten around this is by having another file, a shared.py file in the root directory. In that file, create the database object,
from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()
In your start.py, don't create a new db object. Instead, do
from shared import db
db.init_app(app)
In any place that you want to use the db object, including your models file, import it from shared.py:
from shared import db
# do stuff with db
This way, the object in the shared file will have been initialized with the app context, and there's no chance of circular imports.

Categories