2013-11-05 14 views
20

Tôi có hai mô hình Flask-SQLAlchemy với một mối quan hệ đơn giản một-nhiều, giống như ví dụ tối thiểu dưới đây:SQLAlchemy: biểu hiện lai với mối quan hệ

class School(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(30)) 
    address = db.Column(db.String(30)) 

class Teacher(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(30)) 
    id_school = db.Column(db.Integer, db.ForeignKey(School.id)) 

    school = relationship('School', backref='teachers') 

Sau đó, tôi thêm một tài sản hybrid để giáo viên có sử dụng các mối quan hệ, như:

@hybrid_property 
def school_name(self): 
    return self.school.name 

Và tài sản mà chỉ hoạt động tốt khi tôi sử dụng nó như teacher_instance.school_name. Tuy nhiên, tôi cũng muốn làm cho các truy vấn như Teacher.query.filter(Teacher.school_name == 'x'), nhưng điều đó mang lại cho tôi một lỗi:

`AttributeError: Neither 'InstrumentedAttribute' object nor 
'Comparator' object has an attribute 'school_name'`. 

Tiếp theo tài liệu hướng dẫn SQLAlchemy, tôi đã thêm một biểu thức lai đơn giản, giống như sau:

@school_name.expression 
def school_name(cls): 
    return School.name 

Tuy nhiên , khi tôi thử cùng một truy vấn một lần nữa, nó tạo ra một truy vấn SQL mà không có mệnh đề nối, vì vậy tôi nhận được tất cả các hàng có sẵn trong trường, không chỉ các hàng phù hợp với khóa ngoại trong Giáo viên.

Từ tài liệu SQLAlchemy tôi nhận ra rằng sự biểu hiện hy vọng một bối cảnh nơi tham gia đã có mặt, vì vậy tôi cố gắng truy vấn một lần nữa như:

Teacher.query.join(School).filter(Teacher.school_name == 'x')

Và đó thực sự hoạt động, nhưng nó đánh bại mục đích của cố gắng để có được đường cú pháp trong đó ở nơi đầu tiên nếu tôi cần kiến ​​thức về mô hình trường học để có được điều đó. Tôi hy vọng có một cách để có được tham gia vào các biểu hiện, nhưng tôi không thể tìm thấy nó ở bất cứ đâu. Tài liệu có một ví dụ với biểu thức trả về truy vấn phụ được xây dựng trực tiếp với select(), nhưng ngay cả điều đó cũng không hiệu quả đối với tôi.

Bất kỳ ý tưởng nào?

CẬP NHẬT

Sau câu trả lời Eevee của dưới đây, tôi sử dụng proxy hiệp hội như đề xuất và nó hoạt động, nhưng tôi cũng đã tò mò với những nhận xét rằng nó sẽ làm việc với các select() subquery và cố gắng tìm ra những gì tôi đã làm sai. Nỗ lực ban đầu của tôi là:

@school_name.expression 
def school_name(cls): 
    return select(School.name).where(cls.id_school == School.id).as_scalar() 

Và hóa ra tôi đã gặp lỗi vì tôi đã bỏ lỡ danh sách ở lựa chọn(). Đoạn code dưới đây hoạt động tốt:

@school_name.expression 
def school_name(cls): 
    return select([School.name]).where(cls.id_school == School.id).as_scalar() 

Trả lời

12

Một cách tiếp cận đơn giản hơn nhiều cho một trường hợp đơn giản như thế này là một association proxy:

class Teacher(db.Model): 
    school_name = associationproxy('school', 'name') 

này hỗ trợ truy vấn (ít nhất là với ==) tự động.

Tôi tò mò làm thế nào ví dụ lai select() không hoạt động cho bạn, vì đó là cách dễ nhất để sửa lỗi này trong một kết hợp. Và để hoàn thành, bạn cũng có thể sử dụng một số transformer để sửa đổi truy vấn trực tiếp thay vì truy vấn con.

+1

Điều đó thật đơn giản. Cảm ơn rất nhiều. –

+1

Bạn đã đúng về 'select()'. Lỗi của tôi. Tôi đã thêm một bản cập nhật cho câu hỏi chi tiết nó. –

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