vendredi 4 décembre 2015

Flask-SQLAlchemy multiple databases creation

I have problems creating databases for my Flask-based RESTful server.

What I want to achieve is having one database for users-storage, one for registration requests and one for universities; the former needs to have a relationship one-to-one with the latter, and the latter needs to have a lists of users registered in that university.

Here's some code

settings.py - (configurations, etc.)

import os

basedir = os.path.abspath(os.path.dirname(__file__)) + "/server/databases"


class Config:
    DEBUG = False
    TESTING = False
    SECRET_KEY = '<it's secret>'
    DATABASE_KEYS = ['users', 'registrations', 'universities']
    SQLALCHEMY_TRACK_MODIFICATIONS = True
    SQLALCHEMY_DATABASE_URI = None
    SQLALCHEMY_BINDS = {
        'users': 'sqlite:///' + os.path.join(basedir, 'users/users.db'),
        'registrations': 'sqlite:///' + os.path.join(basedir, 'registrations/registrations.db'),
        'universities': 'sqlite:///' + os.path.join(basedir, 'universities/universities.db')
    }
    SQLALCHEMY_MIGRATE_REPO = {
        'users': os.path.join(basedir, 'users/db_repo'),
        'registrations': os.path.join(basedir, 'registrations/db_repo'),
        'universities': os.path.join(basedir, 'universities/db_repo.db')
    }


class DevelopmentConfig(Config):
    DEBUG = True


class TestingConfig(Config):
    TESTING = True

server/__init__.py - (engines/sessions configuration)

from flask import Flask
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

__all__ = [ "routes", "models", "requests", "registration", "activation" ]

server = Flask(__name__)
server.config.from_object('settings.DevelopmentConfig')

databases = server.config.get('SQLALCHEMY_BINDS')
engines   = {}
sessions  = {}
bases     = {}

for key in databases:
    engines[key]  = create_engine(databases[key])
    sessions[key] = scoped_session(sessionmaker(autocommit=False,
                                                autoflush=False,
                                                bind=engines[key]))
    bases[key] = declarative_base()
    bases[key].query = sessions[key].query_property()

from server import routes, models, requests, JSON_responses
from server import registration

server/models.py - (database models) from server import bases from sqlalchemy import Column, Integer, String, ForeignKey, Boolean from sqlalchemy.orm import relationship

# Modello Utente
class User(bases['users']):
    __bind_key__ = 'users'
    __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    nickname   = Column(String(20), unique=True)
    password   = Column(String(64), unique=True) # Salt-hashed password SHA256
    saltpass   = Column(String(20), unique=True) # Salt 20 characters
    university = Column(Integer, ForeignKey('university.id'))
    email      = Column(String(50), unique=True)
    gender     = Column(Boolean)
    activated  = Column(Boolean)

    def __repr__(self):
        return '<User %r>' % self.nickname


class Registration(bases['registrations']):
    __bind_key__ = 'registrations'
    __tablename__ = 'registration'

    id = Column(Integer, primary_key=True)
    token   = Column(String(205), unique=True)
    user_id = Column(Integer, ForeignKey('user.id'))

    def __repr__(self):
        return '<Registration %r>' % self.token


class University(bases['universities']):
    __bind_key__ = 'universities'
    __tablename__ = 'university'

    id = Column(Integer, primary_key=True)
    name   = Column(String(60), unique=True)
    city   = Column(String(30))
    domain = Column(String(30), unique=True)
    users  = relationship('User', backref='user')
    suggestion = Column(String(30))

    def __init__(self, name, city, domain, suggestion):
        self.name       = name
        self.city       = city
        self.domain     = domain
        self.suggestion = suggestion

    def __repr__(self):
        return '<University %r>' % self.name

I have this script to create all the databases: dbs_create.py

import os.path
import server.models
from server import bases, engines
from settings import Config
from migrate.versioning import api

# Itera sui database e crea il version control per le migrazioni
for key in Config.DATABASE_KEYS:
    # Crea i metadati dei database
    bases[key].metadata.create_all(bind=engines[key])

    # Se il path non esiste, crea nuovo version control
    if not os.path.exists(Config.SQLALCHEMY_MIGRATE_REPO[key]):
        api.create(Config.SQLALCHEMY_MIGRATE_REPO[key], 'Database Repository')
        api.version_control(Config.SQLALCHEMY_BINDS[key],
                            Config.SQLALCHEMY_MIGRATE_REPO[key])
    # Se il path esiste, fa un check sulle versioni
    else:
        api.version_control(Config.SQLALCHEMY_BINDS[key],
                            Config.SQLALCHEMY_MIGRATE_REPO[key],
                            api.version(Config.SQLALCHEMY_MIGRATE_REPO[key]))

Now when i do ./dbs_create.py I get this error:

sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'user.university' could not find table 'university' with which to generate a foreign key to target column 'id'

So, it seems it doesn't find the 'university' table from the university database.

How can I fix this? :)

Aucun commentaire:

Enregistrer un commentaire