app/soc/views/helper/forms.py
changeset 274 56e1c1721299
parent 265 3c2994f3b85f
child 324 05e21c089be6
equal deleted inserted replaced
273:b97d08ebac0e 274:56e1c1721299
       
     1 #!/usr/bin/python2.5
       
     2 #
       
     3 # Copyright 2008 the Melange authors.
       
     4 #
       
     5 # Licensed under the Apache License, Version 2.0 (the "License");
       
     6 # you may not use this file except in compliance with the License.
       
     7 # You may obtain a copy of the License at
       
     8 #
       
     9 #   http://www.apache.org/licenses/LICENSE-2.0
       
    10 #
       
    11 # Unless required by applicable law or agreed to in writing, software
       
    12 # distributed under the License is distributed on an "AS IS" BASIS,
       
    13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    14 # See the License for the specific language governing permissions and
       
    15 # limitations under the License.
       
    16 
       
    17 """Helpers used to display various views that are forms.
       
    18 """
       
    19 
       
    20 __authors__ = [
       
    21   '"Chen Lunpeng" <forever.clp@gmail.com>',
       
    22   '"Todd Larsen" <tlarsen@google.com>',
       
    23   ]
       
    24 
       
    25 
       
    26 from google.appengine.ext.db import djangoforms
       
    27 
       
    28 from django import newforms as forms
       
    29 from django.utils import safestring
       
    30 
       
    31 
       
    32 class DbModelForm(djangoforms.ModelForm):
       
    33   """Subclass of Django ModelForm that fixes some label and help_text issues.
       
    34 
       
    35   The default behavior of ModelForm is to use the verbose_name in all
       
    36   lowercase, capitalizing only the first character, as the displayed field
       
    37   label.  This class uses verbose_name unaltered as the visible field label
       
    38   instead.
       
    39 
       
    40   The Property classes used by the App Engine Datastore do not have a
       
    41   help_text parameter to their constructor.  In a Model class, a help_text
       
    42   attribute *can* be added to the property after it is created, but the
       
    43   help text will not be automatically passed along to the Django ModelForm.
       
    44   This class detects the presence of a help_text attribute and adds it to
       
    45   the corresponding form field object.
       
    46 
       
    47   ugettext_lazy() proxies used for internationalization in the Model will
       
    48   still work correctly with this new behavior, as long as the original
       
    49   strings are used as the translation keys.
       
    50   """
       
    51 
       
    52   def __init__(self, *args, **kwargs):
       
    53     """Fixes label and help_text issues after parent initialization.
       
    54 
       
    55     Args:
       
    56       *args, **kwargs:  passed through to parent __init__() constructor
       
    57     """
       
    58     super(DbModelForm, self).__init__(*args, **kwargs)
       
    59 
       
    60     for field_name in self.fields.iterkeys():
       
    61       # Since fields can be added only to the ModelForm subclass, check to
       
    62       # see if the Model has a corresponding field first.
       
    63       if hasattr(self.Meta.model, field_name):
       
    64         model_prop = getattr(self.Meta.model, field_name)
       
    65 
       
    66         # Check if the Model property defined verbose_name, and copy that
       
    67         # verbatim to the corresponding field label.
       
    68         if hasattr(model_prop, 'verbose_name'):
       
    69           self.fields[field_name].label = model_prop.verbose_name
       
    70 
       
    71         # Check if the Model property added help_text, and copy that verbatim
       
    72         # to the corresponding field help_text.
       
    73         if hasattr(model_prop, 'help_text'):
       
    74           self.fields[field_name].help_text = model_prop.help_text
       
    75 
       
    76 
       
    77 class SelectQueryArgForm(forms.Form):
       
    78   """URL query argument change control implemented as a Django form.
       
    79   """
       
    80 
       
    81   ONCHANGE_JAVASCRIPT_FMT = '''
       
    82 <script type="text/javascript"> 
       
    83   function changeArg_%(arg_name)s(item) 
       
    84   {
       
    85     var idx=item.selectedIndex;
       
    86     item.selected=true;
       
    87     var value=item.value 
       
    88     var url = location.href 
       
    89     var reg = /%(arg_name)s=\d+/ 
       
    90     url = url.replace(reg, "%(arg_name)s="+value) 
       
    91     if(url.match(reg))
       
    92       document.location.href = url 
       
    93    else
       
    94       document.location.href = "%(page_path)s?%(arg_name)s="+value; 
       
    95   }
       
    96 </script>
       
    97 '''
       
    98 
       
    99   def __init__(self, page_path, arg_name, choices, field_name,
       
   100                *form_args, **form_kwargs):
       
   101     """
       
   102     Args:
       
   103       page_path: (usually request.path)
       
   104       arg_name: the URL query parameter that determines which choice is
       
   105         selected in the selection control
       
   106       choices: list (or tuple) of value/label string two-tuples, for example:
       
   107         (('10', '10 items per page'), ('25', '25 items per page'))
       
   108       field_name: name of the selection field in the form
       
   109       *form_args: positional arguments passed on to the Form base
       
   110         class __init__()
       
   111       *form_kwargs: keyword arguments passed on to the Form base
       
   112         class __init__()
       
   113     """
       
   114     super(SelectQueryArgForm, self).__init__(*form_args, **form_kwargs)
       
   115     
       
   116     self._script = safestring.mark_safe(self.ONCHANGE_JAVASCRIPT_FMT % {
       
   117         'arg_name': arg_name, 'page_path': page_path,})
       
   118  
       
   119     onchange_js_call = 'changeArg_%s(this)' % arg_name
       
   120     
       
   121     self.fields[field_name] = forms.ChoiceField(
       
   122         label='', choices=choices,
       
   123         widget=forms.widgets.Select(attrs={'onchange': onchange_js_call}))
       
   124       
       
   125   def as_table(self):
       
   126     """Returns form rendered as HTML <tr> rows -- with no <table></table>.
       
   127     
       
   128     Prepends <script> section with onchange function included.
       
   129     """
       
   130     return self._script + super(SelectQueryArgForm, self).as_table()
       
   131 
       
   132   def as_ul(self):
       
   133     """Returns form rendered as HTML <li> list items -- with no <ul></ul>.
       
   134     
       
   135     Prepends <script> section with onchange function included.
       
   136     """
       
   137     return self._script + super(SelectQueryArgForm, self).as_ul()
       
   138 
       
   139   def as_p(self):
       
   140     """Returns form rendered as HTML <p> paragraphs.
       
   141     
       
   142     Prepends <script> section with onchange function included.
       
   143     """
       
   144     return self._script + super(SelectQueryArgForm, self).as_p()
       
   145 
       
   146 
       
   147 DEF_SELECT_QUERY_ARG_FIELD_NAME_FMT = 'select_query_arg_%(arg_name)s'
       
   148 
       
   149 def makeSelectQueryArgForm(
       
   150     request, arg_name, initial_value, choices,
       
   151     field_name_fmt=DEF_SELECT_QUERY_ARG_FIELD_NAME_FMT):
       
   152   """Wrapper that creates a customized SelectQueryArgForm.
       
   153 
       
   154   Args:
       
   155     request: the standard Django HTTP request object
       
   156     arg_name: the URL query parameter that determines which choice is
       
   157       selected in the selection control
       
   158     initial_value: the initial value of the selection control
       
   159     choices: list (or tuple) of value/label string two-tuples, for example:
       
   160       (('10', '10 items per page'), ('25', '25 items per page'))
       
   161     field_name_fmt: optional form field name format string; default is
       
   162       DEF_SELECT_QUERY_ARG_FIELD_NAME_FMT; contains these named format
       
   163       specifiers:
       
   164         arg_name: replaced with the arg_name argument
       
   165 
       
   166   Returns:
       
   167     a Django form implementing a query argument selection control, for
       
   168     insertion into a template
       
   169   """
       
   170   field_name = field_name_fmt % {'arg_name': arg_name}
       
   171   return SelectQueryArgForm(request.path, arg_name, choices, field_name,
       
   172                             initial={field_name: initial_value})