doc/book/en/development/devweb/views.rst
branchtls-sprint
changeset 1714 a721966779be
child 2172 cf8f9180e63e
equal deleted inserted replaced
1499:fd8751c3f3ee 1714:a721966779be
       
     1 Views
       
     2 -----
       
     3 
       
     4 This chapter aims to describe the concept of a `view` used all along
       
     5 the development of a web application and how it has been implemented
       
     6 in `CubicWeb`.
       
     7 
       
     8 We'll start with a description of the interface providing you with a basic
       
     9 understanding of the classes and methods available, then detail the view
       
    10 selection principle which makes `CubicWeb` web interface very flexible.
       
    11 
       
    12 A `View` is an object applied to another object such as an entity.
       
    13 
       
    14 Basic class for views
       
    15 ---------------------
       
    16 
       
    17 Class `View` (`cubicweb.view`)
       
    18 `````````````````````````````````````
       
    19 
       
    20 This class is an abstraction of a view class, used as a base class for every
       
    21 renderable object such as views, templates, graphic components, etc.
       
    22 
       
    23 A `View` is instantiated to render a result set or part of a result set. `View`
       
    24 subclasses may be parametrized using the following class attributes:
       
    25 
       
    26     * `templatable` indicates if the view may be embeded in a main
       
    27       template or if it has to be rendered standalone (i.e. XML views
       
    28       must not be embeded in the main template for HTML pages)
       
    29     * if the view is not templatable, it should set the `content_type` class
       
    30       attribute to the correct MIME type (text/xhtml by default)
       
    31     * the `category` attribute may be used in the interface to regroup related
       
    32       objects together
       
    33 
       
    34 At instantiation time, the standard `req`, `rset`, and `cursor`
       
    35 attributes are added and the `w` attribute will be set at rendering
       
    36 time.
       
    37 
       
    38 A view writes to its output stream thanks to its attribute `w` (`UStreamIO`).
       
    39 
       
    40 The basic interface for views is as follows (remember that the result set has a
       
    41 tabular structure with rows and columns, hence cells):
       
    42 
       
    43 * `dispatch(**context)`, render the view by calling `call` or
       
    44   `cell_call` depending on the given parameters
       
    45 * `call(**kwargs)`, call the view for a complete result set or null (default 
       
    46   implementation calls `cell_call()` on each cell of the result set)
       
    47 * `cell_call(row, col, **kwargs)`, call the view for a given cell of a result set
       
    48 * `url()`, returns the URL enabling us to get the view with the current
       
    49   result set 
       
    50 * `view(__vid, rset, __fallback_vid=None, **kwargs)`, call the view of identifier 
       
    51   `__vid` on the given result set. It is possible to give a view identifier
       
    52   of fallback that will be used if the view requested is not applicable to the
       
    53   result set
       
    54   
       
    55 * `wview(__vid, rset, __fallback_vid=None, **kwargs)`, similar to `view` except
       
    56   the flow is automatically passed in the parameters
       
    57   
       
    58 * `html_headers()`, returns a list of HTML headers to set by the main template
       
    59 
       
    60 * `page_title()`, returns the title to use in the HTML header `title`
       
    61 
       
    62 
       
    63 Other basic view classes
       
    64 ````````````````````````
       
    65 Here are some of the subclasses of `View` defined in `cubicweb.common.view`
       
    66 that are more concrete as they relate to data rendering within the application:
       
    67 
       
    68 * `EntityView`, view applying to lines or cell containing an entity (e.g. an eid)
       
    69 * `StartupView`, start view that does not require a result set to apply to
       
    70 * `AnyRsetView`, view applied to any result set 
       
    71 * `EmptyRsetView`, view applied to an empty result set
       
    72 
       
    73 
       
    74 Examples of views class 
       
    75 -----------------------
       
    76 
       
    77 - Using `templatable`, `content_type` and HTTP cache configuration
       
    78 
       
    79 .. code-block:: python
       
    80     
       
    81 
       
    82     class RSSView(XMLView):
       
    83         id = 'rss'
       
    84         title = _('rss')
       
    85         templatable = False
       
    86         content_type = 'text/xml'
       
    87         http_cache_manager = MaxAgeHTTPCacheManager
       
    88         cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
       
    89     
       
    90 
       
    91 
       
    92 - Using custom selector
       
    93 
       
    94 .. code-block:: python
       
    95     
       
    96 
       
    97     class SearchForAssociationView(EntityView):
       
    98         """view called by the edition view when the user asks
       
    99         to search for something to link to the edited eid
       
   100         """
       
   101         id = 'search-associate'
       
   102         title = _('search for association')
       
   103         __select__ = one_line_rset() & match_search_state('linksearch') & implements('Any')
       
   104 
       
   105 
       
   106 Example of a view customization
       
   107 -------------------------------
       
   108 
       
   109 [FIXME] XXX Example needs to be rewritten as it shows how to modify cell_call which
       
   110 contredicts our advise of not modifying it.
       
   111 
       
   112 We'll show you now an example of a ``primary`` view and how to customize it.
       
   113 
       
   114 If you want to change the way a ``BlogEntry`` is displayed, just override 
       
   115 the method ``cell_call()`` of the view ``primary`` in ``BlogDemo/views.py`` ::
       
   116 
       
   117 .. code-block:: python
       
   118 
       
   119    from cubicweb.view import EntityView
       
   120    from cubicweb.selectors import implements
       
   121   
       
   122    class BlogEntryPrimaryView(EntityView):
       
   123        id = 'primary'
       
   124        __select__ =implements('Blog')
       
   125        
       
   126        def cell_call(self, row, col):
       
   127            entity = self.entity(row, col)
       
   128            self.w(u'<h1>%s</h1>' % entity.title)
       
   129            self.w(u'<p>published on %s in category %s</p>' % \
       
   130                   (entity.publish_date.strftime('%Y-%m-%d'), entity.category))
       
   131            self.w(u'<p>%s</p>' % entity.text)
       
   132 
       
   133 The above source code defines a new primary view (`line 03`) for
       
   134 ``BlogEntry`` (`line 05`). 
       
   135 
       
   136 Since views are applied to result sets which can be tables of
       
   137 data, we have to recover the entity from its (row,col)-coordinates (`line 08`).
       
   138 We will get to this in more detail later.
       
   139 
       
   140 The view method ``self.w()`` is used to output data. Here `lines
       
   141 09-12` output HTML tags and values of the entity's attributes.
       
   142 
       
   143 When displaying the same blog entry as before, you will notice that the
       
   144 page is now looking much nicer. [FIXME: it is not clear to what this refers.]
       
   145 
       
   146 .. image:: ../../images/lax-book.09-new-view-blogentry.en.png
       
   147    :alt: blog entries now look much nicer
       
   148 
       
   149 Let us now improve the primary view of a blog
       
   150 
       
   151 .. code-block:: python
       
   152 
       
   153  class BlogPrimaryView(EntityView):
       
   154      id = 'primary'
       
   155      __select__ =implements('Blog')
       
   156 
       
   157      def cell_call(self, row, col):
       
   158          entity = self.entity(row, col)
       
   159          self.w(u'<h1>%s</h1>' % entity.title)
       
   160          self.w(u'<p>%s</p>' % entity.description)
       
   161          rset = self.req.execute('Any E WHERE E entry_of B, B eid "%s"' % entity.eid)
       
   162          self.wview('primary', rset)
       
   163 
       
   164 In the above source code, `lines 01-08` are similar to the previous
       
   165 view we defined. [FIXME: defined where ?]
       
   166 
       
   167 At `line 09`, a simple request is made to build a result set with all
       
   168 the entities linked to the current ``Blog`` entity by the relationship
       
   169 ``entry_of``. The part of the framework handling the request knows
       
   170 about the schema and infer that such entities have to be of the
       
   171 ``BlogEntry`` kind and retrieves them.
       
   172 
       
   173 The request returns a selection of data called a result set. At 
       
   174 `line 10` the view 'primary' is applied to this result set to output
       
   175 HTML. 
       
   176 
       
   177 **This is to be compared to interfaces and protocols in object-oriented
       
   178 languages. Applying a given view called 'a_view' to all the entities
       
   179 of a result set only requires to have for each entity of this result set,
       
   180 an available view called 'a_view' which accepts the entity.**
       
   181 
       
   182 Assuming we added entries to the blog titled `MyLife`, displaying it
       
   183 now allows to read its description and all its entries.
       
   184 
       
   185 .. image:: ../../images/lax-book.10-blog-with-two-entries.en.png
       
   186    :alt: a blog and all its entries
       
   187 
       
   188 **Before we move forward, remember that the selection/view principle is
       
   189 at the core of `CubicWeb`. Everywhere in the engine, data is requested
       
   190 using the RQL language, then HTML/XML/text/PNG is output by applying a
       
   191 view to the result set returned by the query. That is where most of the
       
   192 flexibility comes from.**
       
   193 
       
   194 [WRITE ME]
       
   195 
       
   196 * implementing interfaces, calendar for blog entries
       
   197 * show that a calendar view can export data to ical
       
   198 
       
   199 We will implement the `cubicweb.interfaces.ICalendarable` interfaces on
       
   200 entities.BlogEntry and apply the OneMonthCalendar and iCalendar views
       
   201 to result sets like "Any E WHERE E is BlogEntry"
       
   202 
       
   203 * create view "blogentry table" with title, publish_date, category
       
   204 
       
   205 We will show that by default the view that displays 
       
   206 "Any E,D,C WHERE E publish_date D, E category C" is the table view.
       
   207 Of course, the same can be obtained by calling
       
   208 self.wview('table',rset)
       
   209 
       
   210 * in view blog, select blogentries and apply view "blogentry table"
       
   211 * demo ajax by filtering blogentry table on category
       
   212 
       
   213 we did the same with 'primary', but with tables we can turn on filters
       
   214 and show that ajax comes for free.
       
   215 [FILLME]
       
   216 
       
   217 
       
   218 
       
   219 XML views, binaries...
       
   220 ----------------------
       
   221 For views generating other formats than HTML (an image generated dynamically
       
   222 for example), and which can not simply be included in the HTML page generated
       
   223 by the main template (see above), you have to:
       
   224 
       
   225 * set the attribute `templatable` of the class to `False`
       
   226 * set, through the attribute `content_type` of the class, the MIME type generated
       
   227   by the view to `application/octet-stream`
       
   228 
       
   229 For views dedicated to binary content creation (like dynamically generated 
       
   230 images), we have to set the attribute `binary` of the class to `True` (which
       
   231 implies that `templatable == False`, so that the attribute `w` of the view could be
       
   232 replaced by a binary flow instead of unicode).