2

I'm working on a flask application where I'm trying to isolate my unit tests. I'm using flask-sqlalchemy, and I'm trying to use the create_all and drop_all methods to clean my database after running a test.

However, it appears my create_all and drop_all methods do not actually create/drop the tables as the documentation states. I have my models imported in the application before calling create_all, like most other answers say.

This is the error I'm getting with the code below:

psycopg2.ProgrammingError: relation "tasks" does not exist

Here's my relevant code

/app.py

import os
import configparser

from flask import Flask
from src.router import router

from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

app = Flask(__name__)

if not os.path.exists(os.path.join(app.root_path, 'config.ini')):
    raise Exception(f'config.ini not found in the {app.root_path}')

config = configparser.ConfigParser()
config.read('config.ini')

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = config[os.environ['APP_ENV']]['DATABASE_URI']

app.register_blueprint(router)

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

if __name__ == "__main__":
    app.run()

/tests/test_router.py

from unittest import TestCase

from flask import Flask
from app import app, db
from src.models import Task

class TestRouter(TestCase):

    def setUp(self):
        db.create_all()

    def tearDown(self):
        db.drop_all()

    def test_adds_task(self):
        task = Task(task_id='task_1', name='my task')
        db.session.add(task)
        db.session.commit()

1 Answer 1

1

I think I was a little quick to post the question, but I hope this might help others come up with other ideas on how to troubleshoot a similar issue.

In my src/models.py file where I keep my models, you must make sure that your models are defined correctly. Since Flask-SQLAlchemy is a wrapper around the SQLAlchemy you must use the data types under the db object.

Essentially, I had my models defined as such:

class Task(db.Model):
    __tablename__ = 'tasks'

    id = Column(Integer, primary_key=True)
    task_id = Column(String)
    name = Column(String)
    created_at = Column(DateTime, default=datetime.datetime.now)

As you can see, I was inheriting from db.Model instead of the return value of declarative_base(). I also needed to add the db. in front of all the data types, including Column, Integer, String, Float, DateTime, relationship, and ForeignKey.

So, I was able to fix my issue by changing my model to something like:

class Task(db.Model):
    __tablename__ = 'tasks'

    id = db.Column(db.Integer, primary_key=True)
    task_id = db.Column(db.String)
    name = db.Column(db.String)
    created_at = db.Column(db.DateTime, default=datetime.datetime.now)

See: Documentation on declaring Flask-SQLAlchemy models

Sign up to request clarification or add additional context in comments.

1 Comment

That's odd given that the names under db mostly reference the very same SQLAlchemy constructs: "flask_sqlalchemy.SQLAlchemy gives you access to the following things: all the functions and classes from sqlalchemy and sqlalchemy.orm ..."

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.