2

I'm currently learning flask and I'm looking into database relationships, however I'm trying the following commands in cmd:

set FLASK_APP=app4.py
flask db init

When I run that, I get the following come through:

Traceback (most recent call last):
  File "c:\users\admin\appdata\local\programs\python\python37-32\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "c:\users\admin\appdata\local\programs\python\python37-32\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Users\admin\AppData\Local\Programs\Python\Python37-32\Scripts\flask.exe\__main__.py", line 9, in <module>
  File "c:\users\admin\appdata\local\programs\python\python37-32\lib\site-packages\flask\cli.py", line 966, in main
    cli.main(prog_name="python -m flask" if as_module else None)
  File "c:\users\admin\appdata\local\programs\python\python37-32\lib\site-packages\flask\cli.py", line 586, in main
    return super(FlaskGroup, self).main(*args, **kwargs)
  File "c:\users\admin\appdata\local\programs\python\python37-32\lib\site-packages\click\core.py", line 717, in main
    rv = self.invoke(ctx)
  File "c:\users\admin\appdata\local\programs\python\python37-32\lib\site-packages\click\core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "c:\users\admin\appdata\local\programs\python\python37-32\lib\site-packages\click\core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "c:\users\admin\appdata\local\programs\python\python37-32\lib\site-packages\click\core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "c:\users\admin\appdata\local\programs\python\python37-32\lib\site-packages\click\core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "c:\users\admin\appdata\local\programs\python\python37-32\lib\site-packages\click\decorators.py", line 17, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "c:\users\admin\appdata\local\programs\python\python37-32\lib\site-packages\flask\cli.py", line 426, in decorator
    return __ctx.invoke(f, *args, **kwargs)
  File "c:\users\admin\appdata\local\programs\python\python37-32\lib\site-packages\click\core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "c:\users\admin\appdata\local\programs\python\python37-32\lib\site-packages\flask_migrate\cli.py", line 31, in init
    _init(directory, multidb)
  File "c:\users\admin\appdata\local\programs\python\python37-32\lib\site-packages\flask_migrate\__init__.py", line 96, in wrapped
    f(*args, **kwargs)
  File "c:\users\admin\appdata\local\programs\python\python37-32\lib\site-packages\flask_migrate\__init__.py", line 126, in init
    directory = current_app.extensions['migrate'].directory
KeyError: 'migrate'

I'm really unsure as to what I've done wrong, any help would be greatly appreciate it. Here is the python script I have at the moment:

import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

basedir = os.path.abspath(os.path.dirname(__file__))

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir,'data.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)
migrate = Migrate()
migrate.init_app(app, db)



class Puppies(db.Model):

    __tablename__ = 'Puppies'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Text)
    toys = db.relationship('Toy', backref='Puppies', lazy='dynamic') #Connects to the Toy model (the class below) | connects the puppy to many toys | will return list of toys
    owner = db.relationship('Owner', backref='Puppies', uselist=False) #uselist=False will ensure it doesn't bring a list of items, it will return 1.

    def __init__(self,name):
        self.name = name

    def __repr__(self):
        if self.owner:
            return f"Puppy Name: {self.name} | Owner: {self.owner.name}"
        else:
            return f"Puppy Name: {self.name} | The puppy currently has no owner."

    def report_toys(self):
        print("Here are my toys:")
        for toy in self.toys:
            print(toy.item_name)


class Toy(db.Model):

    __tablename__ = 'Toys'

    id = db.Column(db.Integer, primary_key=True)
    item_name = db.Column(db.Text)
    puppies_id = db.Column(db.Integer, db.ForeignKey(Puppies.id)) #this will get the id from the Puppies table (the above class)

    def __init__(self, item_name, puppies_id):
        self.item_name = item_name
        self.puppies_id = puppies_id


class Owner(db.Model):

    __tablename__ = 'Owners'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Text)
    puppies_id = db.Column(db.Integer, db.ForeignKey(Puppies.id)) #this will get the id from the Puppies table

    def __init__(self, name, puppies_id):
        self.name = name
        self.puppies_id = puppies_id
Kryton
  • 95
  • 1
  • 5
  • Try `migrate = Migrate(app, db)` instead of `migrate.init_app(app,db)`. Although i am not quite sure if that will work. Dont see any problems with the above code tbh. – prajwal k Hebbar Mar 30 '20 at 14:36
  • @prajwalkHebbar I've tried that as well and it doesn't work either. – Kryton Mar 30 '20 at 15:14
  • What is the name of your Python script, and what is the value of your FLASK_APP environment variable? – Miguel Grinberg Mar 31 '20 at 09:39
  • If you will use `migrate.init_app(app,db)` then ensure that you have restructured your application to use a factory function. Otherwise, I suggest you update your `migrate` variable to `migrate = Migrate(app)`. Currently, you only have `migrate = migrate()`. – Gitau Harrison Oct 23 '20 at 05:48
  • Also, it is an unfortunate inconsistency that in some instances such as in a `db.relationship()` call, the model is referenced by the model class, which typically starts with an uppercase character, while in other cases such as this `db.ForeignKey()` declaration, a model is given by its database table name, for which SQLAlchemy automatically uses lowercase characters. So, you can consider to use `db.ForeignKey(puppies.id)` instead of `db.ForeignKey(Puppies.id)` – Gitau Harrison Oct 23 '20 at 05:50

1 Answers1

2

The error is obviously a flask db. Hoping that you have imported flask-migrate and flask-sqlalchemy, the way you have registered flask-migrate in __init__.py is incorrect.

Case 1:

If you are using an application factory in you application, then you need to use migrate.init_app(app, db). So your __init__.py will look as such:

from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app.config.from_object(Config)

db = SQLAlchemy()
migrate = Migrate()

def create_app(config_class=Config):
    app = Flask(__name__)
    app.config.from_object(config_class)

    db.init_app(app)
    migrate.init_app(app, db)
    # ...

Above, your factory function is create_app().

Case 2:

If you are not using a factory function, as in your script, then do not use migrate.init_app(app, db). Rather, keep your __init__.py simple enough:

from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app.config.from_object(Config)

db = SQLAlchemy(app)
migrate = Migrate(app, db)

# ...

With either of these, you can run you migrations:

$ flask db init
$ flask db migrate -m '<your table>'
Gitau Harrison
  • 3,179
  • 1
  • 19
  • 23