2012-03-07 40 views
12

Vì vậy, tôi có một loạt các bảng sử dụng SQLAlchemy được mô hình hóa như các đối tượng kế thừa từ kết quả đến một cuộc gọi đến declarative_base(). Ví dụ:Sqlalchemy: tránh nhiều thừa kế và có lớp cơ sở trừu tượng

Base = declarative_base() 
class Table1(Base): 
    # __tablename__ & such here 

class Table2(Base): 
    # __tablename__ & such here 

vv sau đó tôi muốn có một số chức năng thông thường có sẵn cho mỗi lớp học bảng DB của tôi, the easiest way to do this according to the docs là chỉ cần làm đa kế thừa:

Base = declarative_base() 

class CommonRoutines(object): 
    @classmethod 
    def somecommonaction(cls): 
     # body here 

class Table1(CommonRoutines, Base): 
    # __tablename__ & such here 

class Table2(CommonRoutines, Base): 
    # __tablename__ & such here 

Điều tôi không thích về điều này là A) nhiều thừa kế nói chung là một chút icky (được giải quyết khó khăn những thứ như super() cuộc gọi, vv), B) nếu tôi thêm một bảng mới tôi phải nhớ kế thừa từ cả hai BaseCommonRoutines, và C) thực sự rằng "CommonRoutines" class "is-a" loại bảng theo nghĩa nào đó. Thực sự những gì CommonBase là một lớp cơ sở trừu tượng định nghĩa một tập hợp các trường & các thường trình chung cho tất cả các bảng. Đặt một cách khác: "nó-a" bảng trừu tượng.

Vì vậy, những gì tôi muốn là thế này:

Base = declarative_base() 

class AbstractTable(Base): 
    __metaclass__ = ABCMeta # make into abstract base class 

    # define common attributes for all tables here, like maybe: 
    id = Column(Integer, primary_key=True) 

    @classmethod 
    def somecommonaction(cls): 
     # body here 

class Table1(AbstractTable): 
    # __tablename__ & Table1 specific fields here 

class Table2(AbstractTable): 
    # __tablename__ & Table2 specific fields here 

Nhưng điều này tất nhiên không hoạt động, như tôi thì có đến A) định nghĩa một __tablename__ cho AbstractTable, B) các khía cạnh ABC thứ gây ra tất cả các loại đau đầu, và C) phải chỉ ra một số loại mối quan hệ DB giữa AbstractTable và mỗi bảng riêng lẻ.

Câu hỏi của tôi: có thể đạt được điều này một cách hợp lý không? Lý tưởng nhất là tôi muốn thực thi:

  • Không thừa kế nhiều
  • CommonBase/AbstractTable được trừu tượng (tức là không thể được khởi tạo)

Trả lời

14

Nó là khá straigh-forward, bạn chỉ cần thực declarative_base() trở lại một lớp Base được kế thừa từ số CommonBase của bạn sử dụng thông số cls=. Cũng được hiển thị trong tài liệu Augmenting The Base. Mã của bạn sau đó có thể trông giống như dưới đây:

class CommonBase(object): 
    @classmethod 
    def somecommonaction(cls): 
     # body here 

Base = declarative_base(cls=CommonBase) 

class Table1(Base): 
    # __tablename__ & Table1 specific fields here 

class Table2(Base): 
    # __tablename__ & Table2 specific fields here 
+0

Đúng tôi nếu tôi là sai, nhưng những người thừa kế "AbstractTable" nên đọc "cơ sở", có đúng không? (tức là 'lớp Table1 (Cơ sở):') –

+0

@AdamParkin: tất nhiên. sửa chữa. – van

+0

Yup, đây chính xác là những gì tôi đang tìm kiếm. Cảm ơn! Hạn chế duy nhất của phương thức này là bây giờ '__init__' của lớp' CommonBase' không được gọi ('declarative_base' tạo ra một lớp không gọi' super' trong '__init__' của nó nên các cơ chế thừa kế hợp tác của Python không công việc). Hmm .... –

2

Bạn có thể sử dụng AbstractConcreteBase để thực hiện một mô hình cơ sở absract:

from sqlalchemy.ext.declarative import AbstractConcreteBase 


class AbstractTable(AbstractConcreteBase, Base): 
    id = db.Column(db.Integer, primary_key=True) 

    @classmethod 
    def somecommonaction(cls): 
     # body here 
26

phiên bản 0.7.3 SQLAlchemy giới thiệu chỉ thị __abstract__ được sử dụng cho các lớp trừu tượng không được ánh xạ tới bảng cơ sở dữ liệu, mặc dù chúng là các lớp con của sqlalchemy.ext.declarative.api.Base. Vì vậy, bây giờ bạn tạo một lớp cơ sở như thế này:

Base = declarative_base() 

class CommonRoutines(Base): 
    __abstract__ = True 

    id = Column(Integer, primary_key=True) 

    def __init__(self): 
     # ... 

Chú ý cách CommonRoutines không có một thuộc tính __tablename__. Sau đó tạo ra các lớp con như thế này:

class Foo(CommonRoutines): 
    __tablename__ = 'foo' 

    name = Column(...) 

    def __init__(self, name): 
     super().__init__() 
     self.name = name 
     # ... 

này sẽ lập bản đồ vào bảng foo và kế thừa các thuộc tính id từ CommonRoutines.

Nguồn và biết thêm thông tin: http://docs.sqlalchemy.org/en/rel_0_7/orm/extensions/declarative.html#abstract

+0

Đây là những gì tôi thực sự tìm kiếm. cảm ơn – pylover

Các vấn đề liên quan