Jak zbudować aplikację flask wokół już istniejącej bazy danych?

Mam już istniejącą bazę danych, która ma wiele tabel i wiele danych w MySQL. Zamierzam stworzyć Flask aplikację i używać sqlalchemy wraz z nią. Teraz zapytałem się na irc i rozejrzałem się po google i wypróbowałem następujące pomysły:

Najpierw użyłem sqlacodegen do wygenerowania modeli z mojego DB. Ale potem byłem trochę zdezorientowany i spojrzałem trochę więcej. I znalazłem to .

To wyglądało jak eleganckie rozwiązanie.

Więc drugi , przepisałem moje models.py zgodnie z rozwiązaniem tam i teraz jestem jeszcze bardziej zdezorientowany. Szukam najlepszego podejścia do budowy tej aplikacji flask wraz z już istniejącym DB.

Zajrzałem do dokumentacji flask, ale tak naprawdę nie otrzymałem żadnej pomocy dla projektu z już istniejącym db. Jest wiele dobrych rzeczy do tworzenia czegoś od podstaw, tworzenia db i w ogóle. Ale jestem naprawdę zdezorientowany.

Należy pamiętać, że jego mój pierwszy dzień z Flask, ale mam doświadczenie z Django, więc podstawowe pojęcia nie są przeszkodą. Potrzebuję wskazówek w wyborze najlepszego podejścia do tego zastosowania. Szczegółowe wyjaśnienie byłoby bardzo mile widziane. Po szczegółach zdecydowanie nie oczekuję, że ktoś napisze cały kod i na tym mnie nakarmi, ale na tyle, żeby zacząć, czyli bezproblemowo zintegrować ten db z flask poprzez sqlalchemy. Uwaga mój DB jest w MySQL.

Author: AndreL, 2013-07-15

8 answers

Twoje pytanie nie ma nic wspólnego z kolbą. Na przykład nie masz problemu z szablonami, trasami, widokami lub dekoratorami logowania.

Gdzie walczysz jest w SQLAlchemy.

Więc moja sugestia to zignorować Flask na jakiś czas i przyzwyczaić się do SQLAlchemy pierwszy. Musisz przyzwyczaić się do istniejącej bazy danych i jak uzyskać do niej dostęp z SQLAlchemy. Użyj jakiegoś narzędzia dokumentacji MySQL, aby znaleźć drogę wokół tego. Początek z czymś takim (zauważ, że to nie ma nic wspólnego z kolbą zapytaj wszystkich ... jeszcze): {]}

#!/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

W wierszu "engine = " Musisz podać swoją ścieżkę do bazy danych MySQL, aby SQLAlchemy ją znalazł. W moim przypadku użyłem wcześniej istniejącej bazy danych SQLite3.

W wierszu "class Users(Base) " musisz użyć jednej z istniejących tabel w bazie danych MySQL. Wiedziałem, że moja baza danych sqlite3 ma tabelę o nazwie "użytkownicy".

Po tym punkcie SQLAlchemy wie, jak połączyć się z bazą danych MySQL i wie o jednej z tabel. Musisz teraz dodać wszystkie inne tabele, na które Ci zależy. Na koniec musisz określić relacje z SQLalchemy. Mam tu na myśli takie rzeczy jak jeden do jednego, jeden do wielu, wiele do wielu, rodzic-dziecko i tak dalej. Strona SQLAlchemy zawiera dość obszerną sekcję na ten temat.

Po linii "if __name__ == '__main__' " pojawia się jakiś kod testowy. Zostanie on wykonany, jeśli nie zaimportuję skryptu Pythona, ale uruchomię go. Tutaj widzisz, że tworzę sesję DB i jest to bardzo proste zapytanie.

Mój sugerujemy, aby najpierw przeczytać o ważnych częściach dokumentacji SQLAlchemy, na przykład o definicji tabeli opisowej, modelu relacji i sposobie zapytań. Gdy już to wiesz, możesz zmienić ostatnią część mojego przykładu w kontroler (np. używając metody yield Pythona) i napisać widok, który używa tego kontrolera.

 74
Author: HolgerSchurig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-19 07:12:35

Kluczem do połączenia odpowiedzi Holgera z kontekstem kolby jest to, że db.Model jest obiektem declarative_base podobnym do Base. Trochę mi zajęło zwrócenie uwagi na to ważne zdanie w dokumentacji flask-sqlalchemy

Poniżej znajdują się kroki, których użyłem dla mojej aplikacji:

  1. Inicjowanie obiektu {[4] } w zwykły sposób kolby-Alchemia: db = SQLAlchemy(app). Uwaga musisz wcześniej ustawić app.config['SQLALCHEMY_DATABASE_URI'] = 'connection_string'.

  2. / align = "left" / : db.Model.metadata.reflect(db.engine)

  3. Wtedy ty może łatwo korzystać z istniejących tabel (np. Mam tabelę nazwaną budynkami):

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

Teraz twoja klasa Buildings będzie podążać za istniejącym schematem. Możesz spróbować dir(Buildings) w powłoce Pythona i zobaczyć wszystkie kolumny już wymienione.

 37
Author: xysun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-19 07:17:59

Ostatnio przeszedłem przez to samo, z dodatkowym wyzwaniem łączenia modeli w dwóch bazach danych.

Użyłem Flask-SQLAlchemy i wszystko, co musiałem zrobić, to zdefiniować moje modele w taki sam sposób, jak moje tabele bazy danych wyglądały, i byłem daleko śmiejąc się. Trudno było mi ustalić, jak powinna wyglądać struktura mojego projektu.

Mój projekt był Restful API i oto, co znalazłem:

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

Pliki Uwaga:

Conf/xxx.py

W ten sposób mówimy Flask-SQLAlchemy, z czym się połączyć, dodatkowo możesz umieścić tutaj inne elementy konfiguracyjne (takie jak lokalizacja dziennika, konfiguracja debugowania itp.).

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

App_name/___init___.py

Tutaj tworzę swoją aplikację i inicjalizuję db. Ten obiekt db zostanie zaimportowany i użyty w całej aplikacji (np. w modelach, testach, itd.). Ustawiam również logger, inicjalizuję interfejsy API i plany oraz dołączam oprogramowanie pośrednie tutaj (nie pokazano).

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()
Aplikacja jest dostępna w wielu wersjach językowych, takich jak nginx + uWSGI, dev/stage I live.

Zgaduję, że oprócz tego będziesz miał tam katalog views/.

 17
Author: Chris McKinnel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-18 20:54:30

Myślę, że najprostszym sposobem użycia istniejącej bazy danych z sqlalchemy jest użycie klasy AutomapBase . Przykładowy kod z docs jest następujący:

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)

Zobacz SQLAlchemy-Automap Po szczegóły i bardziej skomplikowane zastosowania

 9
Author: droidmad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-22 19:02:29

Próbuję użyć autogenerated, ale nic nie działa lub nie mogłem go uruchomić. Kiedy szukam kodu przy użyciu sqlacodegen znajduję https://github.com/ksindi/flask-sqlacodegen , możesz wygenerować kod tylko

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

Próbowałem i działa idealnie

 3
Author: mcolak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-17 07:55:26

Jest to alternatywny sposób na ustawienie ścieżki silnika opisanej w odpowiedzi Holgera. Wygodne, jeśli w Nazwie użytkownika lub haśle znajdują się znaki specjalne.

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)
 1
Author: sequoia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-21 02:32:49

To rozwiązanie zadziałało dla mnie

"""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()
 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-07 14:05:44

Alembic (narzędzie znajdujące się za flask-sqlalchemy) można skonfigurować tak, aby ignorował tabele. Konfiguracja nie jest zbyt trudna do skonfigurowania. zobacz: https://gist.github.com/utek/6163250

 0
Author: Adam Greenhall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-27 21:28:07