Как построить приложение колбы вокруг уже существующей базы данных?


у меня уже есть существующая база данных, которая имеет много столиков и много данных в MySQL. Я намерен создать Flask приложение и использовать sqlalchemy вместе с ним. Теперь я спросил на irc и посмотрел вокруг на google и попробовал следующие идеи:

первый Я sqlacodegen для создания моделей из моей DB. Но потом я немного растерялся и посмотрел еще немного. И я нашел этой.

этот выглядело как элегантное решение.

так второй, я переписал models.py по решению здесь и сейчас я еще больше запутался. Я ищу лучший подход для создания этого приложения колбы вместе с уже существующей БД.

Я заглянул в документацию колбы, но на самом деле не получил никакой помощи для проекта с уже существующей БД. Есть много хорошего материала для создания чего-то с нуля, создания БД и все такое. Но я действительно смущенный.

обратите внимание, что это мой первый день с Flask, но у меня есть опыт с Django, так что основные понятия не являются препятствием. Мне нужно некоторое руководство в выборе наилучшего подхода для этого usecase. Подробное объяснение было бы весьма полезно. По подробному я определенно не ожидаю, что кто-то напишет весь код и ложкой накормит меня на этом, но достаточно, чтобы я начал, то есть легко интегрировал эту БД в flask через sqlalchemy. Обратите внимание, что моя БД находится в MySQL.

8 52

8 ответов:

Я бы сказал, что ваш вопрос не имеет никакого отношения к колбе вообще. Например, у вас нет проблем с шаблонами, маршрутами, представлениями или декораторами входа в систему.

где вы боретесь на это в SQLAlchemy.

поэтому мое предложение-игнорировать колбу на некоторое время и сначала привыкнуть к SQLAlchemy. Вам нужно привыкнуть к существующей базе данных и как получить к ней доступ из SQLAlchemy. Используйте некоторые инструменты документации MySQL, чтобы найти свой путь вокруг этого. Начнем с чего-то вроде это (обратите внимание, что это не имеет ничего общего с колбой спросить всех ... пока):

#!/usr/bin/python
# -*- mode: python -*-

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///webmgmt.db', convert_unicode=True, echo=False)
Base = declarative_base()
Base.metadata.reflect(engine)


from sqlalchemy.orm import relationship, backref

class Users(Base):
    __table__ = Base.metadata.tables['users']


if __name__ == '__main__':
    from sqlalchemy.orm import scoped_session, sessionmaker, Query
    db_session = scoped_session(sessionmaker(bind=engine))
    for item in db_session.query(Users.id, Users.name):
        print item

в строке "engine = " вам нужно указать свой путь к базе данных MySQL, чтобы SQLAlchemy нашел его. В моем случае я использовал уже существующую базу данных sqlite3.

в строке "class Users(Base) " вам нужно использовать одну из существующих таблиц в вашей базе данных MySQL. Я знал, что в моей базе данных sqlite3 есть таблица с именем "пользователи".

после этого момента SQLalchemy знает, как подключиться к вашему MySQL база данных и она знает об одной из таблиц. Теперь нужно добавить все остальные таблицы, которые вы заботитесь. Наконец, необходимо указать отношения к SQLalchemy. Здесь я имею в виду такие вещи, как один-к-одному, один-ко-многим, многие-ко-многим, родитель-ребенок и так далее. Веб-сайт SQLAlchemy содержит довольно длинный раздел об этом.

после строки "if __name__ == '__main__'" просто приходит какой-то тестовый код. Он будет выполнен, если я не импортирую свой скрипт python, а запускаю. Здесь вы видите, что я создаю сеанс БД и это для очень простого запроса.

Я предлагаю вам сначала прочитать о важных частях документации SQLAlchemy, например, описательное определение таблицы, модель отношений и способ запроса. Как только вы это узнаете, вы можете изменить последнюю часть моего примера в контроллер (например, используя Python yield способ) и написать представление, которое использует этот контроллер.

ключ к подключению ответа Хольгера к контексту колбы - это db.Model это declarative_base объект Base. Мне потребовалось время, чтобы заметить эту важную фразу в колбу-с SQLAlchemy это документация

ниже приведены шаги, которые я использовал для моего приложения:

  1. начать db объект в обычной колбе - алхимический способ:db = SQLAlchemy(app). Обратите внимание, что вам нужно будет установить app.config['SQLALCHEMY_DATABASE_URI'] = 'connection_string' до этого.

  2. связать декларативные база к движку:db.Model.metadata.reflect(db.engine)

  3. затем вы можете легко использовать существующие таблицы (например. У меня есть таблица под названием здания):

    class Buildings(db.Model):
        __table__ = db.Model.metadata.tables['BUILDING']
    
        def __repr__(self):
            return self.DISTRICT
    

теперь ваш Buildings класс будет следовать существующей схеме. Вы можете попробовать dir(Buildings) в оболочке Python и увидеть все столбцы уже перечислены.

недавно я прошел через то же самое, с дополнительной проблемой связывания моделей между двумя базами данных.

Я Колба-SQLAlchemy и все, что мне нужно было сделать, это определить мои модели так же, как выглядели мои таблицы базы данных, и я смеялся. Мне было трудно понять, как именно должна выглядеть моя структура проекта.

мой проект был Restful API, и это то, что я закончил с:

conf/
    __init__.py
    local.py
    dev.py
    stage.py
    live.py
deploy/
    #nginx, uwsgi config, etc
middleware/
    authentication.py
app_name/
    blueprints/
        __init__.py
        model_name.py #routes for model_name
        ...
    models/
        __init.py
        model_name.py
    __init__.py
    database.py
tests/
    unit/
        test_etc.py
        ...
run.py

файлы Примечание:

conf/xxx.py

вот как мы говорим Flask-SQLAlchemy, к чему подключаться, плюс вы можете поместить сюда любые другие элементы конфигурации (например, местоположение журнала, отладочный конфиг и т. д.).

SQLALCHEMY_DATABASE_URI = 'mysql://username:password@host:port/db_name'

app_name/___init___.py

здесь я создаю свое приложение и инициализирую БД. Этот объект БД будет импортирован и использован во всем приложении (т. е. в моделях, тестах и т. д.). Я также устанавливаю свой регистратор, инициализирую свои API и схемы элементов и подключаю свое промежуточное программное обеспечение здесь (не показано).

from app_name.database import db
from flask import Flask

def create_app(*args, **kwargs):
    env = kwargs['env']
    app = Flask(__name__)
    app.config.from_object('conf.%s' % env)
    db.init_app(app)
    return app

app_name/database.py

from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()

app_name/models/model_name.py

from services.database import db


class Bar(db.Model):

    __tablename__ = 'your_MySQL_table_name'

    id = db.Column('YourMySQLColumnName', db.Integer, primary_key=True)
    name = db.Column('WhateverName', db.String(100))
    foo = db.Column(db.ForeignKey('another_MySQLTableName.id'))

class Foo(db.Model):

    __tablename__ = 'another_MySQLTableName'

    id = db.Column('FooId', db.Integer, primary_key=True)
    ...

run.py

#! /usr/bin/env python

from app_name import create_app

app = create_app(env='local')

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

я использую run.py для запуска приложения локально, но я использую nginx + uWSGI для запуска приложения в среде dev/stage/live.

Я предполагаю, что вы будете иметь в дополнение к этому, хотя.

Я думаю, что самый простой способ использовать существующую базу данных с sqlalchemy-это использовать AutomapBase класса . Пример кода из docs выглядит следующим образом:

from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session
from sqlalchemy import create_engine

Base = automap_base()

# engine, suppose it has two tables 'user' and 'address' set up
engine = create_engine("sqlite:///mydatabase.db")

# reflect the tables
Base.prepare(engine, reflect=True)

# mapped classes are now created with names by default
# matching that of the table name.
User = Base.classes.user
Address = Base.classes.address

session = Session(engine)

# rudimentary relationships are produced
session.add(Address(email_address="foo@bar.com", user=User(name="foo")))
session.commit()

# collection-based relationships are by default named
# "<classname>_collection"
print (u1.address_collection)

см. SqlAlchemy-Automap для деталей и более сложных применений

Я пытаюсь использовать autogenerated, но ничего не работает или я не мог запустить его. Когда я ищу генерировать код с помощью sqlacodegen я нахожу https://github.com/ksindi/flask-sqlacodegen, Вы можете создать код просто

flask-sqlacodegen  mysql://username:password@host:port/db_name --schema yourschema --tables table1,table2 --flask

Я пробовал, и он отлично работает

Это альтернативный способ настроить путь двигателя, описанный в ответе Хольгера. Удобно, если в вашем имени пользователя или пароле есть специальные символы.

from sqlalchemy.engine.url import URL
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base

engine_URL = URL('mssql+pymssql',
                 username='DOMAIN\USERNAME', 
                 password="""p@ssword'!""", 
                 host='host.com', 
                 database='database_name')

engine = create_engine(engine_URL)
Base = declarative_base()
Base.metadata.reflect(engine)

Это решение работало для меня

"""Example for reflecting database tables to ORM objects

This script creates classes for each table reflected
from the database.

Note: The class names are imported to the global namespace using
the same name as the tables. This is useful for quick utility scripts.
A better solution for production code would be to return a dict
of reflected ORM objects.
"""

from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base


def reflect_all_tables_to_declarative(uri):
"""Reflects all tables to declaratives

Given a valid engine URI and declarative_base base class
reflects all tables and imports them to the global namespace.

Returns a session object bound to the engine created.
"""

# create an unbound base our objects will inherit from
Base = declarative_base()

engine = create_engine(uri)
metadata = MetaData(bind=engine)
Base.metadata = metadata

g = globals()

metadata.reflect()

for tablename, tableobj in metadata.tables.items():
    g[tablename] = type(str(tablename), (Base,), {'__table__' : tableobj })
    print("Reflecting {0}".format(tablename))

Session = sessionmaker(bind=engine)
return Session()


# set to database credentials/host
CONNECTION_URI = "postgres://..."

session = reflect_all_tables_to_declarative(CONNECTION_URI)

# do something with the session and the orm objects
results = session.query(some_table_name).all()

перегонный куб (инструмент за колбой-sqlalchemy) может быть настроен для игнорирования таблиц. Конфигурация не слишком сложна для настройки. смотрите: https://gist.github.com/utek/6163250