2012-05-16 18 views
6

Moje pytanie brzmi, jak skonfigurować model deklaracji SQLAlchemy, do którego można uzyskać dostęp z klasy QTableView PySide.Projekt "modelu" dla QTableView w PySide + SQLAlchemy.

Po prostu staram się przede wszystkim wdrożyć przód dla Object Relational tutorial

Niestety mam kilka punktów w błąd. Spróbuję wyjaśnić, gdzie jestem.

Mam śledzony samouczek SQLAlchemy do punktu, w którym mam dwie powiązane tabele i można manipulować/kwerendy tych bez żadnych problemów. Próba ustanowienia QTableView class najwyraźniej wymaga setData() method z mojego własnego modelu lub użycie domyślnego modelu wymaga setItem() method.

Pytanie więc, jak zaprojektować model. Zakładam, że oznacza to zdefiniowanie jednej z tych dwóch metod do zapytania/modyfikacji bazy danych. Nie wiem, jak to zrobić.

Model ma być jak imię i nazwisko użytkownika powtarzane w kilku wierszach, dopóki wszystkie adresy nie zostaną wyświetlone, a następnie przejść do następnego użytkownika. Mogę to zrobić za pomocą zagnieżdżonych pętli, aby wydrukować to w wierszu polecenia, ale nie myślę, że zrobienie dużej listy jest drogą do zrobienia, ponieważ wydaje się, że pokonanie punktu posiadania bazy danych w pierwszej kolejności ...

Nie wiem też, co się stanie, gdy baza danych się powiększy, czy cała tabela zostanie utworzona i będzie przechowywana w pamięci, czy też Qt wczytuje wiersze i kolumny, gdy będą one wyświetlane, gdy użytkownik przewinie?

Dużo tekstu tutaj przykro, ale staram się być jasne. Jeśli są dodatkowe rzeczy, które mógłbym dodać, daj mi znać. Lub jeśli jestem całkowicie na niewłaściwym torze ...

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 

Odpowiedz

6

Po pierwsze, zapomnij o zapytaniu i użyj pętli, której używasz. To, czego szukasz w interfejsie użytkownika, to podstawowa sprawa. Z braku dokumentów stwierdziłem, że najlepiej jest użyć QTableWidget (lub cokolwiek innego, co jest QWhateverWidget) lepiej niż QWhateverView w przypadku podstawowych rzeczy. Nie musisz definiować własnego modelu dla prostych rzeczy. Pokażę ci, jak to zrobić za pomocą QTableWidget. Musisz utworzyć QTableWidgetItem dla każdej komórki w (wierszu, kolumnie). Napotkany problem polegał na konieczności ustawienia liczby wierszy przed ich dodaniem. W każdym razie, tutaj:

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

Inną rzeczą, można rozważyć użycie jest QTreeWidget, który obsługuje wiele kolumn, i można zrobić to wyglądać jak stół, ale bez edytowalnych komórek domyślnie i może spełnić swoje dane lepiej tutaj.

Teraz dla zapytania możesz chcieć zrobić jedno pojedyncze zapytanie, aby uniknąć zapętlenia wyników i konieczności wykonania jednego dodatkowego zapytania dla każdego użytkownika. Coś jak:

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) 

Dla wielu rzędach, myślę, że jest to rozwiązanie, ale wtedy musiałby określić swój własny model i używać LIMIT w twoich zapytaniami. Z powodu braku dokumentacji i samouczków nie jest to takie proste ...

I na marginesie nie musisz definiować metody __init__ na swoich zajęciach Adres i Użytkownika, ponieważ nie robisz nic specjalnego , SQLAlchemy może zrobić to automatycznie dla ciebie. Możesz zdefiniować wartości domyślne bezpośrednio w definicji kolumny.

UPDATE: na przykład za pomocą QTableWidgetItem.setData, powiedzmy, że chcemy usunąć użytkownika po dwukrotnym kliknięciu. Wykorzystamy sygnał 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

Wygląda dobrze. Jest już za późno, więc nie może tego teraz wypróbować. Czy możesz wyjaśnić table_item.setData (QtCore.Qt.UserRole + 1, użytkownik)? – jbbiomed

+0

Jest to używane w celu rzeczywistego manipulowania obiektem użytkownika, a nie tylko wyświetlania jego nazwy ... (na przykład). Zaktualizuję moją odpowiedź, aby pokazać przykład. – jadkik94

+0

fajne dzięki za wyjaśnienie. Przypuszczam, że jesteś zwięzły w pierwszym opublikowanym przez ciebie kodzie i mogę łatwo dodać odniesienie do właściwego użytkownika we właściwym miejscu i nie ma żadnej magii, której używasz. – jbbiomed

Powiązane problemy