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
.
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.
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:
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'
./ align = "left" / :
db.Model.metadata.reflect(db.engine)
-
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.
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/
.
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
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
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)
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()
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
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