
Good afternoon, habrauzer.
Not so long ago, my friend and I started making a small text toy in the framework of the fantastic Versum project. In the article I want to talk about the problems that we had to face, as well as about which solutions we chose.
')
We use Python, in particular the
Flask microframe.
Install Flask
The process is quite simple.
pip install flask
pip install sqlalchemy
pip install flask-sqlalchemy
pip install alembic
In those manuals that came across to me,
sqlalchemy-migrate is used for migration, but it seems to me that it is a little more than terrible. It has a dependency on the
sqlalchemy version, that is, to use migrations, you need to specifically select versions for each other. In addition, on
the sqlalchemy-migrate page, the following is written:
If you want to start your project with SQLAlchemy and you need to migrate data schemas, use AlembicSin is not to take advice.
cd ~
mkdir flask
cd flask
alembic init alembic
mkdir app_name
And move on to the next item.
Application skeleton
For writing a simple “Hello, World!” There is a
good manual on the official site . But, having played enough in the sandbox, we began to collect the skeleton of our future application and got the first problems, so to speak. If Django imposes its application structure on us, generating it automatically after startproject and startapp, then Flask gives us complete freedom. I don’t know if this should be considered a “problem”, but when you don’t know where to dig it becomes sad, and your hands drop.
However, after a long meditation on the official textbook, after looking at the repositories on the githaba for a long time (in particular, the search results for “flask skeleton”), after reading a
series of articles (by Miguel Grinberg) - some insight and reassurance came.
In the end, the skeleton of our application is as follows:
~ / flask
| - / alembic
| - / app_name
| | - / static
| | | - / css
| | | - / js
| | | - / img
| | - / templates
| | | - index.html
| | - __init__.py
| | - config.py
| | - models.py
| | - views.py
| - alembic.ini
| - README.md
| - requirements.txt
| - runserver.py
Let's go in order, flask is the root folder of the project, git is initialized here, a virtual environment is created here, in general, everything related to the project, including the dev server startup file - runserver.py. It is quite simple, I use it to run the application on a local machine:
Everything you need, including the initialization of the application and its modules, occurs in
__init__.py import os FLASK_APP_DIR = os.path.dirname(os.path.abspath(__file__))
The very same
config.py looks like this:
class Config(object): SECRET_KEY = 'some_secret' SITE_NAME = 'app_name.ru' SQLALCHEMY_DATABASE_URI = 'mysql://user:pass@localhost/tabe_name?charset=utf8' class ProductionConfig(Config): DEBUG = False TESTING = False class TestConfig(Config): DEBUG = False TESTING = True class DevelopmentConfig(Config): '''Use "if app.debug" anywhere in your code, that code will run in development code.''' DEBUG = True TESTING = True
Now to reach the app object that is commonly used in the application (provided that the
flask folder is added to PYTHONPATH):
from app_name import appThis connects everything necessary for the operation of the application.
When
alembic is initialized,
alembic.ini will also be in the root, but we do not need to touch it. To integrate with our application, you will need to climb into the
env.py file, which lies inside the
alembic folder.
In it, after the line
# target_metadata = mymodel.Base.metadata, you need to add:
and rewrite
run_migrations_online :
def run_migrations_online(): """Run migrations in 'online' mode. In this scenario we need to create an Engine and associate a connection with the context. """ alembic_config = config.get_section(config.config_ini_section) from app_name import app alembic_config['sqlalchemy.url'] = app.config['SQLALCHEMY_DATABASE_URI'] engine = engine_from_config( alembic_config, prefix='sqlalchemy.', poolclass=pool.NullPool) connection = engine.connect() context.configure( connection=connection, target_metadata=target_metadata ) try: with context.begin_transaction(): context.run_migrations() finally: connection.close()
This completes the integration of
alembic with our application. For automatic migration we use:
alembic revision --autogenerate -m 'some text'
At the same time, migration files of the
hashcode_some_text.py type are created in the
versions folder. It is desirable, and sometimes even necessary, to look into them. According to the developers themselves, alembic does not understand the renaming of tables and fields, and also creates keys poorly.
To use the migration, use the following command:
alembic upgrade head
The last line in the
config.py file we
cling to views.py , which stores the business logic. The minimum set for the start can be:
from app_name import app, db from flask import Blueprint, request, render_template frontend = Blueprint('frontend', __name__)
Right at the beginning handlers for errors which will work after shutdown of gebug are added. In general, this is still the same “Hello, World!”, But in an extended version.
The models.py file will store our models until it is empty. With a statics and templates which accordingly lie in
static and
templates , it seems everything is clear.
Run on server
After running on the server with nginx and uwsgi, it turned out that when a fall, a beautiful debbager does not appear. When starting the server via runserver.py, everything is fine, debbager is in place.
The uwsgi daemon writes error details to its logs, so not everything is so bad. The bug is quite old, at least there was a
one-year old question on stackoverflow . It seems that this is the problem of the uwsgi itself or their friendship with nginx, but we could not solve this misunderstanding. We are satisfied with debbager on the local machine and error messages to the mail.
I hope this article will help save some time for those who will first write their application on Flask.