doc/book/en/04-develop-views.en.txt
author Nicolas Chauvat <nicolas.chauvat@logilab.fr>
Fri, 14 Nov 2008 11:05:32 +0100
changeset 74 9a9fe515934d
child 81 f5886815126b
permissions -rw-r--r--
[doc] reuse the lax book

.. -*- coding: utf-8 -*-


Developing the user interface with Views
========================================

Before moving to this section, make sure you read the `Essentials`
section in the Introduction.

Tip: when modifying views, you do not need to restart the local 
server. Just save the file in your editor and reload the page in your
browser to see the changes.

The selection/view principle
----------------------------

With `LAX`, views are defined by Python classes. A view includes :

- an identifier (all objects in `LAX` are entered in a registry
  and this identifier will be used as a key)
  
- a filter to select the resulsets it can be applied to

`LAX` provides a lot of standard views, for a complete list, you
will have to read the code in directory ``ginco/web/views/`` (XXX
improve doc).

For example, the view named ``primary`` is the one used to display
a single entity.

If you want to change the way a ``BlogEntry`` is displayed, just
override the view ``primary`` in ``BlogDemo/views.py`` ::

  01. from ginco.web.views import baseviews
  02.
  03. class BlogEntryPrimaryView(baseviews.PrimaryView):
  04.
  05.     accepts = ('BlogEntry',)
  06.
  07.     def cell_call(self, row, col):
  08.         entity = self.entity(row, col)
  09.         self.w(u'<h1>%s</h1>' % entity.title)
  10.         self.w(u'<p>published on %s in category %s</p>' % \
  11.                (entity.publish_date.strftime('%Y-%m-%d'), entity.category))
  12.         self.w(u'<p>%s</p>' % entity.text)

The above source code defines a new primary view (`line 03`) for
``BlogEntry`` (`line 05`). 

Since views are applied to resultsets and resulsets can be tables of
data, it is needed to recover the entity from its (row,col)
coordinates (`line 08`). We will get to this in more detail later.

The view has a ``self.w()`` method that is used to output data. Here `lines
09-12` output HTML tags and values of the entity's attributes.

When displaying same blog entry as before, you will notice that the
page is now looking much nicer.

.. image:: images/lax-book.09-new-view-blogentry.en.png
   :alt: blog entries now look much nicer

Let us now improve the primary view of a blog ::

  01. class BlogPrimaryView(baseviews.PrimaryView):
  02. 
  03.     accepts = ('Blog',)
  04.
  05.     def cell_call(self, row, col):
  06.         entity = self.entity(row, col)
  07.         self.w(u'<h1>%s</h1>' % entity.title)
  08.         self.w(u'<p>%s</p>' % entity.description)
  09.         rset = self.req.execute('Any E WHERE E entry_of B, B eid "%s"' % entity.eid)
  10.         self.wview('primary', rset)

In the above source code, `lines 01-08` are similar to the previous
view we defined.

At `line 09`, a simple request in made to build a resultset with all
the entities linked to the current ``Blog`` entity by the relationship
``entry_of``. The part of the framework handling the request knows
about the schema and infer that such entities have to be of the
``BlogEntry`` kind and retrieves them.

The request returns a selection of data called a resultset. At 
`line 10` the view 'primary' is applied to this resultset to output
HTML. 

**This is to be compared to interfaces and protocols in object-oriented
languages. Applying a given view to all the entities of a resultset only
requires the availability, for each entity of this resultset, of a
view with that name that can accepts the entity.**

Assuming we added entries to the blog titled `MyLife`, displaying it
now allows to read its description and all its entries.

.. image:: images/lax-book.10-blog-with-two-entries.en.png
   :alt: a blog and all its entries

**Before we move forward, remember that the selection/view principle is
at the core of `LAX`. Everywhere in the engine, data is requested
using the RQL language, then HTML/XML/text/PNG is output by applying a
view to the resultset returned by the query. That is where most of the
flexibility comes from.**

[WRITE ME]

* implementing interfaces, calendar for blog entries
* show that a calendar view can export data to ical

We will implement the ginco.interfaces.ICalendarable interfaces on
entities.BloEntry and apply the OneMonthCalendar and iCalendar views
to resultsets like "Any E WHERE E is BlogEntry"

* create view "blogentry table" with title, publish_date, category

We will show that by default the view that displays 
"Any E,D,C WHERE E publish_date D, E category C" is the table view.
Of course, the same can be obtained by calling
self.wview('table',rset)

* in view blog, select blogentries and apply view "blogentry table"
* demo ajax by filtering blogentry table on category

we did the same with 'primary', but with tables we can turn on filters
and show that ajax comes for free.