pythonflaskflask-sqlalchemyflask-migrate

Cannot migrate Flask db : No such command 'db'


I'm new on Flask, I've been setting up a first version of my flask app : test-app, with a mysql database. Now I want to alter and add some columns to some of my database table without erasing the existing data. I heard about Flask-migrate with Alembic as a solution of that problem. I've tried to setting everything up but came with this error :

Error: Failed to find Flask application or factory in module 'test-app.app'. Use 'test-app.app:name' to specify one.

Usage: flask [OPTIONS] COMMAND [ARGS]...
Try 'flask --help' for help.

Error: No such command 'db'.

when running this command within my .env : flask db migrate -m "initial migration"

I don't understand, here is the skeleton of my Flask app

test-app/
 .venv/
 app/
  models/
   __init__.py
   domain.py
   subdomain.py
 app.py

Some files :

models/__init__.py

from os.path import dirname, basename, isfile, join
from sqlalchemy.pool import QueuePool
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy(engine_options={"pool_size": 10, 'pool_recycle': 280, "poolclass":QueuePool, "pool_pre_ping":True})

import glob
modules = glob.glob(join(dirname(__file__), "*.py"))
__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')]

models/domain.py (very similar to subdomain.py)

from dataclasses import dataclass
from . import db

@dataclass
class Domain(db.Model):

    __tablename__ = 'domain'
    __table_args__ = {'extend_existing': True} 

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255), nullable=False)

app.py

from flask import Flask, request, jsonify, json
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.event import listens_for
from flaskext.mysql import MySQL
from flask_cors import CORS
from dataclasses import dataclass
from sqlalchemy import text
from urllib.parse import quote
from flask_migrate import Migrate    

app = Flask(__name__)
CORS(app, origins=["http://localhost:3000", "http://localhost:3000"])


from app.models import db

mysql =MySQL()

@dataclass
class User(db.Model):

    __tablename__ = 'user'

    id = db.Column(db.Integer, primary_key=True)
    firstname = db.Column(db.String(46), nullable=False)#1
    lastname = db.Column(db.String(46), nullable=False)#1
    

    def __init__(self, firstname, lastname):
        self.firstname = firstname
        self.lastname = lastname

    def as_dict(self):
        excluded_fields = ['id']
        return {field.name:getattr(self, field.name) for field in self.__table__.c if field.name not in excluded_fields}

@dataclass
class User(db.Model):

    __tablename__ = 'user'
    __table_args__ = {'extend_existing': True} 

    id = db.Column(db.Integer, primary_key=True)
    firstname = db.Column(db.String(46), nullable=False)#1
    lastname = db.Column(db.String(46), nullable=False)#1

    def __init__(self, firstname, lastname):
        self.firstname = firstname
        self.lastname = lastname

    def as_dict(self):
        excluded_fields = ['id']
        return {field.name:getattr(self, field.name) for field in self.__table__.c if field.name not in excluded_fields}



app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://username:pwd@127.0.0.1/test'

db.init_app(app)
with app.app_context():
    from app.models import *
    migrate = Migrate(app, db)
    db.create_all()


@app.route('/users', methods=['GET'])
def get_user():
    users = User.query.all()
    return jsonify(users)

@app.route('/user/<firstname>', methods=['GET'])
def user_byfirstname(firstname):
    user = User.query.filter_by(firstname = firstname).first()
    return jsonify(user.as_dict())

if __name__ == '__main__':
   app.run(debug=True)

requirements.txt

aiohttp==3.8.6
aiohttp-retry==2.8.3
aiosignal==1.3.1
alembic==1.13.1
async-timeout==4.0.3
attrs==23.1.0
blinker==1.6.3
certifi==2023.7.22
cffi==1.16.0
charset-normalizer==3.3.1
click==8.1.7
cryptography==41.0.7
distlib==0.3.7
filelock==3.12.4
Flask==2.3.0
Flask-Cors==4.0.0
flask-marshmallow==0.14.0
Flask-Migrate==4.0.7
Flask-MySQL==1.5.2
Flask-MySQLdb==2.0.0
Flask-Script==2.0.6
Flask-SQLAlchemy==3.1.1
flask-talisman==1.1.0
frozenlist==1.4.0
idna==3.4
itsdangerous==2.1.2
Jinja2==3.1.2
Mako==1.3.3
MarkupSafe==2.1.3
marshmallow-sqlalchemy==0.29.0
multidict==6.0.4
mysqlclient==2.2.0
packaging==23.2
platformdirs==3.11.0
psycopg2-binary==2.9.9
pycparser==2.21
PyJWT==2.8.0
PyMySQL==1.1.0
pyOpenSSL==23.3.0
python-dotenv==1.0.0
requests==2.31.0
six==1.16.0
SQLAlchemy==2.0.22
twilio==8.10.0
typing_extensions==4.8.0
urllib3==2.0.7
virtualenv==20.24.5
waitress==2.1.2
Werkzeug==3.0.0
WSGIserver==1.3
yarl==1.9.2

Please help!


Solution

  • I found the solution. flask db migrate -m "initial migration" crashes because I've both folder and file with the same name, within the same root (app/ and app.py). I renamed app/ into common/ and it solved my problem.