2013-07-15 12 views
49

Mam już istniejącą bazę danych, która ma wiele tabel i wiele danych w MySQL. Zamierzam stworzyć aplikację Flask i używać sqlalchemy wraz z nią. Teraz poprosiłem na IRC i rozejrzał się na google i próbowałem następujące pomysły:Jak zbudować aplikację kolby wokół już istniejącej bazy danych?

Pierwszy użyłem sqlacodegen do generowania modeli z mojego DB. Ale potem trochę się zdezorientowałem i wyglądałem trochę. I znalazłem this.

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

Tak Po drugie, przepisałem na nowo moje models.py zgodnie z rozwiązaniem tam, a teraz jestem jeszcze bardziej zdezorientowany. Szukam najlepszego podejścia do budowy tej aplikacji kolby wraz z już istniejącym DB.

Zajrzałem do dokumentacji kolby, ale nie dostałem żadnej pomocy dla projektu z już istniejącą bazą danych. Jest dużo dobrych rzeczy do stworzenia czegoś od zera, tworzenia bazy danych i wszystkiego. Ale jestem naprawdę zdezorientowany.

Należy pamiętać, że jest to 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. Szczegółowo nie oczekuję, że ktoś napisze cały kod i łyżka mnie nakarmi, ale na tyle, żeby zacząć, integruje to db bez problemu z flask przez sqlalchemy. Uwaga: mój DB jest w MySQL.

Odpowiedz

66

Powiedziałbym, że twoje pytanie w ogóle nie ma nic wspólnego z kolbą. Na przykład nie masz problemu z szablonami, trasami, widokami lub dekoratorami logowania.

Gdzie walczysz o to w SQLAlchemy.

Więc moją propozycją jest zignorowanie Flask przez chwilę i najpierw przyzwyczaić się do SQLAlchemy. Musisz przyzwyczaić się do istniejącej bazy danych i uzyskać do niej dostęp z SQLAlchemy. Użyj narzędzia do dokumentacji MySQL, aby znaleźć sposób na obejście tego problemu. Początek z czymś takim (zauważ, że to nie ma nic wspólnego z kolbą zapytać ... wszystko 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 =” trzeba podać ścieżkę do bazy danych MySQL, dzięki czemu SQLAlchemy znajduje to. W moim przypadku użyłem istniejącej bazy danych sqlite3.

W linii "class Users(Base)" należy 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 momencie SQLalchemy wie, jak połączyć się z bazą danych MySQL i wie o jednej z tabel. Musisz teraz dodać wszystkie pozostałe tabele, na których Ci zależy. Na koniec musisz podać relacje do SQLalchemy. Mam tu na myśli rzeczy typu jeden do jednego, jeden do wielu, wiele do wielu, układ macierzysty i tak dalej. Strona internetowa SQLAlchemy zawiera dość obszerną sekcję na ten temat.

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

Moja propozycja jest taka, że ​​najpierw przeczytać o najważniejszych częściach dokumentacji sqlalchemy za, na przykład opisową definicję tabeli, model relacji i jak kwerendy. Gdy już się o tym dowiesz, możesz zmienić ostatnią część mojego przykładu w kontroler (np. Używając metody Pythona yield) i napisać widok, który używa tego kontrolera.

+0

Wielkie dzięki za opisową odpowiedź. Czytałem dokumentację sqlalchemy, a zwłaszcza część relacji. Wdrożyłem twoje rozwiązanie do tej pory, a twoja odpowiedź wydaje się dawać impuls z punktu, w którym czułam się zablokowana, ale zastanawiam się, w jaki sposób powinienem to zintegrować z kolbą? Chodzi mi o to, że w dokumentach z kolbą dużo było o 'init_db()', które miało na celu stworzenie bazy danych. A co z tą sprawą? Dzięki, agian. :) –

+1

+2 gdybym mógł - bardzo dobra odpowiedź! –

+0

Dziękuję ci na zawsze, działa to jak czar. – Rohmer

15

Niedawno zrobiłem to samo, z dodatkowym wyzwaniem związania 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, w jaki wyglądały moje tabele baz danych, a ja nie śmiałem się. Trudne było ustalenie, jak powinna wyglądać struktura mojego projektu.

Mój projekt był spokojny API, a to, co skończyło się z:

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 powiedz Flask-SQLAlchemy, z czym się połączyć, plus możesz umieścić tutaj wszystkie inne elementy konfiguracji (takie jak lokalizacja dziennika, konfiguracja debugowania itp.).

SQLALCHEMY_DATABASE_URI = 'mysql://username:[email protected]:port/db_name' 

nazwa_aplikacji/___ init___.py

To gdzie tworzę moją aplikację i inicjalizacji db. Ten obiekt db zostanie zaimportowany i użyty w całej aplikacji (tj. W modelach, testach itp.). Ustawiam również mój program rejestrujący, inicjuję interfejsy API i plany i dołączam tutaj oprogramowanie pośrednie (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 

nazwa_aplikacji/database.py

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

nazwa_aplikacji/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() 

używam run.py uruchomić aplikację lokalnie, ale używam nginx + uWSGI uruchomić aplikację w etapie/dev/środowisk żywych.

Zgaduję będziesz mieć katalog views/ tam oprócz tego jednak.

+0

dlaczego "modele /" oddzielnie? Czy "model.py" w "aplikacji" nie jest wystarczający? –

+1

Nie, mam wiele modeli, więc podzieliłem je na osobne pliki. –

+0

Awesome! Dzięki pęczku – drewski

32

Kluczem do połączenia odpowiedzi Holgera z kontekstem kolby jest to, że db.Model jest obiektem o numerze declarative_base, takim jak Base. Zajęło mi trochę czasu, aby zauważyć to ważne zdanie w kolbie-sqlalchemy na documentation

Poniżej przedstawiono kroki I wykorzystywane do mojego app:

  1. rozpoczynają db obiekt w zwykłej kolby-alchemia sposób: db = SQLAlchemy(app).Uwaga: musisz wcześniej ustawić app.config['SQLALCHEMY_DATABASE_URI'] = 'connection_string'.

  2. wiążą deklaratywna podstawa do silnika: db.Model.metadata.reflect(db.engine)

  3. Następnie można użyć istniejących tabel łatwo (np Mam tabeli zwane budynków.):

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

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

+0

Dziękuję .. bardzo pomocna i działająca !! –

+1

Wgląd w to, że "db.Model jest obiektem deklaratywnym, jak baza", właśnie zapisał mój dzień. Dopóki tego nie przeczytałem, nie miałem pojęcia, jak to zrobić w alchemii butelkowej. Dziękuję Ci. – ISONecroMAn

+1

, jeśli chodzi o Flask-sqlalchemy db.Model jest analogiczny do Base. db.session jest analogiczny do sesji. – ISONecroMAn

1

Jest to alternatywny sposób ustawienia ścieżki silnika opisanej w odpowiedzi Holgera. Wygodnie, 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="""[email protected]'!""", 
       host='host.com', 
       database='database_name') 

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

Myślę, że najprostszym sposobem, aby użyć istniejącej bazy danych z SQLAlchemy jest użycie AutomapBase klasę. Próbkę kodu 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) 

Patrz SqlAlchemy-Automap po szczegóły i bardziej skomplikowanych zastosowań

1

To rozwiązanie pracował 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() 
2

próbuję użyć wygenerowany automatycznie, ale nic nie działa albo ja nie mógł tego uruchomić. Kiedy poszukiwania wygenerować kod za pomocą sqlacodegen znajdę https://github.com/ksindi/flask-sqlacodegen można wygenerować kod tylko

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

próbowałem i działa idealnie

+0

Próbuję poniżej ciąg połączenia z terminalu, aby połączyć się z moją lokalną instancją serwera sql flask-sqlacodegen --outfile models.py mssql: // użytkownik: hasło @ localhost/db_name Pojawia się błąd "Źródło danych nie znaleziono" i nie określono domyślnego sterownika. Jestem unixodbc, FREETDS zainstalowane i zdolne do połączenia programowego i za pośrednictwem poleceń isql, tsql. –

0

alembic (narzędzie z tyłu kolby-SQLAlchemy) może być skonfigurowany tak, aby ignorować tabele. Konfiguracja nie jest trudna do skonfigurowania. zobacz: https://gist.github.com/utek/6163250

Powiązane problemy