SQLAlchemy फ़ाइलों में कक्षाएं


82

मैं यह पता लगाने की कोशिश कर रहा हूं कि SQLAlchemy कक्षाएं कई फ़ाइलों में कैसे फैली हैं, और मैं अपने जीवन के लिए यह पता नहीं लगा सकता कि यह कैसे करना है। मैं SQLAlchemy के लिए बहुत नया हूँ तो मुझे माफ कर दो अगर यह सवाल तुच्छ है ..

अपनी प्रत्येक फ़ाइल में इन 3 वर्गों पर विचार करें :

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'

मैं इन फ़ाइलों में घोषणात्मक आधार कैसे साझा करूं?

इसे पूरा करने का "सही" तरीका क्या है, इस पर विचार करते हुए कि मैं इसके ऊपर पाइलन्स या टर्बोगियर्स जैसा कुछ फेंक सकता हूं ?

10-03-2011 को संपादित करें

मुझे यह वर्णन पिरामिड फ्रेमवर्क से मिला है जो समस्या का वर्णन करता है और अधिक महत्वपूर्ण बात यह सत्यापित करता है कि यह एक वास्तविक मुद्दा है और केवल (केवल) ही मेरे भ्रमित होने की समस्या नहीं है। आशा है कि यह उन लोगों की मदद कर सकता है जो इस खतरनाक सड़क की हिम्मत करते हैं :)


7
@ S.Lott ऊपर काम करता है अगर सभी वर्ग एक फ़ाइल में हैं, तो आप मुझे बताएं :)
joveha

आपका कोड यह त्रुटि नहीं देता है, कृपया उस कोड को पोस्ट करें जिसमें वास्तविक त्रुटि है। अपने आयात को ठीक करें, इसे चलाएं ताकि कोई वास्तव में आपकी त्रुटि देख सके
knitti

@ S.Lott मेरा भ्रम जाहिर तौर पर चक्रीय आयात से बचने के तरीके के आसपास केंद्रित था। मैं C से आता हूं जहां यह कोई मुद्दा नहीं है। आपका समय लेने के लिए मेरी क्षमायाचना।
जोवेहा

@ जोवेहा: क्या? ये चक्रीय आयात समस्याएं आपके लिए क्या हैं। कृपया चक्रीय आयात के साथ कोड को पोस्ट करें ताकि हम समझा सकें कि उन्हें कैसे विघटित किया जाए और चक्र से बचें। इन टिप्पणियों में बहुत सारे अस्पष्ट काल्पनिक हैं। आपको क्या समस्या है? कृपया विशिष्ट रहें।
एस.लॉट

जवाबों:


88

आपकी समस्या का सबसे सरल समाधान 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यह है कि यह लीक किए गए लेनदेन और बासी डेटा के साथ हवा करना आसान बनाता है, आपके कोड में उस बिंदु पर कोई स्पष्ट लिंक नहीं है जब ऐसा हुआ हो।
सिंगलएनजेशन इलिमिनेशन

यह डिज़ाइन पैटर्न python3 के लिए काम नहीं करता है। वहाँ कोई आसान तय है कि python3 संगत है?
computermacgyver

@computermacgyver: इस पैटर्न को अजगर संस्करणों में सही ढंग से काम करना चाहिए। कृपया एक नया प्रश्न पूछें, ताकि आप अपने सभी कोड और त्रुटियों को देख सकें ।
सिंगलएजिनेशन इलिमिनेशन

धन्यवाद @dequestarmappartialsetattr मैंने पाया कि त्रुटि केवल तब होती है जब मैंने एक अलग मॉड्यूल में थिंक, बीडीओ, सीडोमो, और माडिलडोम को डालने की कोशिश की। मुझे लगता है कि इस मामले में समाधान के बजाय मॉड्यूल की __init__.py फ़ाइल में आधार कोड को शामिल करना था। मैंने कोड और अधिक स्पष्टीकरण यहां दिया है । उत्तर के लिए धन्यवाद।
computermacgyver

13

अगर मैं अपनी भावना को थोड़ा जोड़ सकता हूं क्योंकि मुझे भी यही समस्या थी। आपको उस फ़ाइल में कक्षाएं आयात करने की आवश्यकता होती है जहां आप Base = declarative_base()AFER बनाते हैं , Baseऔर Tables। लघु उदाहरण मेरी परियोजना कैसे स्थापित की जाती है:

मॉडल / 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')

मॉडल / 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'))

मॉडल / __ 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

मैं पायथन 2.7 + फ्लास्क 0.10 + SQLAlchemy 1.0.8 + पोस्टग्रेज 9.4.4.1 का उपयोग कर रहा हूं

यह बॉयलरप्लेट "उपयोगकर्ता" मॉड्यूल में एक ही फ़ाइल "मॉडल थिंकपैड" में संग्रहीत उपयोगकर्ता और उपयोगकर्ता डेटा मॉडल के साथ कॉन्फ़िगर किया गया है। ये कक्षाएं SQLAlchemy बेस क्लास से इनहेरिट करती हैं।

मैंने अपने प्रोजेक्ट में जो अतिरिक्त कक्षाएं जोड़ी हैं, उनमें से सभी इस बेस क्लास से भी निकली हैं, और जैसे-जैसे मॉडल-थ्रू फ़ाइल बड़ी होती गई, मैंने मॉडल-फाई फ़ाइल को प्रति क्लास एक फ़ाइल में विभाजित करने का फैसला किया, और वर्णित समस्या में भाग गया। यहाँ।

समाधान मैंने पाया, @ computermacgyver के अक्टू 23 2013 पोस्ट के रूप में उसी तर्ज पर, करने के लिए अपने सभी वर्गों में शामिल किया गया था init नया मॉड्यूल मैं सभी नव निर्मित वर्ग फ़ाइलों रखने के लिए बनाया का .py फ़ाइल। इस तरह दिखता है:

/project/models/

__init__.py contains

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

2
आपको क्या लगता है कि आपको फ्लास्क का उपयोग करने की आवश्यकता है?
रातें

0

मेरे लिए, import app.tool.tool_entityअंदर app.pyऔर from 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)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.