[doc/book] move a big chunk of primary view customisation example in the primary view chapter stable
authorAurelien Campeas <aurelien.campeas@logilab.fr>
Wed, 14 Apr 2010 18:10:47 +0200
branchstable
changeset 5262 ebd90d2a5639
parent 5261 829f575dd853
child 5263 196eb979318f
[doc/book] move a big chunk of primary view customisation example in the primary view chapter
doc/book/en/development/devweb/views.rst
doc/book/en/development/webstdlib/primary.rst
doc/book/en/tutorials/base/index.rst
--- a/doc/book/en/development/devweb/views.rst	Wed Apr 14 18:10:09 2010 +0200
+++ b/doc/book/en/development/devweb/views.rst	Wed Apr 14 18:10:47 2010 +0200
@@ -8,45 +8,50 @@
 the development of a web application and how it has been implemented
 in *CubicWeb*.
 
-We'll start with a description of the interface providing you with a basic
-understanding of the available classes and methods, then detail the view
-selection principle which makes *CubicWeb* web interface very flexible.
+We'll start with a description of the interface providing you with a
+basic understanding of the available classes and methods, then detail
+the view selection principle.
 
-A `View` is an object applied to another object such as an entity.
+A `View` is an object responsible for the rendering of data from the
+model into an end-user consummable form. They typically churn out an
+XHTML stream, but there are views concerned with email other non-html
+outputs.
 
 Basic class for views
 ~~~~~~~~~~~~~~~~~~~~~
 
 Class `View` (`cubicweb.view`)
-`````````````````````````````````````
+```````````````````````````````
 
 This class is an abstraction of a view class, used as a base class for every
 renderable object such as views, templates, graphic components, etc.
 
-A `View` is instantiated to render a result set or part of a result set. `View`
-subclasses may be parametrized using the following class attributes:
+A `View` is instantiated to render a result set or part of a result
+set. `View` subclasses may be parametrized using the following class
+attributes:
 
 * `templatable` indicates if the view may be embedded in a main
-  template or if it has to be rendered standalone (i.e. XML views must
-  not be embedded in the main template for HTML pages)
+  template or if it has to be rendered standalone (i.e. pure XML views
+  must not be embedded in the main template of HTML pages)
 
 * if the view is not templatable, it should set the `content_type`
-  class attribute to the correct MIME type (text/xhtml by default)
+  class attribute to the correct MIME type (text/xhtml being the
+  default)
 
 * the `category` attribute may be used in the interface to regroup
-  related objects together
+  related view kinds together
 
-A view writes to its output stream thanks to its attribute `w` (an
-`UStreamIO`, except for binary views).
+A view writes to its output stream thanks to its attribute `w` (the
+append method of an `UStreamIO`, except for binary views).
 
 At instantiation time, the standard `_cw` and `cw_rset` attributes are
 added and the `w` attribute will be set at rendering time.
 
-The basic interface for views is as follows (remember that the result set has a
-tabular structure with rows and columns, hence cells):
+The basic interface for views is as follows (remember that the result
+set has a tabular structure with rows and columns, hence cells):
 
 * `render(**context)`, render the view by calling `call` or
-  `cell_call` depending on the given parameters
+  `cell_call` depending on the context
 
 * `call(**kwargs)`, call the view for a complete result set or null
   (the default implementation calls `cell_call()` on each cell of the
@@ -93,7 +98,7 @@
         cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
 
 
-- Using custom selector
+- Using a custom selector
 
 .. sourcecode:: python
 
@@ -107,148 +112,6 @@
 
 
 
-Example of view customization and creation
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-We'll show you now an example of a ``primary`` view and how to customize it.
-
-If you want to change the way a ``BlogEntry`` is displayed, just override
-the method ``cell_call()`` of the view ``primary`` in ``BlogDemo/views.py``:
-
-.. sourcecode:: python
-
-  from cubicweb.selectors import implements
-  from cubicweb.web.views.primary improt Primaryview
-
-  class BlogEntryPrimaryView(PrimaryView):
-    __select__ = PrimaryView.__select__ & implements('BlogEntry')
-
-      def render_entity_attributes(self, entity):
-          self.w(u'<p>published on %s</p>' %
-                 entity.publish_date.strftime('%Y-%m-%d'))
-          super(BlogEntryPrimaryView, self).render_entity_attributes(entity)
-
-The above source code defines a new primary view for
-``BlogEntry``. The `id` class attribute is not repeated there since it
-is inherited through the `primary.PrimaryView` class.
-
-The selector for this view chains the selector of the inherited class
-with its own specific criterion.
-
-The view method ``self.w()`` is used to output data. Here `lines
-08-09` output HTML for the publication date of the entry.
-
-.. 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
-
-.. sourcecode:: python
-
- from logilab.mtconverter import xml_escape
- from cubicweb.selectors import implements, one_line_rset
- from cubicweb.web.views.primary import Primaryview
-
- class BlogPrimaryView(PrimaryView):
-     __regid__ = 'primary'
-     __select__ = PrimaryView.__select__ & implements('Blog')
-     rql = 'Any BE ORDERBY D DESC WHERE BE entry_of B, BE publish_date D, B eid %(b)s'
-
-     def render_entity_relations(self, entity):
-         rset = self._cw.execute(self.rql, {'b' : entity.eid})
-         for entry in rset.entities():
-             self.w(u'<p>%s</p>' % entry.view('inblogcontext'))
-
- class BlogEntryInBlogView(EntityView):
-     __regid__ = 'inblogcontext'
-     __select__ = implements('BlogEntry')
-
-     def cell_call(self, row, col):
-         entity = self.cw_rset.get_entity(row, col)
-         self.w(u'<a href="%s" title="%s">%s</a>' %
-                entity.absolute_url(),
-                xml_escape(entity.content[:50]),
-                xml_escape(entity.description))
-
-This happens in two places. First we override the
-render_entity_relations method of a Blog's primary view. Here we want
-to display our blog entries in a custom way.
-
-At `line 10`, a simple request is made to build a result set 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 infers that such entities have to be of the
-``BlogEntry`` kind and retrieves them (in the prescribed publish_date
-order).
-
-The request returns a selection of data called a result set. Result
-set objects have an .entities() method returning a generator on
-requested entities (going transparently through the `ORM` layer).
-
-At `line 13` the view 'inblogcontext' is applied to each blog entry to
-output HTML. (Note that the 'inblogcontext' view is not defined
-whatsoever in *CubicWeb*. You are absolutely free to define whole view
-families.) We juste arrange to wrap each blogentry output in a 'p'
-html element.
-
-Next, we define the 'inblogcontext' view. This is NOT a primary view,
-with its well-defined sections (title, metadata, attribtues,
-relations/boxes). All a basic view has to define is cell_call.
-
-Since views are applied to result sets which can be tables of data, we
-have to recover the entity from its (row,col)-coordinates (`line
-20`). Then we can spit some HTML.
-
-But careful: all strings manipulated in *CubicWeb* are actually
-unicode strings. While web browsers are usually tolerant to incoherent
-encodings they are being served, we should not abuse it. Hence we have
-to properly escape our data. The xml_escape() function has to be used
-to safely fill (X)HTML elements from Python unicode strings.
-
-
-**This is to be compared to interfaces and protocols in object-oriented
-languages. Applying a given view called 'a_view' to all the entities
-of a result set only requires to have for each entity of this result set,
-an available view called 'a_view' which accepts the entity.**
-
-**Instead of merely using type based dispatch, we do predicate dispatch
-which is quite more powerful.**
-
-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 *CubicWeb*. Everywhere in the engine, data is requested
-using the RQL language, then HTML/XML/text/PNG is output by applying a
-view to the result set 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 `cubicweb.interfaces.ICalendarable` interfaces on
-entities.BlogEntry and apply the OneMonthCalendar and iCalendar views
-to result sets 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.
-[FILLME]
-
 
 XML views, binaries views...
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -258,8 +121,9 @@
 by the main template (see above), you have to:
 
 * set the attribute `templatable` of the class to `False`
-* set, through the attribute `content_type` of the class, the MIME type generated
-  by the view to `application/octet-stream`
+* set, through the attribute `content_type` of the class, the MIME
+  type generated by the view to `application/octet-stream` or any
+  relevant and more specialised mime type
 
 For views dedicated to binary content creation (like dynamically generated
 images), we have to set the attribute `binary` of the class to `True` (which
--- a/doc/book/en/development/webstdlib/primary.rst	Wed Apr 14 18:10:09 2010 +0200
+++ b/doc/book/en/development/webstdlib/primary.rst	Wed Apr 14 18:10:47 2010 +0200
@@ -201,3 +201,112 @@
 the default rendering does not answer your need so that you can focus on the specific
 method (from the list above) that needs to be modified. We do not advise you to
 overwrite ``render_entity`` unless you want a completely different layout.
+
+Example of customization and creation
+-------------------------------------
+
+We'll show you now an example of a ``primary`` view and how to customize it.
+
+We continue along the basic tutorial :ref:`tuto_blog`.
+
+If you want to change the way a ``BlogEntry`` is displayed, just override
+the method ``cell_call()`` of the view ``primary`` in ``BlogDemo/views.py``:
+
+.. sourcecode:: python
+
+  from cubicweb.selectors import implements
+  from cubicweb.web.views.primary improt Primaryview
+
+  class BlogEntryPrimaryView(PrimaryView):
+    __select__ = PrimaryView.__select__ & implements('BlogEntry')
+
+      def render_entity_attributes(self, entity):
+          self.w(u'<p>published on %s</p>' %
+                 entity.publish_date.strftime('%Y-%m-%d'))
+          super(BlogEntryPrimaryView, self).render_entity_attributes(entity)
+
+The above source code defines a new primary view for
+``BlogEntry``. The `id` class attribute is not repeated there since it
+is inherited through the `primary.PrimaryView` class.
+
+The selector for this view chains the selector of the inherited class
+with its own specific criterion.
+
+The view method ``self.w()`` is used to output data. Here `lines
+08-09` output HTML for the publication date of the entry.
+
+.. 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
+
+.. sourcecode:: python
+
+ from logilab.mtconverter import xml_escape
+ from cubicweb.selectors import implements, one_line_rset
+ from cubicweb.web.views.primary import Primaryview
+
+ class BlogPrimaryView(PrimaryView):
+     __regid__ = 'primary'
+     __select__ = PrimaryView.__select__ & implements('Blog')
+     rql = 'Any BE ORDERBY D DESC WHERE BE entry_of B, BE publish_date D, B eid %(b)s'
+
+     def render_entity_relations(self, entity):
+         rset = self._cw.execute(self.rql, {'b' : entity.eid})
+         for entry in rset.entities():
+             self.w(u'<p>%s</p>' % entry.view('inblogcontext'))
+
+ class BlogEntryInBlogView(EntityView):
+     __regid__ = 'inblogcontext'
+     __select__ = implements('BlogEntry')
+
+     def cell_call(self, row, col):
+         entity = self.cw_rset.get_entity(row, col)
+         self.w(u'<a href="%s" title="%s">%s</a>' %
+                entity.absolute_url(),
+                xml_escape(entity.content[:50]),
+                xml_escape(entity.description))
+
+This happens in two places. First we override the
+render_entity_relations method of a Blog's primary view. Here we want
+to display our blog entries in a custom way.
+
+At `line 10`, a simple request is made to build a result set 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 infers that such entities have to be of the
+``BlogEntry`` kind and retrieves them (in the prescribed publish_date
+order).
+
+The request returns a selection of data called a result set. Result
+set objects have an .entities() method returning a generator on
+requested entities (going transparently through the `ORM` layer).
+
+At `line 13` the view 'inblogcontext' is applied to each blog entry to
+output HTML. (Note that the 'inblogcontext' view is not defined
+whatsoever in *CubicWeb*. You are absolutely free to define whole view
+families.) We juste arrange to wrap each blogentry output in a 'p'
+html element.
+
+Next, we define the 'inblogcontext' view. This is NOT a primary view,
+with its well-defined sections (title, metadata, attribtues,
+relations/boxes). All a basic view has to define is cell_call.
+
+Since views are applied to result sets which can be tables of data, we
+have to recover the entity from its (row,col)-coordinates (`line
+20`). Then we can spit some HTML.
+
+.. warning::
+
+  Be careful: all strings manipulated in *CubicWeb* are actually
+  unicode strings. While web browsers are usually tolerant to
+  incoherent encodings they are being served, we should not abuse
+  it. Hence we have to properly escape our data. The xml_escape()
+  function has to be used to safely fill (X)HTML elements from Python
+  unicode strings.
+
+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
--- a/doc/book/en/tutorials/base/index.rst	Wed Apr 14 18:10:09 2010 +0200
+++ b/doc/book/en/tutorials/base/index.rst	Wed Apr 14 18:10:47 2010 +0200
@@ -2,6 +2,7 @@
 
 .. _Tutorial:
 
+.. _tuto_blog:
 
 Building a simple blog
 ======================