I am trying to define a mongodb object inside main flask app. And I want to send that object to one of the blueprints that I created. I may have to create more database objects in main app and import them in different blueprints. I tried to do it this way.
from flask import Flask, render_template
import pymongo
from admin_component.bp1 import bp_1
def init_db1():
try:
mongo = pymongo.MongoClient(
host='mongodb+srv://<username>:<passwrd>#cluster0.bslkwxdx.mongodb.net/?retryWrites=true&w=majority',
serverSelectionTimeoutMS = 1000
)
db1 = mongo.test_db1.test_collection1
mongo.server_info() #this is the line that triggers exception.
return db1
except:
print('Cannot connect to db!!')
app = Flask(__name__)
app.register_blueprint(bp_1, url_prefix='/admin') #only if we see /admin in url we gonna extend things in bp_1
with app.app_context():
db1 = init_db1()
#app.route('/')
def test():
return '<h1>This is a Test</h1>'
if __name__ == '__main__':
app.run(port=10001, debug=True)
And this is the blueprint and I tried to import the init_db1 using current_app.
from flask import Blueprint, render_template, Response, request, current_app
import pymongo
from bson.objectid import ObjectId
import json
bp_1 = Blueprint('bp1', __name__, static_folder='static', template_folder='templates')
print(current_app.config)
db = current_app.config['db1']
But it gives this error without specifying more details into deep.
raise RuntimeError(unbound_message) from None
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
the current application. To solve this, set up an application context
with app.app_context(). See the documentation for more information.
Can someone point out what am I doing wrong here??
The idea you are attempting is correct; however it just needs to be done a little differently.
First, start by declaring your mongo object in your application factory:
In your app/__init__.py:
import pymongo
from flask import Flask
mongo = pymongo.MongoClient(
host='mongodb+srv://<username>:<passwrd>#cluster0.bslkwxdx.mongodb.net/?retryWrites=true&w=majority',
serverSelectionTimeoutMS = 1000
)
# Mongo is declared outside of function
def create_app(app):
app = Flask(__name__)
return app
And then in your other blueprint, you would call:
from app import mongo # This right here will get you the mongo object
from flask import Blueprint
bp_1 = Blueprint('bp1', __name__, static_folder='static', template_folder='templates')
db = mongo
Related
I've been following some tutorials(basic examples), trying to create a RESTful API with Flask-Restx. However, when I try to register endpoints with a more complex project structure(following this example), no API endpoints get registered.
I defined the namespace of an endpoint and tried to register that in app.py:
from flask import Flask, Blueprint, url_for, jsonify
from flask_login import LoginManager
import settings
from database import db
from BE.api.__init__ import api
from BE.api.endpoints.images import ns as image_api
from werkzeug.middleware.proxy_fix import ProxyFix
app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)
#flask_restx API supports prior flask_restplus api
def configure_app(app):
app.config['SWAGGER_UI_DOC_EXPANSION'] = settings.RESTPLUS_SWAGGER_EXPANSION
app.config['RESTPLUS_VALIDATE'] = settings.RESTPLUS_VAL
app.config['RESTPLUS_MASK_SWAGGER'] = settings.RESTPLUS_MASK_SWAGGER
app.config['SQLALCHEMY_DATABASE_URI'] = settings.SQLALCHEMY_DATABASE_URI
app.config['UPLOAD_FOLDER'] = settings.UPLOAD_FOLDER
app.config['MAX_UPLOAD_LENGTH'] = 24 * 1024 * 1024 # limits filesize to 24 mb
def init_app(app):
configure_app(app)
api.add_namespace(image_api)
app.register_blueprint(api, url_prefix='/api/1')
api.init_app(app)
db.init_app(app)
[....main etc]
The API init.py looks as follows:
from flask_restx import Api
api = Api(version='0.1', title='Backend API', description='Backend API for sticker generation')
and the endpoint I want to register:
from flask import request, flash, Blueprint, redirect, send_file
from flask_restx import Resource, Namespace
from BE.database import db as database
from BE.database.models import Image as dbImage
from BE.api.api_definition import image
[....]
ns = Namespace('image', path='/image', description='Available Ops')
#ns.route('/test')
class TestClass(Resource):
def get(self):
return "Hello World"
[....]
While #app.route('/') works in app.py, the #ns.route('/') remains unsuccessful and I'm at a loss as to why.
Answering my own question:
Turns out that running app.py from PyCharm does not run via main() or was configured in a wrong way, but rather appears to just launch the Flask server from the initial app = Flask(__name__). Therefore configure_app() or init_app() never get called.
Transforming the project layout to something more closely resembling Flask's intended layout resolves that in part, resulting in the intended endpoints to work.
I am trying to use SQLAlchemy not in a view function (I was doing something like this with Flask-APSheduler).
I know that there were already a lot of topics related to this theme, but none of them were helpful to me.
So, first of all I will show my code:
./run.py
from app import create_app
from flask_config import DevConfig, ProdConfig
app = create_app(DevConfig)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
./app/__init__.py
from flask import Flask
from .node import node
from .models import db
def create_app(app_config=None):
app = Flask(__name__, instance_relative_config=False)
app.config.from_object(app_config)
db.init_app(app)
app.register_blueprint(node)
return app
./app/models.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Users(BaseFuncs, db.Model):
...
./app/node.py
from flask import Blueprint, request
from .bot import bot, secret
import telebot
node = Blueprint('node', __name__)
#node.route('/{}'.format(secret), methods=['POST'])
def handler():
bot.process_new_updates([telebot.types.Update.de_json(request.get_data().decode('utf-8'))])
return 'ok', 200
./app/bot.py
from flask import current_app as app
...
#bot.message_handler(commands=['test'])
def cmd_test(message):
with app.app_context():
print(Users.query.filter_by(id=0).first())
So when I am trying to call cmd_test from my application I am getting this error:
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context(). See the
documentation for more information.
I tried to use g variable and before_request methods, because every time before calling the database there is a call to the route 'handler', but this also doesn't work.
I also tried to use db.get_app(), but there was no effect.
So my question is how to call database right outside the views?
I have created a small Flask application which stores its data in an sqlite database that I access via flask-sqlalchemy.
However, when I run it, I get the following error:
RuntimeError: No application found. Either work inside a view function or push an application context. See http://flask-sqlalchemy.pocoo.org/contexts/.
I have debugged my application and now know that this error stems from these two functions:
def user_exists(email):
if User.query.filter_by(email = email).count() == 0:
return False
else:
return True
def get_user(email):
user = User.query.filter_by(email = email).first()
return user
Now I am wondering: Is it impossible to access the database via flask-sqlalchemy outside of view functions?
For further context, I added the files in which I configure my flask app:
presentio.py
from app import create_app
app = create_app(os.getenv("FLASK_CONFIG", "default"))
app/init.py
from flask_mail import Mail
from flask_sqlalchemy import SQLAlchemy
from config import config
mail = Mail()
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
mail.init_app(app)
db.init_app(app)
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint, url_prefix = "/auth")
from .text import text as text_blueprint
app.register_blueprint(text_blueprint, url_prefix = "/text")
return app
You need to give the flask app a context after you create it.
This is done automatically in view functions, but outside those, you need to do this after you create the app:
app.app_context().push()
See the docs: https://flask-sqlalchemy.palletsprojects.com/en/2.x/contexts/
I'm having some trouble understanding how to incorporate Flask-Pymongo. My app is initiated from my rrapp.py Inside of this file, I have
rrapp.py
#
# Imports up here
#
app = Flask(__name__)
mongo = PyMongo(app)
# Code down here
Now, to use this, I simply do mongo.db.users.find(). This works fine.
Now, say I have another file called userservice.py that I call methods from one of my endpoints within rrapp.py. How do I incorporate PyMongo(app) in my userservice.py file if I don't have access to the app object? Or am I missing something obvious here?
you should first define mongo oustside create_app to have access to it from inside other files.
then init_app with that like the following:
from flask import Flask, current_app
from flask_pymongo import PyMongo
mongo = PyMongo()
def create_app(config_name):
app = Flask(__name__, instance_relative_config=False)
app.config.from_object(app_config[config_name])
# INIT EXTENSIONS ----------------------
mongo.init_app(app)
return app
then in any file you can import mongo from above file. for example:
from ../factory import mongo
# main.py
from flask import Flask, jsonify
from flask.ext.cors import CORS
from shared.database import db
from src import controllers
import os
app = Flask(__name__)
cors = CORS(app, allow_headers='Content-Type')
app.register_blueprint(controllers.api)
if (os.getenv('SERVER_SOFTWARE') and os.getenv('SERVER_SOFTWARE').startswith('Google App Engine/')):
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+gaerdbms:///gaiapro_api_dev?instance=dev-gaiapro-api:gaiapro-sql'
else:
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+mysqldb://root#127.0.0.1/gaiapro_api_dev'
app.config['DEBUG'] = True
db.init_app(app)
# shared/database.py
from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()
# src/controllers/__init__.py
from flask import Blueprint, jsonify, request
from src import models
from src import views
from shared.helpers import *
api = Blueprint('api', __name__)
#api.route('/test')
def test():
...
# shared/helpers.py
from flask import jsonify, request, abort, make_response
from shared.database import db
def some_method():
...
db.session.commit() # Can access db normally from here
# src/models/__init__.py
from shared.database import db
class Client(db.Model):
id = db.Column(db.Integer, primary_key=True)
...
I am developing for GAE (Google App Engine). Basically what I want is to test my models in the Interactive Console from inside the Admin Server of _dev_appserver.py_.
I have tried to run the following code from the Interactive Console:
from main import *
from src import models
print models.Client.query.get(1)
The result was:
RuntimeError: application not registered on db instance and no application bound to current context
If I try just to print the db variable in this context, the result is: SQLAlchemy engine=None
I don't know what I am doing wrong. My code runs normally on the browser, but I cannot get it to work from the Interactive Console.
You need to be in an app context (or a request context) to access application bound objects.
An easy way to achieve this is to use Flask-Script, which provides a shell command that sets up the application for you. Or use Flask's integration with Click if you are using the development version.
To just get it working immediately, set up the context yourself:
ctx = app.app_context()
ctx.push()
# do stuff
ctx.pop()
# quit
You can also use a context in a with block:
with app.app_context():
# do stuff
Use flask shell instead of default python interpreter
$ flask shell
$ from yourappname import db
$ db # this will print your connection string
$ db.create_all()