Các lớp SQLAlchemy trên các tệp


82

Tôi đang cố gắng tìm ra cách để các lớp SQLAlchemy trải rộng trên một số tệp và tôi có thể suốt đời không tìm ra cách làm điều đó. Tôi còn khá mới với SQLAlchemy vì vậy hãy tha thứ cho tôi nếu câu hỏi này là tầm thường ..

Hãy xem xét 3 lớp này trong mỗi tệp riêng của chúng :

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

Và sau đó giả sử chúng tôi có một main.py một cái gì đó như thế này:

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

Ở trên đưa ra lỗi:

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'

Làm cách nào để chia sẻ cơ sở khai báo trên các tệp này?

Cách "đúng đắn" để thực hiện điều này là gì, khi tôi có thể ném thứ gì đó như Pylons hoặc Turbogears lên trên nó?

chỉnh sửa 10-03-2011

Tôi tìm thấy mô tả này từ khung Kim tự tháp mô tả vấn đề và quan trọng hơn là xác minh rằng đây là một vấn đề thực tế chứ không phải (duy nhất) chỉ là bản thân tôi đang bối rối đó là vấn đề. Hy vọng nó có thể giúp những người khác dám xuống con đường nguy hiểm này :)


7
@ S. Lott Các công trình trên nếu tất cả các lớp học nằm trong một tập tin, vì vậy bạn cho tôi biết :)
joveha

Mã của bạn không có lỗi này, vui lòng đăng mã có lỗi thực sự. Sửa lỗi nhập của bạn, làm cho nó chạy để ai đó có thể thực sự thấy lỗi của bạn.
đanti

@ S.Lott Sự nhầm lẫn của tôi dường như xoay quanh việc làm thế nào để tránh nhập khẩu theo chu kỳ. Tôi đến từ C, nơi đây không phải là một vấn đề. Tôi xin lỗi vì đã chiếm thời gian của bạn.
joveha

@joveha: Cái gì? Bạn đang gặp phải những vấn đề về nhập tuần hoàn nào. Vui lòng đăng mã với các lần nhập theo chu kỳ để chúng tôi có thể giải thích cách phân hủy chúng và tránh các chu kỳ. Có quá nhiều giả thuyết mơ hồ trong những bình luận này. Vấn đề mà bạn đang mắc phải là gì? Hãy cụ thể.
S.Lott

Câu trả lời:


87

Giải pháp đơn giản nhất cho vấn đề của bạn sẽ được đưa Basera khỏi mô-đun rằng hàng nhập khẩu A, BC ; Ngắt nhập tuần hoà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()

Hoạt động trên máy của tôi:

$ python main.py ; echo $?
0

1
Sử dụng scoped_session.
người dùng

3
@user: xử lý phiên không liên quan đến câu hỏi trong bài đăng này, đây thực sự là một câu hỏi python cũ đơn giản (làm cách nào để nhập nội dung?); nhưng kể từ khi tôi đã có sự chú ý của bạn, tôi sẽ tư vấn cho mạnh mẽ chống lại sử dụng scoped_session, trừ khi bạn biết lý do tại sao bạn cần sợi lưu trữ địa phương; Vấn đề với việc sử dụng scoped_sessionlà nó khiến tất cả dễ dàng kết thúc với các giao dịch bị rò rỉ và dữ liệu cũ, không có liên kết rõ ràng đến điểm trong mã của bạn khi điều đó có thể xảy ra.
SingleNegationElimination

Mẫu thiết kế này dường như không hoạt động với python3. Có cách khắc phục dễ dàng nào tương thích với python3 không?
computermacgyver

@computermacgyver: mẫu này sẽ hoạt động chính xác trên các phiên bản python. Vui lòng đặt một câu hỏi mới để bạn có thể bao gồm tất cả mã của mình và các lỗi bạn đang gặp.
SingleNegationElimination

Cảm ơn @noughestarmappartialsetattr. Tôi nhận thấy lỗi chỉ xảy ra khi tôi cố gắng đặt a.py, b.py, c.py và model.py vào một mô-đun riêng biệt. Tôi tìm thấy giải pháp trong trường hợp đó là đưa mã base.py vào tệp __init__.py của mô-đun thay thế. Tôi đã đặt mã và giải thích thêm ở đây . Cảm ơn vi đa trả lơi.
computermacgyver

13

Nếu tôi có thể thêm chút ý thức của mình vì tôi đã gặp vấn đề tương tự. Bạn cần nhập các lớp trong tệp nơi bạn tạo Base = declarative_base()SAU KHI bạn tạo BaseTables. Ví dụ ngắn gọn về cách thiết lập dự án của tôi:

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

Tôi đang sử dụng Python 2.7 + Flask 0.10 + SQLAlchemy 1.0.8 + Postgres 9.4.4.1

Bản soạn thảo này được định cấu hình với mô hình User và UserDetail được lưu trữ trong cùng một tệp "models.py" trong mô-đun "người dùng". Cả hai lớp này đều kế thừa từ một lớp cơ sở SQLAlchemy.

Tất cả các lớp bổ sung mà tôi đã thêm vào dự án của mình cũng bắt nguồn từ lớp cơ sở này và khi tệp models.py lớn hơn, tôi quyết định chia tệp models.py thành một tệp cho mỗi lớp và gặp phải sự cố được mô tả đây.

Giải pháp mà tôi tìm thấy, cùng dòng với bài đăng ngày 23 tháng 10 năm 2013 của @ computermacgyver, là đưa tất cả các lớp của tôi vào tệp init .py của mô-đun mới mà tôi đã tạo để chứa tất cả các tệp lớp mới được tạo. Trông như thế này:

/project/models/

__init__.py contains

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

2
tại sao bạn nghĩ bạn cần sử dụng Flask?
đêm

0

Đối với tôi, thêm import app.tool.tool_entitybên trong app.pyfrom app.tool.tool_entity import Toolbên trong tool/__init__.pylà đủ để có được bảng được tạo ra. Tuy nhiên, tôi vẫn chưa thử thêm mối quan hệ.

Cấu trúc thư mục:

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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.