Warning: Can't synchronize with repository "(default)" (Unsupported version control system "svn": No module named svn). Look in the Trac log for more information.

Changes between Version 6 and Version 7 of StatelessWidgets


Ignore:
Timestamp:
03/08/08 10:37:06 (11 years ago)
Author:
Chris Arndt
Comment:

migrated

Legend:

Unmodified
Added
Removed
Modified
  • StatelessWidgets

    v6 v7  
    1 = The stateless nature of widgets = 
     1{{{ 
    22 
    3 Widgets have been designed from the ground up to be stateless objects [1], this means that a  
    4 widget instance does not hold any knowledge of what happened previously thus the same instance 
    5 can be reused across all requests. 
     3#!rst 
    64 
    7 ['''FIXME''' stateless motivations:  
    8 performance is not the main one, basically reusing the same instance fits well with the way 
    9 you work with TG controllers and decorators (for example you pass a form instance to the  
    10 @validate decorator, see [2]] 
    11  
    12 While writing your application the are two important rules you should keep in mind  
    13 when working with widgets: 
    14  
    15 == 1) Reuse widgets instances inside your application == 
    16  
    17 To effectively share the same widget instance across all requests you should 
    18 take care of using *only one instance* of a given widget inside your  
    19 application. 
    20  
    21 '''Yes:''' 
    22  
    23 {{{ 
    24 #!python 
    25 banana_widget = BananaWidget() 
    26  
    27 class MyController(...): 
    28     @turbogears.expose(html="my.template") 
    29     def index(self): 
    30         return dict(widget=banana_widget) 
    31      
    32 class AnotherController(...): 
    33     @turbogears.expose(html="another.template") 
    34     def fruit(self): 
    35         return dict(fruit_widget=banana_widget) 
     5.. note:: This page has been migrated to http://docs.turbogears.org/1.0/StatelessWidgets 
    366}}} 
    377 
    38 '''No:''' 
    39  
    40 {{{ 
    41 #!python 
    42 class MyController(...): 
    43     @turbogears.expose(html="my.template") 
    44     def index(self): 
    45         widget = BananaWidget() 
    46         return dict(widget=widget) 
    47  
    48 class AnotherController(...): 
    49     @turbogears.expose(html="another.template") 
    50     def fruit(self): 
    51         fruit_widget = BananaWidget() 
    52         return dict(fruit_widget=fruit_widget) 
    53 }}} 
    54          
    55 '''No:''' 
    56  
    57 {{{ 
    58 #!python 
    59 <?py from my.widgets import BananaWidget ?> 
    60  
    61 <div py:content="BananaWidget().display()" /> 
    62 }}} 
    63  
    64 == 2) Treat widget instances as immutable after creation == 
    65  
    66 Since the same widget instance is used across all requests its instance 
    67 attributes should be immutable so that any thread has a consistent view 
    68 of the instance. In particular, changing widget instance's attributes  
    69 inside a request is not threadsafe. 
    70  
    71 '''Yes:''' 
    72  
    73 {{{ 
    74 #!python 
    75 class BananaWidget(Widget): 
    76     def __init__(self, foo, **kw): 
    77         super(Widget, self).__init__(**kw) 
    78         self.foo = foo 
    79 }}} 
    80  
    81 '''Rather not:''' 
    82  
    83 {{{ 
    84 #!python 
    85 banana_widget = BananaWidget() 
    86 banana_widget.foo = "bar" 
    87  
    88 class MyController(...): 
    89     @turbogears.expose(html="my.template") 
    90     def index(self): 
    91         return dict(widget=banana_widget) 
    92 }}} 
    93  
    94 '''Definitely not:''' 
    95  
    96 {{{ 
    97 #!python 
    98 banana_widget = BananaWidget() 
    99  
    100 class MyController(...): 
    101     @turbogears.expose(html="my.template") 
    102     def index(self): 
    103         banana_widget.foo = "bar" 
    104         return dict(widget=banana_widget)  
    105 }}} 
    106  
    107 '''Definitely not:''' 
    108  
    109 {{{ 
    110 #!python 
    111 class BananaWidget(Widget): 
    112     def update_params(d): 
    113         super(Widget, self).update_params(self, d) 
    114         self.bar = d["bar"] 
    115          
    116 }}} 
    117  
    118 Whenever you see "self.<attribute> = <value>" in a widget class outside its constructor, you know  
    119 you're in trouble. If two requests come in simultaneously and both try to  
    120 render that widget at the same time, the two users might end up getting  
    121 the same value appearing for their widget. Basically, you can't put *any*  
    122 values that need to vary from request to request in self. 
    123  
    124 If the same widget instance is being used for every requests and its  
    125 attributes are immutable how the widget can behave differently from request  
    126 to request? 
    127  
    128  1. Define the widget's ''request-independent'' knowledge and behavior at construction time. 
    129  2. Define the widget's ''per-request'' knowledge and behavior at render time. 
    130  
    131 In this sense, a widget is similar to a controller's method: the  
    132 widget appearance is defined by its template attribute, and at render time you  
    133 send to its template (via its display() or render() methods) a set of parameters that  
    134 are request-dependent and that the widget manipulates (using its adjust_value() and  
    135 update_params() methods) to behave correctly. 
    136  
    137 Although the widget/controller's method parallelism can help to understand  
    138 how a widget works, it's important to remember that unlike a controller's  
    139 method a widget is not responsible for directly responding to a given request. 
    140 This job is always left to the controller method that interacts with the widget  
    141 and sends request-dependent parameters to it. 
    142  
    143 {{{ 
    144 #!python 
    145 banana_widget = BananaWidget() 
    146  
    147 class MyController(...): 
    148     @turbogears.expose(html="my.template") 
    149     def index(self): 
    150         value = "Brasilian banana" 
    151         return dict(banana_widget=banana_widget, banana_value=value) 
    152 }}} 
    153  
    154 inside my/template.kid: 
    155  
    156 {{{ 
    157 <div py:content="banana_widget.display(value=banana_value)" /> 
    158 }}} 
    159  
    160 ==== References ==== 
    161  
    162 This document also takes inspiration from some discussions that have take place 
    163 in the Google group (for example Bob Ippolito's reply [2] that clearly tells  
    164 why you shouldn't change an instance attribute inside a request, and some replies  
    165 by Kevin). 
    166  
    167 [1] http://ootips.org/stateless-distributed-objects.html 
    168  
    169 [2] http://tinyurl.com/pfyho (see Kevin's reply to jpellerin, use @validate not @expose) 
    170  
    171 [3] http://tinyurl.com/p79pg