Dosyalar arasında SQLAlchemy sınıfları


82

SQLAlchemy sınıflarının birkaç dosyaya nasıl dağıldığını anlamaya çalışıyorum ve hayatım boyunca bunu nasıl yapacağımı çözemiyorum. SQLAlchemy'de oldukça yeniyim, bu yüzden bu soru önemsizse beni affedin ..

Her biri kendi dosyasında bulunan bu 3 sınıfı düşünün :

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

Ve sonra şöyle bir main.py'imiz olduğunu söyleyin :

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

Yukarıdakiler hatayı verir:

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'

Bildirim temelini bu dosyalar arasında nasıl paylaşırım?

Bunun üzerine Direk veya Turbogears gibi bir şey atabileceğimi düşünürsek, bunu başarmanın "doğru" yolu nedir?

düzenle 10-03-2011

Bu açıklamayı, sorunu tanımlayan ve daha da önemlisi bunun gerçek bir sorun olduğunu doğrulayan Piramitler çerçevesinden buldum ve (sadece) sadece kafa karışıklığım değil, sorun bu. Umarım bu tehlikeli yolda cesaret edenlere yardımcı olabilir :)


7
@ S.Lott Yukarıdakiler, tüm sınıflar tek bir
dosyadaysa

Kodunuz bu hatayı vermiyor, lütfen gerçek hatayı içeren kodu gönderin. İçe aktarımlarınızı düzeltin, çalıştırmasını sağlayın, böylece birisi hatanızı gerçekten görebilir .
knitti

@ S.Lott Benim kafa karışıklığım görünüşe göre döngüsel içe aktarmalardan nasıl kaçınılacağına odaklanmıştı. Bunun bir sorun olmadığı C'den geliyorum. Zaman ayırdığım için özür dilerim.
joveha

@joveha: Ne? Yaşadığınız bu döngüsel içe aktarma sorunları nelerdir? Lütfen kodu döngüsel içe aktarmalarla birlikte gönderin, böylece onları nasıl ayrıştıracağımızı ve döngüleri nasıl önleyeceğimizi açıklayabiliriz. Bu yorumlarda çok fazla belirsiz varsayım var. Problemin ne? Lütfen açık ol.
S.Lott

Yanıtlar:


88

Sorununuza basit çözüm almaya olacak Basemodülün dışına o ithalatı A, Bve C; Döngüsel içe aktarmayı kırın.

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

Makinemde çalışıyor:

$ python main.py ; echo $?
0

1
Kullanın scoped_session.
kullanıcı

3
@user: oturum işleme, bu gönderideki soruyla ilgisizdir, bu gerçekten basit ve eski bir python sorusudur (öğeleri nasıl içe aktarırım?); ancak dikkatinizi çektiğim için , neden iş parçacığı yerel depolamaya ihtiyacınız olduğunu bilmiyorsanız, kullanmaya şiddetle tavsiye scoped_sessionederim; Kullanmayla ilgili sorun, scoped_sessionsızan işlemler ve eski verilerle sonuçlanmayı kolaylaştırması ve kodunuzda bunun gerçekleşmiş olabileceği noktaya açık bir bağlantı olmadan her şeyi kolaylaştırmasıdır.
SingleNegationElimination

Bu tasarım deseni python3 için çalışmıyor gibi görünüyor. Python3 ile uyumlu herhangi bir kolay düzeltme var mı?
computermacgyver

@computermacgyver: Bu model python sürümlerinde doğru şekilde çalışmalıdır. Eğer tüm içerebilir, böylece yeni bir soru sormak Lütfen sizin kodu ve Gördüğünüz hataları.
SingleNegationElimination

Teşekkürler @dequestarmappartialsetattr. Hatanın yalnızca a.py, b.py, c.py ve model.py'yi ayrı bir modüle koymaya çalıştığımda oluştuğunu gördüm. Bu durumda çözümün, bunun yerine modülün __init__.py dosyasına base.py kodunu eklemek olduğunu buldum. Kodu ve daha fazla açıklamayı buraya koydum . Yanıt için teşekkürler.
computermacgyver

13

Aynı problemi yaşadığım için biraz da hislerimi ekleyebilir miyim? Oluşturduğunuz dosyasında sınıfları ithalat gerekir Base = declarative_base()Oluşturduğunuz SONRA Baseve Tables. Projemin nasıl kurulduğuna dair kısa bir örnek:

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 kullanıyorum

Bu şablon, "kullanıcı" modülünde aynı "models.py" dosyasında saklanan User ve UserDetail modelleriyle yapılandırılmış olarak gelir. Bu sınıfların her ikisi de bir SQLAlchemy temel sınıfından miras alır.

Projeme eklediğim tüm ek sınıflar da bu temel sınıftan türetildi ve models.py dosyası büyüdükçe, models.py dosyasını sınıf başına bir dosyaya bölmeye karar verdim ve açıklanan problemle karşılaştım buraya.

Bulduğum çözüm, @ computermacgyver'in 23 Ekim 2013 gönderisiyle aynı çizgide, tüm sınıflarımı yeni oluşturulan tüm sınıf dosyalarını tutmak için oluşturduğum yeni modülün init .py dosyasına dahil etmekti . Buna benzer:

/project/models/

__init__.py contains

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

2
Neden Flask kullanmanız gerektiğini düşünüyorsunuz?
geceleri

0

Benim için import app.tool.tool_entityiçini app.pyve from app.tool.tool_entity import Tooliçini eklemektool/__init__.py tablonun oluşturulması için yeterliydi. Yine de henüz ilişki eklemeyi denemedim.

Klasör yapısı:

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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.