User Guide ========== Core feature of :ref:`wheezy.html` is :py:class:`~wheezy.html.factory.WidgetFactory`. This class has shortcut ``widget``. You instantiate :py:class:`~wheezy.html.factory.WidgetFactory` and pass the following arguments: * ``model`` - object being wrapped. * ``errors`` - dictionary contains all errors reported; ``key`` corresponds to attribute name, while ``value`` is a list of errors. Let declare our domain model:: class Credential(object): def __init__(self): self.username = '' self.password = '' This way we get HTML widget:: from wheezy.html import widget credential = Credential() errors = {} credential = widget(credential, errors) Widget Name ~~~~~~~~~~~ Each attribute in widget corresponds to appropriate attribute in ``model``. Attribute name becomes ``name`` in html element. Convention for html ``id`` is replace underscope with dash. So attribute ``confirm_password`` remains unchanged in html name, however id will be ``confirm-password``. Widget Rendering ~~~~~~~~~~~~~~~~ Once we know name of html widget, next pass control to appropriate widget for rendering:: credential.username.textbox(autocomplete='off') Let explain this single line: * ``credential`` - an instance of :py:class:`~wheezy.html.factory.WidgetFactory` that wraps ``model`` and ``errors``. * ``username`` - attribute name of our domain object. * ``textbox`` - widget we need to render. * ``autocomplete`` - html specific attribute. Once that code is executed we get the following:: Value Formatting ~~~~~~~~~~~~~~~~ You can format model value before it is passed to widget for rendering. Let declare our domain model:: from datetime import date class Registration(object): def __init__(self): self.date_of_birth = date.min Here is how you can apply formatting:: registration.date_of_birth.format('%Y/%m/%d') or this way:: registration.date_of_birth.format( format_provider=lambda value, ignore: value.strftime('%m-%d-%y')) Widget formatting can follow by actual widget that needs to be rendered:: registration.date_of_birth.format('%Y/%m/%d').textbox() ``format_provider`` - a callable of the following form:: def my_format_provider(value, format_string): return value_formatted There are default format providers for built-in types. You can replace and extend it with your own by altering ``format_providers`` map:: from wheezy.html.utils import format_providers format_providers['my_type'] = my_format_provider Default implementation for date/time types formats it minimal value to empty string. Model Error ~~~~~~~~~~~ Since ``widget`` is initialized with model and errors, it capable to decorate html widget with attributes specific to errors. Let see this in the following example:: errors = {'username': ['Required field cannot be left blank.']} We get the errors from some sort of validation. The same ``textbox`` is now decorated with class error:: So I can apply appropriate css style to draw a border around input, or what ever else since in html I have distinguished situation between input with error and with valid input. Now let display error:: credential.username.error() Read above as render error message for username, here is what we get:: Required field cannot be left blank. General Error ~~~~~~~~~~~~~ General error is not related to certain model attribute but to operation related instead. If ``errors`` dictionary contains an element with __ERROR__ key than that one is used as general error:: errors = {'__ERROR__': 'The username or password provided is incorrect.'} You can display it this way:: credential.error() It renders the following html element only if __ERROR__ key exists:: The username or password provided is incorrect. Notice class ``error-message``. Your application is able to distinguish field errors from general errors. Widgets ~~~~~~~ :ref:`wheezy.html` comes with a number of built-in widgets. They can be generally divided into two categories with support of a single value (``string``, ``int``, ``datetime``, etc) or multiple (``list`` or ``tuple``). Single value widgets: * :py:meth:`~wheezy.html.widgets.hidden` - html element input of type hidden. * :py:meth:`~wheezy.html.widgets.emptybox` - html element input of type text, value is rendered only if evaluated to boolean True. * :py:meth:`~wheezy.html.widgets.textbox` - html element input of type text, value is rendered only if it is not None or ''. * :py:meth:`~wheezy.html.widgets.password` - html element input of type password, value is rendered only if it is not None or ''. * :py:meth:`~wheezy.html.widgets.textarea` - html element textarea. * :py:meth:`~wheezy.html.widgets.checkbox` - html element input of type checkbox. * :py:meth:`~wheezy.html.widgets.label` - html element label. * :py:meth:`~wheezy.html.widgets.dropdown` - html element select (there is also synonym ``select``). Attribute ``choices`` is a list of html options. * :py:meth:`~wheezy.html.widgets.radio` - a group of html input elements of type radio. Attribute ``choices`` is a list of options. Widgets that support multiple values: * :py:meth:`~wheezy.html.widgets.multiple_hidden` - renders several html input elements of type hidden per item in the value list. * :py:meth:`~wheezy.html.widgets.multiple_checkbox` - renders several html elements of type checkbox per item in the value list nested into html label element. * :py:meth:`~wheezy.html.widgets.listbox` - html element select of type multiple (there is also synonym ``multiple_select``). Attribute ``choices`` is a list of html options. Several widgets support ``choinces`` attribute, it is an iteratable of tuple of two:: account_types = (('u', 'User'), ('b', 'Business')) account.account_type.radio(choices=account_types) It renders the following html:: It is sometimes more convinient to operate with dictionary:: >>> from operator import itemgetter >>> account_types = sorted({'u': 'User', 'b': 'Business'}.items(), ... key=itemgetter(1)) >>> account_types [('u', 'User'), ('b', 'Business')] Custom Widgets ~~~~~~~~~~~~~~ It is easy to provide own widgets. A widget is any callable of the following contract:: from wheezy.html.markup import Tag def my_widget(name, value, attrs): tag_attrs = { 'id' = id(name) } if attrs: tag_attrs.update(attrs) return Tag('name', value, attrs=tag_attrs) Here is a description of each attribute: * ``name`` - name of model attribute. * ``value`` - value that is currently rendered. * ``attrs`` - a dictionary of extra key-word arguments passed. Your custom widget must return an instance of :py:class:`~wheezy.html.markup.Tag` or :py:class:`~wheezy.html.markup.Fragment`. In case of field error html element is decorated with css class ``error``. Registration ^^^^^^^^^^^^ Once ``my_widget`` is ready you can add it to a list of default widgets:: from wheezy.html.widgets import default as default_widgets default_widgets['my_widget'] = my_widget Now you should be able to use it:: credential.username.my_widget() Since ``default_widgets`` is python dictionary you can manipulate it a way you like. Integration ~~~~~~~~~~~ :ref:`wheezy.html` integrates with the following template systems: * `Jinja2 Templates `_ * `Mako Templates `_ * `Tenjin Templates `_ * `Wheezy Templates `_ Jinja2 ^^^^^^ :ref:`wheezy.html` integration with ``Jinja2`` is provided via extension feature. Here is how to add :py:meth:`~wheezy.html.ext.jinja2.WidgetExtension` to your code:: from wheezy.html.ext.jinja2 import WidgetExtension env = Environment( ... extensions=[WidgetExtension]) The only thing :py:meth:`~wheezy.html.ext.jinja2.WidgetExtension` does is translation of widget code to adequate ``Jinja2`` code. Let demonstrate with by example:: {{ model.remember_me.checkbox() }} is translated to the following ``Jinja2`` code (during template compilation phase):: which effectively renders the HTML at runtime:: Since widgets also decorate appropriate HTML tags in case of error, ``errors`` dictionary must be available in ``Jinja2`` context:: template = env.get_template(template_name) assert 'errors' in kwargs template.render( **kwargs ) See :py:mod:`wheezy.html.ext.mako` for more examples. Mako ^^^^ :ref:`wheezy.html` integration with ``Mako`` is provided via preprocessor feature. Here is how to add :py:meth:`~wheezy.html.ext.mako.widget_preprocessor` to your code:: from wheezy.html.ext.mako import widget_preprocessor template_lookup = TemplateLookup( ... preprocessor=[widget_preprocessor]) The only thing :py:meth:`~wheezy.html.ext.mako.widget_preprocessor` does is translation of widget code to adequate ``Mako`` code. Let demonstrate with by example:: ${model.remember_me.checkbox()} is translated to the following ``Mako`` code (during template compilation phase):: which effectively renders the HTML at runtime:: Since widgets also decorate appropriate HTML tags in case of error, ``errors`` dictionary must be available in ``Mako`` context:: template = template_lookup.get_template(template_name) assert 'errors' in kwargs template.render( **kwargs ) See :py:mod:`wheezy.html.ext.mako` for more examples. Tenjin ^^^^^^ :ref:`wheezy.html` integration with ``Tenjin`` is provided via preprocessor feature. Here is how to add :py:meth:`~wheezy.html.ext.tenjin.widget_preprocessor` to your code:: from wheezy.html.ext.tenjin import widget_preprocessor engine = tenjin.Engine( ... pp=[widget_preprocessor]) The only thing :py:meth:`~wheezy.html.ext.mako.widget_preprocessor` does is translation of widget code to adequate ``Tenjin`` code. Let demonstrate with by example:: ${model.remember_me.checkbox(class_='i')} is translated to the following ``Tenjin`` code (during template compilation phase):: class="error i" class="i" checked="checked" /> which effectively renders the HTML at runtime:: Since widgets also decorate appropriate HTML tags in case of error, ``errors`` dictionary must be available in ``Tenjin`` context:: assert 'errors' in kwargs engine.render('page.html', **kwargs ) See :py:mod:`wheezy.html.ext.tenjin` for more examples. Wheezy Template ^^^^^^^^^^^^^^^ :ref:`wheezy.html` integration with ``wheezy.template`` is provided via preprocessor feature. Here is how to add :py:meth:`~wheezy.html.ext.template.WidgetExtension` to your code:: from wheezy.html.ext.template import WidgetExtension from wheezy.html.utils import html_escape from wheezy.html.utils import format_value engine = Engine( ... extensions=[ WidgetExtension ]) engine.global_vars.update({ 'format_value': format_value, 'h': html_escape }) The only thing :py:meth:`~wheezy.html.ext.template.WidgetExtension` does is translation of widget code to adequate ``wheezy.template`` code. Let demonstrate with by example:: @model.remember_me.checkbox(class_='i') is translated to the following ``wheezy.template`` code (during template compilation phase):: which effectively renders the HTML at runtime:: Since widgets also decorate appropriate HTML tags in case of error, ``errors`` dictionary must be available in ``wheezy.template`` context:: assert 'errors' in kwargs engine.render('page.html', **kwargs ) See :py:mod:`wheezy.html.ext.template` for more examples.