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

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

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

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

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

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

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

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

4b9b3361

Ответ 1

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

Где вы боретесь - в SQLAlchemy.

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

#!/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 есть таблица с именем "users".

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

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

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

Ответ 2

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

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

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

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

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

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

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

Ответ 3

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

Я использовал Flask-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

Файлы заметок:

конф/xxx.py

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

SQLALCHEMY_DATABASE_URI = 'mysql://username:[email protected]:port/db_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

имя_приложения /database.py

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

APP_NAME/модели /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.

Я предполагаю, что у вас будет каталог views/ в дополнение к этому.

Ответ 4

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

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="[email protected]", user=User(name="foo")))
session.commit()

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

Обратитесь SqlAlchemy-Automap для получения более подробной информации и более сложных способов использования

Ответ 5

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

flask-sqlacodegen  mysql://username:[email protected]:port/db_name --schema yourschema --tables table1,table2 --flask

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

Ответ 6

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

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="""[email protected]'!""", 
                 host='host.com', 
                 database='database_name')

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

Ответ 7

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

"""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()

Ответ 8

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