117 votes

Classes SQLAlchemy dans les fichiers

J'essaie de comprendre comment répartir les classes SQLAlchemy dans plusieurs fichiers, et je n'arrive pas à trouver comment le faire. Je suis assez novice en SQLAlchemy donc pardonnez-moi si cette question est triviale

Considérons ces 3 classes en chacun son dossier :

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"))

Et puis disons que nous avons un main.py quelque chose comme ça :

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

Ce qui précède donne l'erreur :

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'

Comment partager la base déclarative entre ces fichiers ?

Quelle est la "bonne" façon d'y parvenir, sachant que je pourrais lancer quelque chose comme Pylônes o Turbogears en plus de cela ?

modifier 10-03-2011

J'ai trouvé este description du cadre des Pyramides qui décrit le problème et, plus important encore, qui décrit le problème et, plus important encore, qui décrit le problème. vérifie qu'il s'agit d'un problème réel et que ce n'est pas (seulement) mon moi confus qui est en cause. J'espère que cela pourra aider d'autres personnes qui osent s'engager sur cette voie dangereuse :)

117voto

IfLoop Points 59461

La solution la plus simple à votre problème sera de prendre Base du module qui importe A , B et C Casser l'importation cyclique.

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

Fonctionne sur ma machine :

$ python main.py ; echo $?
0

24voto

Peter Points 435

Si je peux me permettre d'ajouter mon grain de sel, j'ai eu le même problème. Vous devez importer les classes dans le fichier où vous créez le fichier Base = declarative_base() APRES avoir créé le Base et le Tables . Petit exemple de la façon dont mon projet est structuré :

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

8voto

RadX3 Points 81

J'utilise Python 2.7 + Flask 0.10 + SQLAlchemy 1.0.8 + Postgres 9.4.4.1

Ce modèle est configuré avec un modèle User et un modèle UserDetail stockés dans le même fichier "models.py" dans le module "user". Ces classes héritent toutes deux d'une classe de base SQLAlchemy.

Toutes les classes supplémentaires que j'ai ajoutées à mon projet ont également dérivé de cette classe de base, et comme le fichier models.py s'est agrandi, j'ai décidé de diviser le fichier models.py en un fichier par classe, et j'ai rencontré le problème décrit ici.

La solution que j'ai trouvée, dans la même veine que le post de @computermacgyver du 23 octobre 2013, a été d'inclure toutes mes classes dans le fichier init .py du nouveau module que j'ai créé pour contenir tous les fichiers de classe nouvellement créés. Voici à quoi cela ressemble :

/project/models/

__init__.py contains

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

0voto

Ambroise Rabier Points 342

Pour moi, l'ajout de import app.tool.tool_entity à l'intérieur app.py et from app.tool.tool_entity import Tool à l'intérieur tool/__init__.py a suffi pour que la table soit créée. Je n'ai cependant pas encore essayé d'ajouter une relation.

Structure du dossier :

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)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X