A Local Exchange Trade System

In this tutorial we imagine a whole Lino project from scratch. The fictive application described here is probably a bit too simple for a real-life website. But we imagine that this is what our customer asked us to do. (More about the Lino application development process in About analysis.)


The fictive application we are going to write is a website of a Local Exchange Trade System group (LETS). The members of that site would register the products and services they want to sell or to buy. The goal is to connect the providers and the customers.

Database structure

  • Products : one row for every product or service. We keep it simple and just record the designation for our products. We don't even record a price.

  • Members : the people who use this site to register their offers and demands. For each member we record their contact data such as place and email.

  • An Offer is when a given member declares that they want to sell a given product.

  • A Demand is when a given member declares that they want to buy a given product.

  • Every member is located in a given Place. And in a future version we want to add filtering on offers and demands limited to the place.

Here is a graphical representation of the database structure:

digraph foo  {

     graph [renderer="neato"]

     node [shape=box]
     node [style=filled]
         node [fontname="times bold", fillcolor=red]
            Product Member
         node [fontname="times" fillcolor=gold]  Offer  Demand
         node [fontname="times italic" fillcolor=lightblue]  Place

     Product -> Offer[arrowhead="inv"]
     Product -> Demand[arrowhead="inv"]

     Offer -> Member[taillabel="provider", labelangle="-90", labeldistance="2"];
     Demand -> Member[taillabel="customer", labelangle="90", labeldistance="2"];
     Member ->  Place;


You shoud do such diagrams interactively, together with the customer. Above picture has been realized using graphviz. You might prefer Dia which renders it as follows:


There are many methodologies for visualizing a database model (UML, IDEF1X), and above style is just our favourite because it is so simple, intuitive and useful. The basic rules are:

  • Every node on the diagram represents a database model.

  • Every arrow on the diagram represents a ForeignKey. We prefer to use the word pointer instead of ForeignKey when talking with a customer because that's more intuitive.

  • We display the name of a pointer only if it differs from the model it points to. For example the arrow from Offer to Product is a FK field called product, defined on the Offer model. We do not display the name product on our diagram because that would be a waste of place.

The colors of this diagram are a convention for grouping the models into three "data categories":

  • red is for master data (i.e. relatively stable data)

  • yellow is for moving data (i.e. data which changes relatively often)

  • blue is for configuration data (i.e. data which is rather in background and accessible only to site administrators)

Note about many-to-many relationships

There are two many-to-many relationships between Member and Product:

  • A given member can offer multiple products, and a given product can be offered by multiple members. We can call this the providers of a product.

  • A given member can want multiple products, and a given product can be wanted by multiple members. We can call this the customers of a product.

Using Django's interface for many-to-many relationships, we can express this as follows:

providers = models.ManyToManyField(
    'lets.Member', through='lets.Offer', related_name='offered_products')
customers = models.ManyToManyField(
    'lets.Member', through='lets.Demand', related_name='wanted_products')

Which you can read as follows:

  • Offer is the "intermediate model" used "to govern the m2m relation Product.providers / Member.offered_products.

  • Demand is the intermediate model used to govern the m2m relation Product.customers / Member.wanted_products.

A ManyToManyField is originally a shortcut for telling Django to create an automatic, "invisible", additional model, with two ForeignKey fields. But in most real-life situations you anyway want to define what Django calls "extra fields on many-to-many relationships", and thus you must explicitly name that "intermediate model" of your ManyToManyField. That's why we don't use ManyToManyField and recommend instead to always define an explicit intermediate models for your m2m relations.

Writing a prototype

With above information you should be ready to write a "first draft" or "prototype".

For this tutorial we wrote actually two prototypes. In the second variant the members are "polymorphic": they can be either customers or suppliers, or both. This is an example of multi-table inheritance and how you can use it with Lino's Polymorphic mixin.




The LETS application specs (v1)


The LETS application specs (v2)

Note the difference between "code" and "specs". The code directory contains runnable Python code and maybe application-specific configuration files. A copy of this would be needed on a production site. The specs is a Sphinx documentation tree and contains mainly .rst files. These are not needed on a production site.

Please explore these projects and try to get them running. If you have installed a Lino contributor environment, you can simply do:

$ go lets1
$ python manage.py prep
$ python manage.py runserver

And point your browser to

Form layouts

Note the detail_layout attributes of certain tables. They define the layout of the detail window for these database models (a detail window is what Lino opens when the user double-clicks on a given row).

The detail window of a Product should show the data fields and two slave tables, one showing the the offers and another with the demands for this product.

Here is the code for this:

detail_layout = """
id name
OffersByProduct DemandsByProduct


When seeing the code on the left, you should be able to imagine something like the picture on the right.

The web interface

Here are some screenshots.

../../_images/a.png ../../_images/b1.png ../../_images/c.png ../../_images/d.png ../../_images/e.png ../../_images/members_insert1.png