Flask failed to load configuration from config.py - flask

My __init__.py file
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import app_config
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__, instance_relative_config=True)
app.config.from_object(app_config[config_name])
app.config.from_pyfile('config.py')
db.init_app(app)
#app.route('/')
def index():
return 'Hello, user'
return app
I will find tutorial for flask
build crud app flask
My config.py file:
import os
# Set path for our db
basedir = os.path.dirname(os.path.abspath(__file__))
class Config:
DEBUG = True
class DevConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir,
'bookshell.db')
SQLALCHEMY_ECHO = True
SQLALCHEMY_TRACK_MODIFICATIONS = False
class ProdConfig(Config):
DEBUG = False
class TestConfig(Config):
DEBUG = True
app_config = {
'development': DevConfig,
'production': ProdConfig,
'testing': TestConfig
}
run.py file
import os
# Import from app/__init__
from app import create_app
config_name = os.getenv('FLASK_CONFIG', 'development')
app = create_app(config_name)
if __name__ == '__main__':
app.run()
So, I tried to configure my own config.py file, but I get an error
FileNotFoundError: [Errno 2] Unable to load configuration file (No such file or directory): '/Users/yevhensurzhenko/Desktop/Simple_login_form/instance/config.py'
But when I change some configuration, and when try to reload page it give me
405 error method not allowed
or
app.config.from_object(app_config[config_name])
KeyError: <flask.cli.ScriptInfo object at 0x1038a5b70>
So, I made some changes, like
In config.py add
app_config = {
..
'default': DevConfig
}
In __init__.py create instance dir.
from instance import config
And now I get output from func that I create in __init__.py, in create__app()...
#app.route('/')
def index():
return 'Hello, user'
But, FLASK_CONFIG not change, it work only production, wtf:(

Related

Integrate flask-sqlalchemy into project

I am new comer of flask api. I am doing a flask restful api project which purpose is to search stores by store name that is kept in existing database online.
Now is is connect to database using psycopg2.
I would like to improve it by using flask-sqlalchemy. I have searched on the web and the solution seems to use Automap, that I learned from the tutorial. The problem I am facing now is how to integrate those codes into my existing project, like where should I put the settings like automap_base() into my existing codes. Here is my current file structure:
app.py
∟ models
∟ family_mart.py
∟ resources
∟ family_mart.py
app.py:
from flask import Flask
from flask_restful import Api
from resources.family_mart import FamilyMart
app = Flask(__name__)
app.secret_key = 'apple'
api = Api(app)
api.add_resource(FamilyMart, '/familymart/<string:name>')
if __name__ == '__main__':
app.run(port=5000, debug=True)
family_mart.py in models folder:
import psycopg2
from config import config
class FamilyMartModel:
#classmethod
def find_by_name(cls, name):
conn = None
try:
params = config()
conn = psycopg2.connect(**params)
cur = conn.cursor()
query = f"""
SELECT extract_date
, store_name
, address
FROM cnvnt_str_fm
WHERE store_name = '{name}'
"""
cur.execute(query)
rows = cur.fetchall()
cur.close()
if rows:
result = {'store':[]}
for row in rows:
append_dict = {'extract_date':row[0].strftime('%Y-%m-%d'),
'store_name':row[1],
'address':row[2]}
result['store'].append(append_dict)
return result
except (Exception, psycopg2.DatabaseError) as error:
print(error)
finally:
if conn is not None:
conn.close()
print('Database connection closed.')
family_mart.py in resources folder:
from flask_restful import Resource
from models.family_mart import FamilyMartModel
class FamilyMart(Resource):
def get(self, name):
item = FamilyMartModel.find_by_name(name)
if item:
return item
return {'message':'Store not found.'}, 404
After study the documentation, I restructured my project and integrate with sqlalchemy successfully. I removed model folder and added db.py to configure the existing database, here is the detail :
New file structure:
app.py
∟ resources
∟ family_mart.py
db.py
app.py:
from flask import Flask
from flask_restful import Api
from config import config
from db import db
from resources.family_mart import FamilyMart
params = config()
DB_FULL_URL = f"postgresql+psycopg2://{params['user']}:{params['password']}#{params['host']}/{params['database']}"
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = DB_FULL_URL
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.secret_key = 'apple'
api = Api(app)
api.add_resource(FamilyMart, '/familymart/<string:name>')
if __name__ == '__main__':
db.init_app(app)
app.run(port=5000, debug=True)
db.py:
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData
from sqlalchemy import Table, Column, Integer, String, DateTime
db = SQLAlchemy()
metadata_obj = MetaData()
fm_table = Table('cnvnt_str_fm', metadata_obj,
Column('extract_date', String),
Column('store_name', String),
Column('address', String)
)
family_mart.py:
from flask_restful import Resource
from db import db
from db import fm_table
class FamilyMart(Resource):
def get(self, name):
results = db.session.query(fm_table).filter_by(store_name=name).\
order_by(fm_table.c.extract_date.desc()).limit(3)
output = {'store':[]}
for row in results:
extract_date = str(row[0])
store_name = row[1]
address = row[2]
output['store'].append({'extract_date':extract_date,
'store_name':store_name,
'address':address})
return output

Flask - How to load database with config from Flask config?

My folder structure is the following:
- app.py
app
- __init__.py
- database.py
in app.py I have:
from app import create_app
app = create_app()
my init.py looks something like:
from flask import Flask
from app.database import db_session, init_db
db = SQLAlchemy()
def create_app():
myapp = Flask(__name__, static_folder='static', static_url_path='/static', template_folder="templates")
myapp.config.from_object('config.Config')
db.init_app(myapp)
migrate.init_app(myapp, db)
# loading blueprints
from app.core_bp import core_bp
myapp.register_blueprint(core_bp, url_prefix='/', template_folder="templates")
return myapp
and database.py looks like this
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('sqlite:///rapporteur.db')
db_session = scoped_session(sessionmaker(autocommit=False,autoflush=False,bind=engine))
That sqlite path is currently hardcoded to raporteur.db but it should be loaded from config, because I don't want it hardcoded, but unfortunately the flask app is not yet loaded. So how would I do this?
You can use flask-sqlalchemy and set the SQLALCHEMY_DATABASE_URI in the config file.
class Config:
SQLALCHEMY_DATABASE_URI = 'sqlite:///rapporteur.db'
then in your init.py
from youApp import Config
def create_app(config_class=Config)
app = Flask(__name__)
app.config.from_object(config_class)
db = SQLAlchemy()
db.init_app(app)
return app

Flask not reading Secret_key when FLASK_ENV = 'production'

I have a simple Flask app with Config file having Config, Prod and Debug Classes. I have a .env in project root folder, containing the secrets. When I config using Debug it reads the secret key. But when I set it to use Prod it complains:
RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
I am not using Sessions. Here is the code for Config.py:
from os import environ, path
from dotenv import load_dotenv
basedir = path.abspath(path.dirname(__file__))
load_dotenv(path.join(basedir, '.env'))
class Config:
SECRET_KEY = environ.get('SECRET_KEY')
SQLALCHEMY_DATABASE_URI = environ.get('DB_URI')
class ProdConfig(Config):
FLASK_ENV = 'production'
DEBUG = False
TESTING = False
class DevConfig(Config):
FLASK_ENV = 'development'
DEBUG = True
TESTING = True
Here goes init.py
def create_app(config_class=ProdConfig):
flask_app = Flask(__name__)
flask_app.config.from_object(config_class)
Here is run.py which I use to run the project:
from server import create_app
from server.config import DevConfig
app = create_app()
# app = create_app(DevConfig)
csrf.init_app(app)
if __name__ == '__main__':
app.run()
When using DevConfig it works fine but not with ProdConfig. Thank you
from os import environ, path
from dotenv import load_dotenv
basedir = path.abspath(path.dirname(__file__))
load_dotenv(path.join(basedir, '.env'))
class Config(object):
SECRET_KEY = environ.get('SECRET_KEY')
SQLALCHEMY_DATABASE_URI = environ.get('DB_URI')
class ProdConfig(Config):
SECRET_KEY = environ.get('SECRET_KEY_FOR_PROD')
FLASK_ENV = 'production'
DEBUG = False
TESTING = False
class DevConfig(Config):
FLASK_ENV = 'development'
DEBUG = True
TESTING = True
app.py
def create_app():
flask_app = Flask(__name__)
flask_app.config.from_object(config.ProdConfig)

Transferring django settings to Environment Variables

I set the django project settings and added values to environment variables at my local ubuntu mashine and AWS Ubuntu server using .bashrc file at the root folder.
...
export DEBUG="True"
...
settings.py
...
SECRET_KEY = os.environ.get('SECRET_KEY')
DEBUG = os.environ.get('DEBUG', False)
...
At local all working good, but at production server values are not importing. Why doesn't it work on both machines? How do I set up production?
Im running production server using asgi server daphne, accordingly this tutorial
upd
asgi.py
import os
import django
from channels.routing import get_default_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
django.setup()
application = get_default_application()
So, what I usually do is: I have a script which runs when Django is setup and creates a .env file with some values.
project_setup.py
import os
import random
import string
def write_dot_env_file(env_file):
settings = get_settings()
with open(env_file, 'w') as f:
for k, v in settings.items():
f.write(f'{k.upper()}={v}\n')
def get_settings():
return {
'SECRET_KEY': generate_secret_key(),
'DEBUG': True,
'ALLOWED_HOSTS': '*',
}
def generate_secret_key():
specials = '!##$%^&*(-_=+)'
chars = string.ascii_lowercase + string.digits + specials
return ''.join(random.choice(chars) for _ in range(50))
def main():
env_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), '.env')
if not os.path.isfile(env_file):
write_dot_env_file(env_file)
else:
pass
if __name__ == '__main__':
main()
Then on my manage.py and wsgi.py just before Django setting the path of the settings you do:
manage.py
#!/usr/bin/env python
import os
import sys
from project_setup import main as project_setup_main
if __name__ == '__main__':
project_setup_main()
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'yoursettings')
...
And that's it. When Django runs it'll create a .env file for you with the minimum requirements. Or you can just create the function generate_secret_key inside your settings.py and use it as a default for your SECRET_KEY declaration, like: SECRET_KEY = os.environ.get('SECRET_KEY', get_secret_key())

how to use db instance in flask-apscheduler's jobs function

When I used flask-apscheduler(not apscheduler), I have some problems in my flask web project. Especially when I used db(flask-sqlalchemy) objects. The problem may be:
JOBS = [
{
'id': 'job1',
'func': 'app.monitor.views:test',
'args': (),
'trigger': 'interval',
'seconds': 2
}
]
./app/init.py:
from flask import Flask
from flask.ext.bootstrap import Bootstrap
from flask.ext.mail import Mail
from flask.ext.moment import Moment
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.login import LoginManager
from flask.ext.pagedown import PageDown
from flask_apscheduler import APScheduler
from celery import Celery
# from apscheduler.schedulers.blocking import BlockingScheduler
from config import config,Config
bootstrap = Bootstrap()
mail = Mail()
moment = Moment()
db = SQLAlchemy()
pagedown = PageDown()
celery = Celery(__name__, broker=Config.CELERY_BROKER_URL)
# https://pypi.python.org/pypi/Flask-APScheduler
scheduler = APScheduler()
login_manager = LoginManager()
login_manager.session_protection = 'strong'
login_manager.login_view = 'auth.login'
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
bootstrap.init_app(app)
mail.init_app(app)
moment.init_app(app)
db.init_app(app)
login_manager.init_app(app)
pagedown.init_app(app)
scheduler.init_app(app)
celery.conf.update(app.config)
if not app.debug and not app.testing and not app.config['SSL_DISABLE']:
from flask.ext.sslify import SSLify
sslify = SSLify(app)
from .monitor import monitor as monitor_1_0_blueprint
from .laser import laser as laser_1_0_blueprint
app.register_blueprint(monitor_blueprint,url_prefix='/monitor/api')
app.register_blueprint(laser_1_0_blueprint,url_prefix='/laser/api/v1.0')
return app
Error 1:db is : Error 2:db is :No handlers
could be found for logger "apscheduler.executors.default" Error 3:db
is : raise RuntimeError('working outside of application context')
RuntimeError: working outside of application context
The key to the problem is to get the db and app objects in flask-apscheduler jobs function(views.py):
from app import scheduler
def test():
#to Solve the log error problem
import logging
log = logging.getLogger('apscheduler.executors.default')
log.setLevel(logging.INFO) # DEBUG
fmt = logging.Formatter('%(levelname)s:%(name)s:%(message)s')
h = logging.StreamHandler()
h.setFormatter(fmt)
log.addHandler(h)
#get the app object
app = scheduler.app
#get the db object and use it
with app.app_context():
print '........................',db
from app import scheduler#
def test():
#to Solve the log error problem
import logging
log = logging.getLogger('apscheduler.executors.default')
log.setLevel(logging.INFO) # DEBUG
fmt = logging.Formatter('%(levelname)s:%(name)s:%(message)s')
h = logging.StreamHandler()
h.setFormatter(fmt)
log.addHandler(h)
#get the app object
app = scheduler.app
#get the db object and use it
with app.app_context():
print '........................',db
def test():
#to Solve the log error problem
import logging
log = logging.getLogger('apscheduler.executors.default')
log.setLevel(logging.INFO) # DEBUG
fmt = logging.Formatter('%(levelname)s:%(name)s:%(message)s')
h = logging.StreamHandler()
h.setFormatter(fmt)
log.addHandler(h)
#get the app object
app = scheduler.app
#get the db object and use it
with app.app_context():
print '........................',db #the right db object