Подключите шаблон Flask SQLAlchemy к существующей базе данных - Hybrid Alembi c и Automap - PullRequest
0 голосов
/ 29 мая 2020

Я подключаю приложение Flask к существующей базе данных MySQL. Я позволяю функции SQLAlchemy db.create () создавать и управлять новой таблицей USER в обычном режиме - см. Это в файле models.py ниже. Таким образом, SQLAlchemy может управлять им с помощью своих настроек ORM и Alembi c. У меня вопрос, какая дополнительная конфигурация необходима, чтобы позволить SQLAlchemy теперь автоматически отображать другие таблицы и поля в той же базе данных MySQL - без воссоздания этих метаданных таблицы в моем models.py и без запроса python для управления таблицами MySQL?

Думаю, мне нужен гибрид, который добавляет отраженные таблицы "Base" автомата в соответствии с моей конфигурацией Models.py ... но до сих пор я получаю ошибку при каждой конфигурации, которую я пытаюсь. При необходимости запрашивайте дополнительные конфигурации, и я отправлю их (run.py, routes.py et c.).

Я просмотрел https://docs.sqlalchemy.org/en/13/orm/extensions/automap.html, https://www.blog.pythonlibrary.org/2010/09/10/sqlalchemy-connecting-to-pre-existing-databases/ и аналогичная документация по гибридам, но ни одна из них не создала рабочую конфигурацию.

Мне нужен опытный взгляд на лучший подход к использованию ORM SQLAlchemy с помощью моего bootstrap шаблона, а также мне нужны несколько строк синтаксиса, которые реализуют его, как того требует мой подход к продвижению кода. Спасибо!

from sqlalchemy.ext.automap import automap_base

Base = automap_base()
Base.prepare(db.engine, reflect=True) # These lines don't give an error when added to Models.py

Country = Base.classes.country #This is one of the tables in the existing database

Ошибка определения таблицы Country со следующей трассировкой -

File "F:\Users\etilley\Documents\GitHub\Dashboard\run.py", line 21, in <module>
app = create_app(config_mode)
File "F:\Users\etilley\Documents\GitHub\Dashboard\app\__init__.py", line 81, in create_app
register_blueprints(app)
File "F:\Users\etilley\Documents\GitHub\Dashboard\app\__init__.py", line 24, in register_blueprints
module = import_module('app.{}.routes'.format(module_name))
File "F:\Users\etilley\Anaconda3\lib\importlib\__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "F:\Users\etilley\Documents\GitHub\Dashboard\app\base\routes.py", line 18, in <module>
from app.base.models import User, Country
File "F:\Users\etilley\Documents\GitHub\Dashboard\app\base\models.py", line 78, in <module>
Base.prepare(db.engine, reflect=True)
File "F:\Users\etilley\Anaconda3\lib\site-packages\flask_sqlalchemy\__init__.py", line 937, in engine
return self.get_engine()
File "F:\Users\etilley\Anaconda3\lib\site-packages\flask_sqlalchemy\__init__.py", line 946, in get_engine
app = self.get_app(app)
File "F:\Users\etilley\Anaconda3\lib\site-packages\flask_sqlalchemy\__init__.py", line 982, in get_app
'No application found. Either work inside a view function or push'
RuntimeError: No application found. Either work inside a view function or push an application context. See http://flask-sqlalchemy.pocoo.org/contexts/.

__init__.py

from flask import Flask, url_for
from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemy
from importlib import import_module
from logging import basicConfig, DEBUG, getLogger, StreamHandler
from os import path

db = SQLAlchemy()

login_manager = LoginManager()

def register_extensions(app):
    db.init_app(app)
    login_manager.init_app(app)

def register_blueprints(app):
    for module_name in ('base', 'home'):
        module = import_module('app.{}.routes'.format(module_name))
        app.register_blueprint(module.blueprint)

def configure_database(app):

    @app.before_first_request
    def initialize_database():
        db.create_all()

    @app.teardown_request
    def shutdown_session(exception=None):
        db.session.remove()

def configure_logs(app):
    # soft logging

def apply_themes(app):
    (Using Bootstrap 4 Theme)

def create_app(config, selenium=False):
    app = Flask(__name__, static_folder='base/static')
    app.config.from_object(config)
    if selenium:
        app.config['LOGIN_DISABLED'] = True
    register_extensions(app)
    register_blueprints(app)
    configure_database(app)
    configure_logs(app)
    apply_themes(app)
    return app

Models.py

from flask_login import UserMixin
from sqlalchemy import Binary, Column, Integer, String
from sqlalchemy.ext.automap import automap_base

# from sqlalchemy.dialects import mysql
# from sqlalchemy.dialects.mysql import VARCHAR, TEXT

from app import db, login_manager

from app.base.util import hash_pass

class User(db.Model, UserMixin):

    __tablename__ = 'User'

    id = Column(Integer, primary_key=True)
    username = Column(String(22), unique=True, nullable=False)
    email = Column(String(120), unique=True, nullable=False)
    password = Column(Binary)

(User table Flask_login logic removed ...)

Base = automap_base()
Base.prepare(db.engine, reflect=True) # These lines don't give an error when added to Models.py

Country = Base.classes.country  #This line throws the error traced above

Config.py

import os
from   os import environ

class Config(object):

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

    SECRET_KEY = 'keysecret'

    # This will create a file in <app> FOLDER
    # SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'database.db')
    user = "user"
    passw = "password"
    host = "localhost"
    database = "database"
    port = 3306

    #mysql.connector.connect - removed a couple of default connections - FYI
    # db = create_engine('mysql+mysqldb://' + user + ':' + passw + '@' + host + ':' + str(port) + '/' + database , echo=False)
    #SQLALCHEMY_DATABASE_URI = 'mysql+mysqlconnector+connect://' + user + ':' + passw + '@' + host + ':' + str(port) + '/' + database

    SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://' + user + ':' + passw + '@' + host + ':' + str(port) + '/' + database

    SQLALCHEMY_TRACK_MODIFICATIONS = False
    SQLALCHEMY_ECHO = True
...