Lesson 6 : A list with relations

Download lesson [here]

In this lesson, a collection of records is presented as a Qt list on the left and a form corresponding to an individual record is on the right, while user can interact with the form, create new entries, delete old ones and modify the existing ones.

For persons of a certain type (“PersonRowExtended”), we can mark up their favorite foods from a list. This is achieved with ListEditColumn (see below) that creates a relation from rows of type “PersonRowExtended” to the document collection listing different kinds of foods (“food_collection”).

import sys
# from PyQt5 import QtWidgets, QtCore, QtGui # Qt5
from PySide2 import QtWidgets, QtCore, QtGui
from cute_mongo_forms.column import LineEditColumn, ListEditColumn, CheckBoxColumn
from cute_mongo_forms.row import ColumnSpec, Row
from cute_mongo_forms.container import List, FormSet, EditFormSet
from cute_mongo_forms.db import SimpleCollection

Databases, Row types, containers (FormSets, etc.) are all encapsulated into a single class that describes the data model

class DataModel:


  def __init__(self):
    self.define()
    self.initDB()

  def define(self):
    """Define column patterns and databases
    """
    class FoodRow(Row):
      columns=[
        ColumnSpec(LineEditColumn, key_name="name", label_name="Name"),
        ColumnSpec(LineEditColumn, key_name="price",label_name="Price"),
        ColumnSpec(CheckBoxColumn, key_name="spicy",label_name="Is spicy")
      ]
    self.FoodRow=FoodRow

    self.food_collection =SimpleCollection(filename="food_test.db",row_classes=[self.FoodRow])

    class PersonRow(Row):
      columns=[
        ColumnSpec(LineEditColumn, key_name="firstname", label_name="First Name"),
        ColumnSpec(LineEditColumn, key_name="surname",   label_name="Surname"),
        ColumnSpec(LineEditColumn, key_name="address",   label_name="Address"),
        ColumnSpec(CheckBoxColumn, key_name="married",   label_name="Is married")
      ]
    self.PersonRow=PersonRow

    class PersonRowExtended(Row):
      columns=[
        ColumnSpec(LineEditColumn, key_name="firstname", label_name="First Name"),
        ColumnSpec(LineEditColumn, key_name="secondname",label_name="Second Name"),
        ColumnSpec(LineEditColumn, key_name="surname",   label_name="Surname"),
        ColumnSpec(LineEditColumn, key_name="address",   label_name="Address"),
        # in the following, we're referring to self.food_collection and there, to the columns with keys "_id" and "name".  The ListEditColumn itself is a list of foreign_keys
        ColumnSpec(ListEditColumn, key_name="foods",     label_name="Favorite foods",  collection=self.food_collection, foreign_label_name="name")
      ]
    self.PersonRowExtended=PersonRowExtended

    self.collection =SimpleCollection(filename="simple_test.db",row_classes=[PersonRow,PersonRowExtended])

    class PersonList(List):
      def makeLabel(self,entry):
        try:
          st=entry["firstname"]+" "+entry["surname"]
        except KeyError:
          st="?"
        return st
    self.PersonList=PersonList


  def initDB(self):
    """Write some entries to databases
    """
    self.collection.new(self.PersonRow,{"firstname":"Paavo",  "surname":"Vayrynen",  "address":"Koukkusaarentie 1", "married":True} )
    self.collection.new(self.PersonRow,{"firstname":"Martti", "surname":"Ahtisaari", "address":"Lokkisaarentie 1",  "married":True} )

    # add some foods
    self.food_collection.new(self.FoodRow,{"name":"Hamburger","price":10, "spicy":False})
    self.food_collection.new(self.FoodRow,{"name":"Hotdog",   "price":50, "spicy":False})
    self.food_collection.new(self.FoodRow,{"name":"Freedom Fries",   "price":10, "spicy":False})
    self.food_collection.new(self.FoodRow,{"name":"Bacalao",   "price":100,"spicy":False})
    self.food_collection.new(self.FoodRow,{"name":"Piparra",   "price":1,  "spicy":True})

    # get ids of some foods ..
    bacalao=list(self.food_collection.get(query={"name":"Bacalao"}))[0]["_id"]
    piparra=list(self.food_collection.get(query={"name":"Piparra"}))[0]["_id"]

    self.collection.new(self.PersonRowExtended,{"firstname":"Juho", "secondname":"Kustaa","surname":"Paasikivi", "address":"Kontulankaari 1", "foods":[] })
    self.collection.new(self.PersonRowExtended,{"firstname":"Esko", "secondname":"Iiro",  "surname":"Seppänen",  "address":"Mellunraitti 3",  "foods":[bacalao, piparra] })

The main Qt program

class MyGui(QtWidgets.QMainWindow):


  def __init__(self,parent=None):
    super(MyGui, self).__init__()
    self.initVars()
    self.setupUi()


  def initVars(self):
    # Connect to db, define column patters (i.e. rows),
    self.data_model=DataModel()


  def setupUi(self):
    self.setGeometry(QtCore.QRect(100,100,800,800))
    self.w=QtWidgets.QWidget(self)
    self.setCentralWidget(self.w)
    self.lay=QtWidgets.QHBoxLayout(self.w)

    # Create a list
    self.lis=self.data_model.PersonList(collection=self.data_model.collection)

    # Get lists's widget
    self.lis.widget.setParent(self.w)

    # Add to main layout
    self.lay.addWidget(self.lis.widget)

    # Create a group of forms
    self.formset=EditFormSet(collection=self.data_model.collection)

    # Get form's widget and set it's parent to the current main widget
    self.formset.widget.setParent(self.w)

    # Add formset to layout
    self.lay.addWidget(self.formset.widget)

    # Inform formset about the item in question.  "self.lis.widget" is a QListWidget instance.
    self.lis.widget.currentItemChanged. connect(self.formset.chooseForm_slot)

    # inform list when a new record has been added or when a record has been saved
    self.formset.signals.new_record.    connect(self.lis.update_slot)
    self.formset.signals.save_record.   connect(self.lis.update_slot)

Start the Qt program

if (__name__=="__main__"):
  app=QtWidgets.QApplication([])
  gui=MyGui()
  gui.show()
  app.exec_()