Ich versuche herauszufinden, wie SQLAlchemy-Klassen auf mehrere Dateien verteilt werden können, und ich kann für mein Leben nicht herausfinden, wie das geht. Ich bin ziemlich neu in SQLAlchemy, also vergib mir, wenn diese Frage trivial ist.
Betrachten Sie diese 3 Klassen in jeder eigenen Datei :
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"))
Und dann sagen wir, wir haben eine main.py wie diese:
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()
Das obige gibt den Fehler:
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'
Wie teile ich die deklarative Basis für diese Dateien?
Was ist der "richtige" Weg, um dies zu erreichen, wenn man bedenkt, dass ich so etwas wie Pylone oder Turbogears darüber werfen könnte ?
bearbeiten 10-03-2011
Ich fand diese Beschreibung von den Pyramiden Rahmen , die das Problem und was noch wichtiger beschreiben prüft , dass dies ein tatsächliches Problem ist und nicht (nur) nur mein verwirrtes Selbst , das ist das Problem. Hoffe, es kann anderen helfen, die es wagen, diesen gefährlichen Weg zu gehen :)
quelle
Antworten:
Die einfachste Lösung für Ihr Problem zu nehmen
Base
von dem Modul heraus , daß die EinfuhrenA
,B
undC
; Unterbrechen Sie den zyklischen Import.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()
Funktioniert auf meiner Maschine:
$ python main.py ; echo $? 0
quelle
scoped_session
.scoped_session
, es sei denn , Sie wissen , warum Sie lokale Speicher fädeln braucht; Das Problem bei der Verwendungscoped_session
besteht darin, dass es zu einfach ist, durchgesickerte Transaktionen und veraltete Daten zu beenden, ohne explizite Verknüpfung zu dem Punkt in Ihrem Code, an dem dies möglicherweise geschehen ist.Wenn ich auch meinen Sinn hinzufügen darf, da ich das gleiche Problem hatte. Sie müssen die Klassen in die Datei importieren, in der Sie die erstellen, nachdem Sie
Base = declarative_base()
dieBase
und die erstellt habenTables
. Kurzes Beispiel für die Einrichtung meines Projekts: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
quelle
Ich verwende Python 2.7 + Flask 0.10 + SQLAlchemy 1.0.8 + Postgres 9.4.4.1
Dieses Boilerplate wird mit einem User- und einem UserDetail-Modell konfiguriert, die in derselben Datei "models.py" im Modul "user" gespeichert sind. Diese Klassen erben beide von einer SQLAlchemy-Basisklasse.
Alle zusätzlichen Klassen, die ich meinem Projekt hinzugefügt habe, stammen ebenfalls von dieser Basisklasse. Als die Datei models.py größer wurde, entschied ich mich, die Datei models.py in eine Datei pro Klasse aufzuteilen, und stieß auf das beschriebene Problem Hier.
Die Lösung, die ich in Anlehnung an den Beitrag von @ computermacgyver vom 23. Oktober 2013 gefunden habe, bestand darin, alle meine Klassen in die init .py-Datei des neuen Moduls aufzunehmen, das ich erstellt habe, um alle neu erstellten Klassendateien aufzunehmen. Sieht aus wie das:
/project/models/ __init__.py contains from project.models.a import A from project.models.b import B etc...
quelle
Für mich war das Hinzufügen von
import app.tool.tool_entity
innenapp.py
undfrom app.tool.tool_entity import Tool
innentool/__init__.py
genug, um die Tabelle zu erstellen. Ich habe jedoch noch nicht versucht, eine Beziehung hinzuzufügen.Ordnerstruktur:
# 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)
quelle