5

Tôi đang sử dụng thừa kế bảng cụ thể với SQLAlchemy. Trong lớp mô hình kiểu suy giảm, tôi đã cấu hình nó thành công.Mối quan hệ đa hình SQLAlchemy với kế thừa bê tông

Mã của tôi chỉ thích:

class Entry(AbstractConcreteBase, db.Model): 
    """Base Class of Entry.""" 

    id = db.Column(db.Integer, primary_key=True, nullable=False) 
    created = db.Column(db.DateTime, nullable=False) 
    post_id = declared_attr(lambda c: db.Column(db.ForeignKey("post.id"))) 
    post = declared_attr(lambda c: db.relationship("Post", lazy="joined")) 

    @declared_attr 
    def __tablename__(cls): 
     return cls.__name__.lower() 

    @declared_attr 
    def __mapper_args__(cls): 
     # configurate subclasses about concrete table inheritance 
     return {'polymorphic_identity': cls.__name__, 
       'concrete': True} if cls.__name__ != "Entry" else {} 

class TextEntry(Entry): 
    """Text and Article Entry.""" 

    text = db.deferred(db.Column(db.Text, nullable=False)) 

class PhotoEntry(Entry): 
    """Photo Entry.""" 

    path = db.deferred(db.Column(db.String(256), nullable=False)) 

Nó hoạt động tốt khi thử nghiệm nó trong vỏ:

>>> from models.entry import Entry 
>>> 
>>> Entry.query.all() 
[<PhotoEntry 'Title' created by tonyseek>, 
<PhotoEntry 'TITLE 2' created by tonyseek>, 
<PhotoEntry 'Title 3' created by tonyseek>, 
<PhotoEntry 'Title 4' created by tonyseek>, 
<TextEntry 'Title' created by tonyseek>] 

Sau đó, tôi rơi vào rắc rối khi thiết lập các mối quan hệ trong các mô hình khác. Mỗi mục có khóa ngoài post_id để tham gia Post mô hình, nhưng tôi không thể xác định tham chiếu ngược trong Post. Điều đó không thể làm việc:

class Post(db.Model): 
    """An Post.""" 

    id = db.Column(db.Integer, primary_key=True, nullable=False) 
    description = db.Column(db.Unicode(140), nullable=False) 
    entries = db.relationship(Entry, lazy="dynamic") 

Nó nêu ra một ngoại lệ và nói:

InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Original exception was: Class 'models.entry.Entry' is not mapped.

Rõ ràng các Entry là một lớp trừu tượng, mà không thể được ánh xạ tới một thực tồn tại bảng. Tài liệu trên trang web chính thức có một ví dụ nhưng lớp cơ sở của nó không trừu tượng. Bây giờ làm thế nào tôi nên làm gì để thiết lập mối quan hệ đa hình với một mô hình trừu tượng?

Trả lời

7

Tôi đã tìm ra nguyên nhân của sự cố và giải pháp của nó.

Theo tài liệu của trang web chính thức sqlalchemy, lớp trừu tượng có thể là một lớp được ánh xạ, bởi vì hàm polymorphic_union có thể tạo ra một bảng ảo.

Tôi đang sử dụng kiểu kiểu suy giảm, không xây dựng trình ánh xạ bằng tay, do đó không được tạo bảng ảo pjoin bằng tay. Lớp cơ sở AbstractConcreteBase có phương thức __delcare_last__ sẽ tạo pjoin với chức năng polymorphic_union, nhưng nó sẽ được gọi trong khi sự kiện after_configured kích hoạt.

Mối quan hệ với Entry trong Post sẽ được tạo ra sau khi lớp Post được tạo ra, trong thời gian này sự kiện after_configured chưa được kích hoạt, vì vậy __delcare_last__ chức năng chưa tạo bảng ảo pjoin và ánh xạ nó vào Entry. Vì vậy, ngoại lệ "Class" models.entry.Entry 'không được ánh xạ. " sẽ được nâng lên.

Bây giờ, tôi refactor mô hình Post, hãy để nó tạo ra các mối quan hệ với Entry trong __delcare_last__ chức năng, sau đó nó sẽ thành công vì sự kiện được kích hoạt và ánh xạ Entry.

Lớp triển khai mới của tôi như sau:

class Post(db.Model): 
    """An Post.""" 

    id = db.Column(db.Integer, primary_key=True, nullable=False) 
    description = db.Column(db.Unicode(140), nullable=False) 

    @classmethod 
    def __declare_last__(cls): 
     cls.entries = db.relationship(Entry, viewonly=True) 

    def attach_entries(self, entries): 
     """Attach Entries To This Post. 

     Example: 
      >>> post = Post("An Interesting News", "Wow !!!") 
      >>> text_entry = TextEntry(*t_args) 
      >>> photo_entry = PhotoEntry(*p_args) 
      >>> post.attach_entries([text_entry, photo_entry]) 
      >>> len(post.entries) 
      2 
      >>> db.session.commit() 
      >>> 
     """ 
     for entry in entries: 
      self.entries.append(entry) 
      entry.post = self 
      db.session.add(entry) 
Các vấn đề liên quan