About this module

Overview

Word of warning: this is not your traditional database/object mapper - if you need a lightweight orm for mongo, check out this project instead.

This module is about creating graphical user interfaces in Qt that interact with an underlying programming logic and a document database (say, MongoDB) in an automatic fashion.

Both the view, database patterns (“model” or “schema”) and field validations are declared in one-shot:

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")
  ]

This declares a column structure in a document database (“schema”). It also declares an autogenerated Qt form that is presented to the user (view). The Qt form can also validate the input fields with a QValidator.

Relations are declared like this:

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"),
    # let's specify a relation to "food_collection"
    ColumnSpec(ListEditColumn, key_name="foods",     label_name="Favorite foods",  collection=food_collection, foreign_label_name="name")
  ]

In the PersonRowExtended row class, the last columns corresponds to a list (ListEditColumn) where user can choose several foods. The details of each food are found in the food_collection (that can be a simple collection or a MongoDB).

A collection is instantiated by passing it the row classes:

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

In this example, the collection can have two different row structures corresponding to PersonRow and PersonRowExtended.

What it does?

Once you instantiate a row

person_row =PersonRow()

You’ll get for “free” the corresponding QWidget form (at the “widget” member) that you can parent to your Qt program, like this:

person_row.widget # the QtWidget form
person_row.widget.setParent(some_parent_widget) # let's parent it to someone

However, normally you don’t instantiate the Row classes (and the associated QtWidget forms) yourself, but leave that to “containers”, such as the FormSet container:

formset=FormSet(collection=collection)

Formset gets from “collection” the Row classes (that we just declared - see above), instantiates them and places their widgets correctly in place inside the container’s own widget (accessible in formset.widget).

The container uses the database to update the data in the Row’s QtWidget forms automatically, displays the the correct form in question (PersonRow or PersonRowExtended) and writes the database, according to user’s interaction with the QtWidget forms.

In a more traditional db/object mapper, the data is placed in an “intermediate layer”, i.e. into an object that gives easy access to the data and may perform type etc. checking on the data. Here that object is the QtWidget itself! If you want certain type of constraints to the data, create a custom Column class and there, use a QValidator. This way your data is always validated.

Try it out

Brave enough to give it a try?

An example tells more than thousand explanatory words, so take a look at the tutorial.

The prerequisites are, that you are quite familiar with Python, Qt and their combination, PyQt.

There is a more complex example available (with a larger schema and several relations using MongoDB) here.