UFO ET IT

이미 존재하는 데이터베이스를 중심으로 플라스크 애플리케이션을 구축하는 방법은 무엇입니까?

ufoet 2020. 11. 22. 20:58
반응형

이미 존재하는 데이터베이스를 중심으로 플라스크 애플리케이션을 구축하는 방법은 무엇입니까?


많은 테이블과 많은 데이터가있는 기존 데이터베이스가 이미 있습니다 MySQL. Flask을 만들고 sqlalchemy를 함께 사용 하려고 합니다. 이제 irc에 대해 물어보고 Google을 둘러보고 다음 아이디어를 시도했습니다.

우선 내가 사용 sqlacodegen을 내에서 모델을 생성합니다 DB. 그러나 나는 그것에 대해 조금 혼란스러워하고 좀 더 보았습니다. 그리고 나는 이것을 발견 했다 .

이것은 우아한 해결책처럼 보였습니다.

그래서 둘째 , 나는 models.py거기에 해결책에 따라 다시 썼고 이제는 더 혼란스러워졌습니다. 이미 존재하는 DB와 함께이 플라스크 앱을 구축하는 가장 좋은 방법을 찾고 있습니다.

플라스크 문서를 살펴 보았지만 이미 존재하는 db가있는 프로젝트에 대한 도움을받지 못했습니다. 무언가를 처음부터 만들고, db를 만드는 등의 좋은 것들이 많이 있습니다. 하지만 정말 혼란 스럽습니다.

를 사용한 첫날 Flask이지만을 사용한 경험이 Django있으므로 기본 개념은 장애물이 아닙니다. 이 사용 사례에 가장 적합한 접근 방식을 선택하려면 몇 가지 지침이 필요합니다. 자세한 설명을 주시면 감사하겠습니다. 자세히 설명하자면, 누군가가 모든 코드를 작성하고 숟가락으로 저에게 먹이를 줄 것으로 기대하지는 않지만 시작하기에 충분합니다 . 이 db를 flaskvia에 원활하게 통합하는 것입니다 sqlalchemy. 내 DB는 MySQL.


나는 당신의 질문이 플라스크와 전혀 관련이 없다고 말하고 싶습니다. 예를 들어 템플릿, 경로,보기 또는 로그온 데코레이터에 문제가 없습니다.

당신이 어려움을 겪는 곳은 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 =" 에서 SQLAlchemy가 찾을 수 있도록 MySQL 데이터베이스에 대한 경로를 제공해야합니다. 제 경우에는 기존 sqlite3 데이터베이스를 사용했습니다.

" class Users(Base)" 에서 MySQL 데이터베이스의 기존 테이블 중 하나를 사용해야합니다. 내 sqlite3 데이터베이스에 "users"라는 테이블이 있다는 것을 알고있었습니다.

이 시점 이후 SQLalchemy는 MySQL 데이터베이스에 연결하는 방법을 알고 테이블 중 하나에 대해 알고 있습니다. 이제 관심있는 다른 모든 테이블을 추가해야합니다. 마지막으로 SQLalchemy에 대한 관계를 지정해야합니다. 여기서는 일대일, 일대 다, 다 대다, 부모-자녀 등과 같은 것을 의미합니다. SQLAlchemy 웹 사이트에는 이에 대한 다소 긴 섹션이 있습니다.

" if __name__ == '__main__'" 줄 뒤에 테스트 코드가 표시됩니다. 파이썬 스크립트를 가져 오지 않고 실행하면 실행됩니다. 여기에서 제가 DB 세션을 생성 한 것을 볼 수 있으며 이는 매우 간단한 쿼리를위한 것입니다.

내 제안은 SQLAlchemy 설명서의 중요한 부분 (예 : 설명 테이블 정의, 관계 모델 및 쿼리 방법)에 대해 먼저 읽어 보는 것입니다. 이 사실을 알게되면 내 예제의 마지막 부분을 컨트롤러로 변경하고 (예 : Python의 yield메서드 사용) 해당 컨트롤러를 사용하는 뷰를 작성할 수 있습니다.


플라스크 컨텍스트에 홀가의 답변을 연결하는 열쇠는 점이다 db.ModelA는 declarative_base같은 오브젝트 Base. flask-sqlalchemy의 문서 에서이 중요한 문장을 알아 채는 데 시간이 걸렸습니다.

다음은 내 앱에 사용한 단계입니다.

  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 셸에서 시도 하고 이미 나열된 모든 열을 볼 수 있습니다 .


나는 최근에 두 개의 데이터베이스에 걸쳐 모델을 연결하는 추가적인 도전과 함께 같은 일을 겪었습니다.

저는 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

참고 파일 :

conf / xxx.py

이것이 Flask-SQLAlchemy에 연결할 대상을 알려주는 방법이며 여기에 다른 구성 항목 (로그 위치, 디버깅 구성 등)을 넣을 수 있습니다.

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

app_name / __ init__.py

여기에서 앱을 만들고 db를 초기화합니다. 이 db 개체는 전체 앱 (예 : 모델, 테스트 등)에서 가져 와서 사용됩니다. 로거를 설정하고 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로컬 응용 프로그램을 실행하는,하지만 난 dev에 / 무대 / 라이브 환경에서 응용 프로그램을 실행하기의 nginx + uWSGI를 사용합니다.

그래도 views/거기에 디렉토리가있을 것이라고 생각합니다 .


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="foo@bar.com", user=User(name="foo")))
session.commit()

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

자세한 내용과 더 복잡한 사용법은 SqlAlchemy-Automap참조하십시오.


I try to use autogenerated but nothing works or I couldn't run it. When I searching generate code using sqlacodegen I find https://github.com/ksindi/flask-sqlacodegen, you can generate the code just

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

I tried and it works perfectly


This is an alternative way to set up the engine path described in Holger's answer. Convenient if there are special characters in your user name or password.

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)

This solution worked for me

"""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 (the tool behind flask-sqlalchemy) can be configured to ignore tables. The configuration isn't too hard to setup. see: https://gist.github.com/utek/6163250

참고URL : https://stackoverflow.com/questions/17652937/how-to-build-a-flask-application-around-an-already-existing-database

반응형