파일 간 SQLAlchemy 클래스


82

SQLAlchemy 클래스를 여러 파일에 분산시키는 방법을 알아 내려고하는데, 어떻게해야할지 모르겠습니다. 나는 SQLAlchemy를 처음 사용하므로이 질문이 사소한 경우 용서해주십시오 ..

각각의 파일 에서 다음 세 가지 클래스를 고려 하십시오 .

A.py :

from sqlalchemy import *
from main import Base

class A(Base):
    __tablename__ = "A"
    id  = Column(Integer, primary_key=True)
    Bs  = relationship("B", backref="A.id")
    Cs  = relationship("C", backref="A.id")

B.py :

from sqlalchemy import *
from main import Base

class B(Base):
    __tablename__ = "B"
    id    = Column(Integer, primary_key=True)
    A_id  = Column(Integer, ForeignKey("A.id"))

C.py :

from sqlalchemy import *
from main import Base

class C(Base):
    __tablename__ = "C"    
    id    = Column(Integer, primary_key=True)
    A_id  = Column(Integer, ForeignKey("A.id"))

그리고 다음 과 같은 main.py 가 있다고합시다 .

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, backref, sessionmaker

Base = declarative_base()

import A
import B
import C

engine = create_engine("sqlite:///test.db")
Base.metadata.create_all(engine, checkfirst=True)
Session = sessionmaker(bind=engine)
session = Session()

a  = A.A()
b1 = B.B()
b2 = B.B()
c1 = C.C()
c2 = C.C()

a.Bs.append(b1)
a.Bs.append(b2)    
a.Cs.append(c1)
a.Cs.append(c2)    
session.add(a)
session.commit()

위의 오류는 다음과 같습니다.

sqlalchemy.exc.NoReferencedTableError: Foreign key assocated with column 'C.A_id' could not find table 'A' with which to generate a foreign key to target column 'id'

이 파일에서 선언적 기반을 어떻게 공유합니까?

Pylons 또는 Turbogears 와 같은 것을 이 위에 던질 수 있다는 점을 고려할 때 "올바른"방법은 무엇입니까 ?

2011 년 3 월 10 일 수정

나는 문제를 설명하는 Pyramids 프레임 워크 에서이 설명을 찾았고 , 더 중요한 것은 이것이 문제인 내 혼란스러워하는 자신이 아니라 실제 문제임을 확인 하는 것입니다. 이 위험한 길을 감히 도전하는 다른 사람들을 도울 수 있기를 바랍니다. :)


7
@ S.Lott 모든 클래스가 하나의 파일에 있으면 위의 내용이 작동하므로 알려주세요 :)
joveha

귀하의 코드는이 오류를 제공하지 않습니다. 실제 오류가있는 코드를 게시하십시오. 가져 오기를 수정하고 누군가가 실제로 오류를 수 있도록 실행 하십시오 .
knitti

@ S.Lott 내 혼란은주기적인 수입을 피하는 방법에 집중되었습니다. 나는 이것이 문제가 아닌 C에서 왔습니다. 시간을내어 죄송합니다.
joveha 2011 년

@joveha : 뭐? 이러한 주기적 가져 오기 문제는 무엇입니까? 순환 가져 오기와 함께 코드를 게시하여 분해하고 순환을 피하는 방법을 설명 할 수 있습니다. 이 의견에는 모호한 가설이 너무 많습니다. 어떤 문제가 있습니까? 구체적으로 작성하십시오.
S.Lott 2011 년

답변:


87

문제에 대한 가장 간단한 솔루션을 가지고하는 것입니다 Base모듈의 출력이 수입 A, B그리고 C; 주기적 가져 오기를 중단하십시오.

base.py

from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

a.py

from sqlalchemy import *
from base import Base
from sqlalchemy.orm import relationship

class A(Base):
    __tablename__ = "A"
    id  = Column(Integer, primary_key=True)
    Bs  = relationship("B", backref="A.id")
    Cs  = relationship("C", backref="A.id")

b.py

from sqlalchemy import *
from base import Base

class B(Base):
    __tablename__ = "B"
    id    = Column(Integer, primary_key=True)
    A_id  = Column(Integer, ForeignKey("A.id"))

c.py

from sqlalchemy import *
from base import Base

class C(Base):
    __tablename__ = "C"    
    id    = Column(Integer, primary_key=True)
    A_id  = Column(Integer, ForeignKey("A.id"))

main.py

from sqlalchemy import create_engine
from sqlalchemy.orm import relationship, backref, sessionmaker

import base


import a
import b
import c

engine = create_engine("sqlite:///:memory:")
base.Base.metadata.create_all(engine, checkfirst=True)
Session = sessionmaker(bind=engine)
session = Session()

a1 = a.A()
b1 = b.B()
b2 = b.B()
c1 = c.C()
c2 = c.C()

a1.Bs.append(b1)
a1.Bs.append(b2)    
a1.Cs.append(c1)
a1.Cs.append(c2)    
session.add(a1)
session.commit()

내 컴퓨터에서 작동 :

$ python main.py ; echo $?
0

1
사용 scoped_session.
사용자

3
@user : 세션 처리는이 게시물의 질문과 관련이 없습니다. 이것은 정말 평범한 파이썬 질문입니다 (어떻게 물건을 가져 오나요?). 내가 관심을 가지고 있기 때문에, 나는 권합니다 에 대해 강력하게 사용 scoped_session하면 스레드 로컬 저장소를 필요 이유를 알지 못한다면,; 사용의 문제 scoped_session는 유출 된 트랜잭션과 오래된 데이터로 인해 발생했을 수있는 코드의 지점에 대한 명시적인 링크없이 쉽게 끝낼 수 있다는 것입니다.
SingleNegationElimination 2013-09-06

이 디자인 패턴은 python3에서 작동하지 않는 것 같습니다. python3과 호환되는 쉬운 수정이 있습니까?
computermacgyver

@computermacgyver :이 패턴은 Python 버전에서 올바르게 작동합니다. 모든 코드와 표시되는 오류를 포함 할 수 있도록 새로운 질문을 하십시오 .
SingleNegationElimination

감사합니다 @dequestarmappartialsetattr. a.py, b.py, c.py 및 model.py를 별도의 모듈에 넣으려고 할 때만 오류가 발생한다는 것을 알았습니다. 이 경우 해결책은 모듈의 __init__.py 파일에 base.py 코드를 대신 포함하는 것입니다. 여기에 코드와 자세한 설명을 넣었습니다 . 답장을 보내 주셔서 감사합니다.
computermacgyver

13

같은 문제가 있었기 때문에 약간의 감각을 더할 수 있다면. Base = declarative_base()을 만든 후 파일 을 만든 파일에서 클래스를 가져와야 Base합니다 Tables. 내 프로젝트 설정 방법의 간단한 예 :

model / user.py

from sqlalchemy import *
from sqlalchemy.orm import relationship

from model import Base

class User(Base):
     __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    budgets = relationship('Budget')

model / budget.py

from sqlalchemy import *

from model import Base

class Budget(Base):
    __tablename__ = 'budget'

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('user.id'))

model / __ init__.py

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

_DB_URI = 'sqlite:///:memory:'
engine = create_engine(_DB_URI)

Base = declarative_base()
Base.metadata.create_all(engine)
DBSession = sessionmaker(bind=engine)
session = DBSession()

from .user import User
from .budget import Budget

8

Python 2.7 + Flask 0.10 + SQLAlchemy 1.0.8 + Postgres 9.4.4.1을 사용하고 있습니다.

이 상용구는 "user"모듈의 동일한 파일 "models.py"에 저장된 User 및 UserDetail 모델로 구성됩니다. 이러한 클래스는 모두 SQLAlchemy 기본 클래스에서 상속됩니다.

내 프로젝트에 추가 한 모든 추가 클래스는이 기본 클래스에서도 파생되었으며 models.py 파일이 커짐에 따라 models.py 파일을 클래스 당 하나의 파일로 분할하기로 결정하고 설명 된 문제에 직면했습니다. 여기.

@computermacgyver의 2013 년 10 월 23 일 게시물과 동일한 줄을 따라 내가 찾은 해결책 은 새로 만든 모든 클래스 파일을 보관하기 위해 만든 새 모듈 의 init .py 파일에 모든 클래스를 포함하는 것입니다. 다음과 같이 보입니다.

/project/models/

__init__.py contains

from project.models.a import A 
from project.models.b import B
etc...

2
Flask를 사용해야하는 이유는 무엇입니까?

0

저에게는 import app.tool.tool_entity내부 app.pyfrom app.tool.tool_entity import Tool내부를 추가하는 tool/__init__.py것만으로도 테이블을 만들 수있었습니다. 나는 아직 관계를 추가하려고 시도하지 않았습니다.

폴더 구조 :

app/
  app.py
  tool/
    __init__.py
    tool_entity.py
    tool_routes.py
# app/tool/tool_entity.py

from app.base import Base
from sqlalchemy import Column, Integer, String


class Tool(Base):
    __tablename__ = 'tool'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)
    fullname = Column(String)
    fullname2 = Column(String)
    nickname = Column(String)

    def __repr__(self):
        return "<User(name='%s', fullname='%s', nickname='%s')>" % (
            self.name, self.fullname, self.nickname)
# app/tool/__init__.py
from app.tool.tool_entity import Tool
# app/app.py

from flask import Flask
from sqlalchemy import create_engine
from app.tool.tool_routes import tool_blueprint
from app.base import Base


db_dialect = 'postgresql'
db_user = 'postgres'
db_pwd = 'postgrespwd'
db_host = 'db'
db_name = 'db_name'
engine = create_engine(f'{db_dialect}://{db_user}:{db_pwd}@{db_host}/{db_name}', echo=True)
Base.metadata.create_all(engine)


app = Flask(__name__)
@app.route('/')
def hello_world():
    return 'hello world'


app.register_blueprint(tool_blueprint, url_prefix='/tool')

if __name__ == '__main__':
    # you can add this import here, or anywhere else in the file, as debug (watch mode) is on, 
    # the table should be created as soon as you save this file.
    import app.tool.tool_entity
    app.run(host='0.0.0.0', port=5000, debug=True)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.