I created a simple boilerplate flask application with one class in the model. My problem is that my app doesn't create the table in the mysql database after the app first run. Ideally, table should be created only if it doesn't exist (so I can leave the create_all instruction in the code)
project tree is:
.
├── application.py
├── module
│ ├── __init__.py
│ ├── __pycache__
│ │ └── __init__.cpython-36.pyc
│ └── models.py
├── requirements.txt
├── static
└── templates
That's the content of application.py file
from flask import Flask
from module import db
app = Flask(__name__)
app.config['DEBUG'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://oskar:secret#ipaddress/analytics'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
#app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
# with app.app_context():
db.init_app(app)
app.app_context().push()
# create tables only once
db.create_all(app=app)
db.session.commit()
app.run()
Content of module/__init__.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
Content of module/models.py
from module import db
class PostalCodeCities(db.Model):
postal_code = db.Column(db.String(6), nullable=False) # kod pocztowy
city = db.Column(db.String(126), nullable=False) # miejscowosc
street = db.Column(db.String(126))
building = db.Column(db.String(32))
municipality = db.Column(db.String(126)) # gmina
county = db.Column(db.String(126)) # powiat
voivodeship = db.Column(db.String(126)) # wojewodztwo
def __repr__(self):
return '<PostalEntry %r>' % self.postal_code
What I'm doing wrong?
Thanks!
I already found the solution. I had to move everything from __init__.py to models.py and in applications.py import db from module.models
Related
I have flask application that I am using to get familiar with the flask-sqlalchemy lib and testing using Pytest with fixtures.
I am trying to overwrite the sqlalchemy_database_uri in the app configuration in my test fixtures. But the problem is that when I run them, my tests seem to be working with the "production" database rather than with an ephemeral one. The test record I created for test via fixtures are all in the database that I create in the app initialization.
When I run the test in the example below using pytest from the root folder in that structure. The tests are collected ok, run and pass as expected. But after running the tests a new database called hello.db has been created in the instance folder. What I am trying to do is that the tests use a sqlite database in memory that disapears after the tests run.
How do I go about writing/configuring my tests so that I use an ephemeral sqlite database in memory that is only used for those tests?
# Folder structure
.
├── mini_app
│ ├── __init__.py
│ ├── app.py
│ ├── config.py
│ └── models.py
└── tests
├── __init__.py
└── test_all.py
## app.py
from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
from mini_app import config
db = SQLAlchemy()
def create_app(cfg= None):
if cfg is None:
cfg = config.Config()
app = Flask(__name__)
app.config.from_object(cfg)
# Init_apps
db.init_app(app)
#app.route("/square")
def square():
"""A view which uses no templates and no database."""
number = int(request.args.get("number", 0))
return str(number ** 2)
return app
## config.py
class Config:
SQLALCHEMY_DATABASE_URI = "sqlite:///hello.db"
## models.py
from mini_app.app import db
class Author(db.Model):
__tablename__ = "authors"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String)
## test_all.py
import pytest
import mini_app.app
import mini_app.models
#pytest.fixture
def client():
# Prepare before your test
app = mini_app.app.create_app()
app.config["TESTING"] = True
app.testing = True
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite://"
with app.test_client() as client:
with app.app_context():
mini_app.app.db.create_all()
author1 = mini_app.models.Author(id=1, name="foo")
mini_app.app.db.session.add(author1)
mini_app.app.db.session.commit()
# Give control to the test
yield client
# Cleanup after the test run.
# ... nothing here, for this simple example
def test_square(client):
rv = client.get("/square?number=8")
assert b"64" == rv.data
1.I was trying to use Pymongo to connect to my MongoDB atlas database. I wrote this file into the connect.py file. Here is the tree folder structure. The connect.py contains the URL information to connect the database.
└── uploading
├── __pycache__
│ └── upload.cpython-38.pyc
└── upload.py
├── Database
│ ├── __pycache__
│ │ └── connect.cpython-38.pyc
│ └── connect.py
├── app.py
2.Here is code for connect.py
import pymongo
client = pymongo.MongoClient("URL",ssl=True, ssl_cert_reqs='CERT_NONE')
db = client.datasets
Here is the code for uplod.py
from flask import Blueprint, current_app
from Database.connect import db
sample = Blueprint('sample', __name__)
#sample.route('/')
def index():
x = current_app.config['UPLOAD_PATH']
return str(db)
Here is the code for app.py:
app = Flask(__name__)
app.secret_key = b'pj&\xe9\xd7\xd7\xabc\xe6KX\xbe\x9f<\x9f\x87'
app.config['UPLOAD_PATH'] = 'public' # to create a folder which is used to save the uploaded file
CORS(app)
app.register_blueprint(sample)
'''
Datasets and model upload
'''
#app.route('/connect-upload', methods=["POST"])
#cross_origin()
def connect_upload():
index=0
# get username
return "result"
When I tried to use : from Database.connect import db to import database in the upload.py, it showed error message :ImportError: cannot import name 'db' from 'Database.connect'. How can I solve this problem?
You are not referencing your module correctly. Your module should be the filename. You should use from connect import db.
Intro
I've read like a thousand posts on SO and other sites trying to figure out what's wrong with my Flask structure and why I can't seem to figure out something. As a last resort, I decided to finally ask the question here.
My project is really simple:
I have to fetch some data from some networking devices via API, process the data and store it in a Postgresql DB (most part of the code is in lib/).
This project is going to be deployed on multiple environments (test, dev, staging and prod).
To do the above I'm using the following:
Flask-SQLAlchemy + Flask-Migrate + Flask-Script - all of these for handling migrations and DB related operations;
Python-dotenv - for handling sensitive configuration data
Project details
My project structure looks like this:
my_project/
├── api/
├── app.py
├── config.py
├── __init__.py
├── lib/
│ ├── exceptions.py
│ └── f5_bigip.py
├── log.py
├── logs/
├── manage.py
├── migrations/
├── models/
│ ├── __init__.py
│ ├── model1.py
│ └── model2.py
└── run.py
My app.py looks like this:
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from dotenv import load_dotenv
from flask import Flask
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
migrate = Migrate()
def create_app():
load_dotenv()
app = Flask(__name__)
environment = app.config['ENV']
if environment == 'production':
app.config.from_object('config.ProductionConfig')
elif environment == 'testing':
app.config.from_object('config.TestingConfig')
else:
app.config.from_object('config.DevelopmentConfig')
db.init_app(app)
migrate.init_app(app, db)
return app
My config.py looks like this:
import os
from sqlalchemy.engine.url import URL
PROJECT_ROOT = os.path.dirname(os.path.realpath(__file__))
class BaseConfig:
DEBUG = False
TESTING = False
DB_DRIVERNAME = os.getenv('DB_DRIVERNAME')
DB_HOST = os.getenv('DB_HOST')
DB_PORT = os.getenv('DB_PORT')
DB_NAME = os.getenv('DB_NAME')
DB_USERNAME = os.getenv('DB_USERNAME')
DB_PASSWORD = os.getenv('DB_PASSWORD')
DB = {
'drivername': DB_DRIVERNAME,
'host': DB_HOST,
'port': DB_PORT,
'database': DB_NAME,
'username': DB_USERNAME,
'password': DB_PASSWORD,
}
SQLALCHEMY_DATABASE_URI = URL(**DB)
SQLALCHEMY_TRACK_MODIFICATIONS = False
class DevelopmentConfig(BaseConfig):
DEVELOPMENT = True
DEBUG = True
class TestingConfig(BaseConfig):
TESTING = True
class StagingConfig(BaseConfig):
DEVELOPMENT = True
DEBUG = True
class ProductionConfig(BaseConfig):
pass
My __init__.py looks like this:
from contextlib import contextmanager
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# here, create_engine needs the SQLALCHEMY_DATABASE_URI
# how do I get it from the proper config?
engine = create_engine()
Session = sessionmaker(bind=engine)
#contextmanager
def session_scope():
"""
Provide a transactional scope around a series of operations.
"""
session = Session()
try:
yield session
session.commit()
except Exception as e:
print(f'Something went wrong here: {str(e)}. rolling back.')
session.rollback()
raise
finally:
session.close()
My manage.py looks like this:
from flask_script import Manager
from flask_migrate import MigrateCommand
from app import create_app
from models import *
manager = Manager(create_app)
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
My models/model1.py looks like this:
from sqlalchemy.dialects.postgresql import INET
from sqlalchemy.sql import func
from app import db
class Model1(db.Model):
__tablename__ = 'model1'
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
ip_address = db.Column(INET, unique=True, nullable=False)
last_update = db.Column(db.DateTime(), server_default=func.now())
def __repr__(self):
return f'<Model1: {self.ip_address}>'
def __init__(self, ip_address):
self.ip_address = ip_address
Questions
Now, I have three main questions:
In my main __init__.py how can I import SQLALCHEMY_DATABASE_URI from the app's config?
Having the Session() object in the __init__.py doesn't seem too intuitive. Should it be placed in other places? For more context, the session is used in lib/f5_bigip.py and is probably going to be used in the api/ as well.
Is the overall project structure ok?
Your questions 1 and 2 are directly related to the part of your project that I found strange, so instead of answering those questions I'll just give you a much simpler and better way.
It seems in __init__.py you are implementing your own database sessions, just so that you can create a scoped session context manager. Maybe you've got that code from another project? It is not nicely integrated with the rest of your project, which uses the Flask-SQLAlchemy extension, you are just ignoring Flask-SQLAlchemy, which manages your database connections and sessions, and basically creating another connection into the database and new sessions.
What you should do instead is leverage the connections and sessions that Flask-SQLAlchemy provides. I would rewrite __init__.py as follows (doing this by memory, so excuse minor mistakes):
from contextlib import contextmanager
from app import db
#contextmanager
def session_scope():
"""
Provide a transactional scope around a series of operations.
"""
try:
yield db.session
session.commit()
except Exception as e:
print(f'Something went wrong here: {str(e)}. rolling back.')
db.session.rollback()
raise
finally:
db.session.close()
With this you are reusing the connection/sessions from Flask-SQLAlchemy. Your question 1 then is not a problem anymore. For question 2, you would use db.session anywhere in your app where you need database sessions.
Regarding question 3 I think you're mostly okay. I would suggest you do not use Flask-Script, which is a fairly old and unmaintained extension. Instead you can move your CLI to Flask's own CLI support.
I'm trying to run a simple unit-test for a restful app I'm creating. The server runs perfectly and displays the json data. I'm looking for a test that confirms that the json data is a 'GET' request or confirms a say a 200 response status code
below is my directory structure
├── MealAPP
├── app
│ ├── __init__.py
│ └── models.py
├── instance
│ ├── __init__.py
│ └── config.py
├── manage.py
├── requirements.txt
├── run.py
└── test_mealapp.py
init.py
from flask_api import FlaskAPI
from flask_sqlalchemy import SQLAlchemy
from flask import Flask, jsonify, request
# local import
from instance.config import app_config
# initialize sql-alchemy
db = SQLAlchemy()
def create_app(config_name):
app = FlaskAPI(__name__, instance_relative_config=True)
app.config.from_object(app_config["development"])
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)
#app.route("/", methods=['GET'])
def test():
return jsonify({'message':'It works!'})
return app
test_mealapp.py
import unittest
import os
import json
from app import create_app
class FlaskTestCase(unittest.TestCase):
def test_index(self):
"""Define test variables and initialize app."""
self.app = create_app(config_name="testing")
self.client = app.client.test_client
response = self.client("/")
# self.assertEqual(response[message],"It works!")
self.assertEqual(response.status_code, 200)
if __name__ == '__main__':
unittest.main()
Any tips on how to fix my test_mealapp.py?
This would work:
class FlaskTestCase(unittest.TestCase):
def test_index(self):
self.app = create_app(config_name="testing")
with self.app.test_client() as client:
response = client.get("/")
responseJson = json.loads(response.data)
self.assertEqual(responseJson['message'], "It works!")
self.assertEqual(response.status_code, 200)
Try to always use the client in a with: block and make sure to use the request method as the attribute to client (get in this case)
I am using django 1.5.1 and trying to get moving the management command. I have an app called patient and here is the directory structure.
patient/
├── __init__.py
├── forms.py
├── management
│ ├── __init.py__
│ └── commands
│ ├── __init.py__
│ └── recall1.py
├── models.py
├── urls.py
├── views.py
Here is what happens when I try to run the recall1 command:
$ python manage.py recall1
Unknown command: 'recall1'
Here is how my code looks like:
from django.core.management.base import BaseCommand, CommandError
from recall.model import PatientRecalls, RecallType, RecallMessage
from patient.model import Patient
class Command(BaseCommand):
args = '<patient_id patient_id ...>'
def handle(self, *args, **options):
for patient_id in args:
try:
patient = Patient.objects.get(pk=int(patient_id))
except Patient.DoesNotExist:
raise CommandError('Patient "%s" does not exist' % patient_id)
patient.opened = False
patient.save()
self.stdout.write('Successfully closed patient "%s"' % patient_id)
What wrong do I need to correct before I can run this thing? The app is running great, except for this issue..
Your filename __init.py__ should actually be __init__.py both in the directories management/ and commands/