Search code examples
pythonflaskflask-sqlalchemypymysqlflask-script

Troubles with MySQL, SQLAlchemy, Flask, and flask.ext.script -- create_all() doesn't create tables


I am not able to create tables when I do the following in my virtualenv:

(plasma) $ python checkup_web.py shell
> from app import db 
> db.create_all()

There is no error message thrown at all. Here's the structure of my project:

root
---app
------__init__.py
------models.py
------[various blueprints]
---checkup_web.py
---config.py

I can include more code if necessary, but I believe that these are the important files for consideration:

1) checkup_web.py

#!/usr/bin/env python
import os
from app import create_app, db
from flask.ext.script import Manager

app = create_app(os.getenv('FLASK_CONFIG') or 'default')
manager = Manager(app)


if __name__ == '__main__':
    manager.run()

2) config.py

import os

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY')


class DevelopmentConfig(Config):
    DEBUG = True
    SECRET_KEY = os.environ.get('SECRET_KEY') or 't0p s3cr3t'
    SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \
        'mysql+pymysql://root:root_password@localhost/checkup_db'

class TestingConfig(Config):
    TESTING = True
    SECRET_KEY = 'secret'


class ProductionConfig(Config):
    pass


config = {
    'development': DevelopmentConfig,
    'testing': TestingConfig,
    'production': ProductionConfig,
    'default': DevelopmentConfig
}

3) app/__init__.py

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from config import config

db = SQLAlchemy()

def create_app(config_name):
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    db.init_app(app)    

    from .families import families as families_blueprint
    app.register_blueprint(families_blueprint)

    from .patients import patients as patients_blueprint
    app.register_blueprint(patients_blueprint)

    from .doctors import doctors as doctors_blueprint
    app.register_blueprint(doctors_blueprint)

    from .conversations import conversations as conversations_blueprint
    app.register_blueprint(conversations_blueprint)

    from .appointments import appointments as appointments_blueprint
    app.register_blueprint(appointments_blueprint)

    return app

4) app/models.py (not sure if I'm doing anything wrong here - first time using SQLAlchemy)

from datetime import datetime
from . import db

family_2_doc = db.Table('family_2_doc',
    db.Column('family_id', db.Integer, db.ForeignKey('families.id')),
    db.Column('doctor_id', db.Integer, db.ForeignKey('users.id'))
)

patient_2_doc = db.Table('patient_2_doc',
    db.Column('patient_id', db.Integer, db.ForeignKey('users.id')),
    db.Column('doctor_id', db.Integer, db.ForeignKey('users.id'))
)

class Family(db.Model):
    __tablename__ = 'families'
    id = db.Column(db.Integer, primary_key=True)
    street_address = db.Column(db.String(64))
    city = db.Column(db.String(64))
    zipcode = db.Column(db.String(64))
    country = db.Column(db.String(64))
    phone_number = db.Column(db.String(64))
    stripe_id = db.Column(db.String(64))
    billing_valid = db.Column(db.Boolean)
    num_relationships = db.Column(db.Integer)
    doctors = db.relationship('Doctor', secondary=family_2_doc,
        backref=db.backref('families', lazy='dynamic'), lazy='dynamic')
    patients = db.relationship('Patient', backref='family', lazy='dynamic')

class Clinic(db.Model):
    __tablename__ = 'clinics'
    id = db.Column(db.Integer, primary_key=True)
    street_address = db.Column(db.String(64))
    city = db.Column(db.String(64))
    zipcode = db.Column(db.String(64))
    country = db.Column(db.String(64))
    phone_number = db.Column(db.String(64))
    doctors = db.relationship('Doctor', backref='clinic', lazy='dynamic')
    admins = db.relationship('Admin', backref='clinic', lazy='dynamic')

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(64), unique=True, index=True)
    first_name = db.Column(db.String(64))
    last_name = db.Column(db.String(64))
    password_hash = db.Column(db.String(128))
    date_joined = db.Column(db.DateTime())
    discriminator = Column('type', String(50))
    __mapper_args__ = {'polymorphic_on': discriminator}

class Patient(User):
    __mapper_args__ = {'polymorphic_identity': 'patient'}
    dob = db.Column(db.String(64))
    relationship_to_creator = db.Column(db.Boolean) # is equal to 'creator' if patient is creator
    is_primary = db.Column(db.Boolean)
    street_address = db.Column(db.String(64))
    city = db.Column(db.String(64))
    zipcode = db.Column(db.String(64))
    country = db.Column(db.String(64))
    phone_number = db.Column(db.String(64))
    profile_pic = db.Column(db.String(64))
    doctors = db.relationship('Doctor', secondary=patient_2_doc,
        backref=db.backref('patients', lazy='dynamic'), lazy='dynamic')
    appointments = db.relationship('Appointment', backref='patient', lazy='dynamic')

class Doctor(User):
    __mapper_args__ = {'polymorphic_identity': 'doctor'}
    practice_street_address = db.Column(db.String(64))
    practice_city = db.Column(db.String(64))
    practice_zipcode = db.Column(db.String(64))
    practice_country = db.Column(db.String(64))
    practice_phone_number = db.Column(db.String(64))
    personal_street_address = db.Column(db.String(64))
    personal_city = db.Column(db.String(64))
    personal_zipcode = db.Column(db.String(64))
    personal_country = db.Column(db.String(64))
    personal_phone_number = db.Column(db.String(64))
    schedule_start = db.Column(db.DateTime())
    schedule_end = db.Column(db.DateTime())
    appointments = db.relationship('Appointment', backref='doctor', lazy='dynamic')    

class Admin(User):
    __mapper_args__ = {'polymorphic_identity': 'admin'}

class Appointment(db.Model):
    __tablename__ = 'appointments'
    is_subscriber = db.Column(db.Boolean)
    start = db.Column(db.DateTime())
    end = db.Column(db.DateTime())
    notes = db.Column(db.Text())

class Message(db.Model):
    __tablename__ = 'messages'
    body = db.Column(db.Text())
    timestamp = db.Column(db.DateTime())
    user1_id = db.Column(db.Integer) # smaller id
    user2_id = db.Column(db.Integer) # larger id
    user_sender_id = db.Column(db.Integer)
    message_number = db.Column(db.Integer)

class Conversation(db.Model):
    __tablename__ = "conversations"
    user1_id = db.Column(db.Integer) # smaller id
    user2_id = db.Column(db.Integer) # larger id
    total_messages = db.Column(db.Integer)

Unfortunately despite not throwing any errors, the call to create_all() does not produce any tables in my mysql database:

$ mysql -u root -p
Password: *********

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| channels           |
| checkup_db         |
| comments           |
| media              |
| mysql              |
| notifications      |
| performance_schema |
| reactions          |
| sessions           |
| shares             |
| sparks             |
| test               |
| users              |
+--------------------+
14 rows in set (0.01 sec)

mysql> use checkup_db
Database changed

mysql> show tables;
Empty set (0.00 sec)

I'd very much appreciate any thoughts/advice!


Solution

  • I think the problem is that the models are not imported. When you do:

    from app import db
    

    you trigger the creation of the SQLAlchemy object, but the models are not registered. So then db.create_all() thinks there are no tables to create.

    If you import the models, then they are going to register themselves with the database object. This may seem odd, because you don't really need to use the models directly, but it is the only way the database object learns about them.