2012-05-16 3 views
6

제 질문은 실제로 PySide의 QTableView 클래스에서 액세스 할 수있는 SQLAlchemy 선언 모델을 설정하는 것입니다. 난 그냥 기본적으로 Object Relational tutorialPySide + SQLAlchemy의 QTableView 용 '모델'디자인.

에 대한 처음과 끝을 구현하기 위해 노력하고있어

불행하게도 나는 혼란의 몇 가지 포인트가 있습니다. 나는 어디에 있는지 설명하려고 노력할 것이다.

SQLAlchemy 튜토리얼을 따라 두 개의 관련 테이블을 가지며 아무 문제없이 조작/쿼리 할 수 ​​있습니다. QTableView class을 설정하려고하면 내 모델에 setData() method이 필요하거나 기본 모델을 사용하려면 setItem() method이 필요합니다.

그래서 모델을 설계하는 방법이 궁금합니다. 나는이 두 가지 방법 중 하나를 데이터베이스 쿼리/수정을 정의하는 것을 의미합니다. 나는 이것을 할 올바른 방법을 모른다.

모델은 모든 주소가 표시 될 때까지 사용자 이름과 성을 몇 줄로 반복 한 다음 다음 사용자로 이동해야합니다. 나는이 작업을 프롬프트에서 인쇄하기 위해 중첩 된 for 루프로 처리 할 수 ​​있지만, 큰 목록을 만드는 것이 처음부터 데이터베이스를 갖는 지점을 무력화시키는 것처럼 보이지는 않는다고 생각합니다.

또한 데이터베이스가 커질 때 어떤 일이 발생할지 모르고, 전체 테이블이 인스턴스화되어 메모리에 보관되거나 사용자가 스크롤 할 때 볼 때 들어오는 행과 열을 Qt로드합니까?

여기에 텍스트가 많이 있지만 죄송합니다. 추가 할 수있는 것이 있으면 알려 주시기 바랍니다. 아니면 내가 완전히 잘못된 트랙에 있다면 ....

from PySide import QtCore, QtGui 
from sqlalchemy import Column, Integer, String, Text, Sequence, ForeignKey, Date, Boolean, create_engine 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import sessionmaker, relationship, backref, aliased 
import datetime 


engine = create_engine('sqlite:///reminder.db') 

Base = declarative_base() 

class User(Base): 
    __tablename__ = 'users_db' 
    id = Column(Integer, Sequence('user_id_seq'), primary_key=True) 
    lastname = Column(String) 
    firstname = Column(String) 
    contact = Column(String) 
    history = Column(Text) 
    notes = Column(Text) 

    addresses = relationship('Address', order_by='Address.id', 
           backref='user', cascade='all, delete, delete-orphan') 


    def __init__(self, firstname, lastname, contact): 
     self.firstname = firstname 
     self.lastname = lastname 
     self.contact = contact 

    def __repr__(self): 
     return "<User('{0}', '{1}', '{2}')>".format(self.firstname, self.lastname, self.contact) 


class Address(Base): 
    __tablename__ = 'addresses_db' 
    id = Column(Integer, primary_key=True) 
    address = Column(String(150)) 
    date = Column(Date) 
    check1 = Column(Boolean) 
    check2 = Column(Boolean) 

    user_id = Column(Integer, ForeignKey('users_db.id')) 

    def __init__(self, address, date): 
     self.address = address 
     self.date = date 
     self.check1 = False 
     self.check2 = False 

    def __repr__(self): 
     return "<Address('{0}', '{1}')>".format(self.address, self.date) 

if __name__ == '__main__': 
    Base.metadata.create_all(engine) 
    Session = sessionmaker(bind=engine) 
    session = Session() 
    header = [User.firstname, User.lastname, nextaddressfromUser] 

>>> for user in session.query(User).all(): 
...  for addr in user.addresses: 
...   print user.firstname, user.lastname, addr.address 

답변

6

먼저, 우리는 쿼리에 대해 잊어 버리고 사용중인 루프를 사용하십시오. UI에서 찾고있는 것이 기본적인 것입니다. 나는 문서의 부족으로, QTableWidget (또는 무엇이든 QWhateverWidget)을 QWhateverView보다 더 잘 사용하는 것이 가장 좋다는 것을 발견했다. 간단한 작업을 위해 자신 만의 모델을 정의 할 필요는 없습니다. 그래서, QTableWidget으로 어떻게하는지 보여 드리겠습니다. (행, 열)에 각 셀에 대한 QTableWidgetItem을 만들어야합니다. 내가 직면 한 한 가지 문제점은 행을 추가하기 전에 행 수를 설정해야한다는 것입니다. 여기에, 어쨌든 :

import sys 
from PySide import QtGui, QtCore 

class Test(QtGui.QWidget): 

    def __init__(self, rows): 
     super(Test, self).__init__() 

     self.table = QtGui.QTableWidget() 
     self.table.setColumnCount(3) 
     # Optional, set the labels that show on top 
     self.table.setHorizontalHeaderLabels(("First Name", "Last Name", "Address")) 

     self.table.setRowCount(len(rows)) 
     for row, cols in enumerate(rows): 
      for col, text in enumerate(cols): 
       table_item = QtGui.QTableWidgetItem(text) 
       # Optional, but very useful. 
       table_item.setData(QtCore.Qt.UserRole+1, user) 
       self.table.setItem(row, col, table_item) 

     # Also optional. Will fit the cells to its contents. 
     self.table.resizeColumnsToContents() 

     # Just display the table here. 
     layout = QtGui.QHBoxLayout() 
     layout.addWidget(self.table) 
     self.setLayout(layout) 

if __name__ == "__main__": 
    # ... 
    rows = [] 
    # Here I have to fill it in an array, because you need to know the number of rows before adding... There might be a better solution though. 
    for user in session.query(User).all(): 
     for addr in user.addresses: 
      # These are the columns on each row (firstname, lastname, address) 
      rows.append((user.firstname, user.lastname, addr.address)) 

    app = QtGui.QApplication(sys.argv) 
    test = Test(rows) 
    test.show() 
    app.exec_() 

사용하는 것이 좋습니다 또 다른 것은 여러 열을 지원하는 QTreeWidget입니다, 당신이 그것을 테이블처럼 보이게하지만, 기본적으로 편집 가능한 세포없이, 그것은 데이터에 맞게 수 있습니다 더 나은 여기.

이제 쿼리에 대해 결과를 반복하지 않고 각 사용자에 대해 하나의 추가 쿼리를 만들지 않고 단일 쿼리로 만들 수 있습니다. 같은 뭔가 : 행이 많이 들어

query = session.query(User.firstname, User.lastname, Address.address).filter(Address.user_id == User.id) 
    for row in query.all(): 
     # firstname, lastname, address = row 
     rows.append(row) 

, 나는 해결책이 있다고 생각하지만, 당신은 당신의 자신의 모델을 정의하고 쿼리에서 LIMIT의를 사용해야합니다. 문서 및 자습서가 부족하여 쉽지 않습니다.

그리고 특별한 언급이없는 것처럼 주소 및 사용자 클래스에 __init__ 메서드를 정의 할 필요가 없습니다. , SQLAlchemy가 자동으로이 작업을 수행 할 수 있습니다. 또한 열 정의에 직접 기본값을 정의 할 수 있습니다.

업데이트 : 예를 들어 QTableWidgetItem.setData을 사용하는 경우 두 번 클릭 할 때 사용자를 삭제하려고한다고 가정 해 봅시다. itemDoubleClicked 신호를 사용합니다.

# in the __init__ function 
self.table.itemDoubleClicked.connect(self.onItemDoubleClick) 

# in onItemDoubleClicked function 
def onItemDoubleClicked(self, item): 
    # Every data has a role, you can specify your own (it's an integer) as long as it's greater than UserRole. Others are used internally, like DisplayRole and some others you can find in the QtCore package. 
    # You can use data with other widgets also, not just TableWidgets. 
    user = item.data(QtCore.Qt.UserRole+1) 
    # you get a session however you want, then delete the user. This object is the same as the one you passed earlier when creating the item, it can be whatever you like. 
    session.delete(user) 
    session.commit() 
+0

좋아요. 그것의 늦은 그래서 지금 그것을 시도 할 수 없습니다. 당신이 설명해 줄 수 있습니까? table_item.setData (QtCore.Qt.UserRole + 1, user) – jbbiomed

+0

이것은 실제 사용자 개체를 조작 할 수 있으며 그의 이름을 표시하는 것뿐만 아니라 (예를 들어) 사용할 수 있도록하기 위해 사용됩니다. 나는 예를 보여주기 위해 나의 대답을 업데이트 할 것이다. – jadkik94

+0

설명해 주셔서 감사드립니다. 나는 당신이 게시 한 첫 번째 코드에서 간결한 것으로 보이며 적절한 사용자에게 참조를 쉽게 추가 할 수 있으며 사용중인 마법은 없다고 가정합니다. – jbbiomed