Django

Code

Changeset 5444

Show
Ignore:
Timestamp:
06/09/07 09:08:14 (2 years ago)
Author:
mtredinnick
Message:

unicode: Merged from trunk up to [5443].

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/unicode

    • Property svnmerge-integrated changed from /django/trunk:1-5418 to /django/trunk:1-5443
  • django/branches/unicode/django/template/defaulttags.py

    r5399 r5444  
    77from django.utils.encoding import smart_str 
    88import sys 
     9import re 
    910 
    1011register = Library() 
     
    6364 
    6465class ForNode(Node): 
    65     def __init__(self, loopvar, sequence, reversed, nodelist_loop): 
    66         self.loopvar, self.sequence = loopvar, sequence 
     66    def __init__(self, loopvars, sequence, reversed, nodelist_loop): 
     67        self.loopvars, self.sequence = loopvars, sequence 
    6768        self.reversed = reversed 
    6869        self.nodelist_loop = nodelist_loop 
     
    7475            reversed = '' 
    7576        return "<For Node: for %s in %s, tail_len: %d%s>" % \ 
    76             (self.loopvar, self.sequence, len(self.nodelist_loop), reversed) 
     77            (', '.join( self.loopvars ), self.sequence, len(self.nodelist_loop), reversed) 
    7778 
    7879    def __iter__(self): 
     
    109110                    yield data[index] 
    110111            values = reverse(values) 
     112        unpack = len(self.loopvars) > 1 
    111113        for i, item in enumerate(values): 
    112114            context['forloop'] = { 
     
    122124                'parentloop': parentloop, 
    123125            } 
    124             context[self.loopvar] = item 
     126            if unpack: 
     127                # If there are multiple loop variables, unpack the item into them. 
     128                context.update(dict(zip(self.loopvars, item))) 
     129            else: 
     130                context[self.loopvars[0]] = item 
    125131            for node in self.nodelist_loop: 
    126132                nodelist.append(node.render(context)) 
     133            if unpack: 
     134                # The loop variables were pushed on to the context so pop them 
     135                # off again. This is necessary because the tag lets the length 
     136                # of loopvars differ to the length of each set of items and we 
     137                # don't want to leave any vars from the previous loop on the 
     138                # context. 
     139                context.pop() 
    127140        context.pop() 
    128141        return nodelist.render(context) 
     
    488501    parser.delete_first_token() 
    489502    return FilterNode(filter_expr, nodelist) 
    490 filter = register.tag("filter", do_filter) 
     503do_filter = register.tag("filter", do_filter) 
    491504 
    492505#@register.tag 
     
    532545        </ul> 
    533546 
    534     You can also loop over a list in reverse by using 
     547    You can loop over a list in reverse by using 
    535548    ``{% for obj in list reversed %}``. 
     549     
     550    You can also unpack multiple values from a two-dimensional array:: 
     551     
     552        {% for key,value in dict.items %} 
     553            {{ key }}: {{ value }} 
     554        {% endfor %} 
    536555 
    537556    The for loop sets a number of variables available within the loop: 
     
    554573    """ 
    555574    bits = token.contents.split() 
    556     if len(bits) == 5 and bits[4] != 'reversed': 
    557         raise TemplateSyntaxError, "'for' statements with five words should end in 'reversed': %s" % token.contents 
    558     if len(bits) not in (4, 5): 
    559         raise TemplateSyntaxError, "'for' statements should have either four or five words: %s" % token.contents 
    560     if bits[2] != 'in': 
    561         raise TemplateSyntaxError, "'for' statement must contain 'in' as the second word: %s" % token.contents 
    562     loopvar = bits[1] 
    563     sequence = parser.compile_filter(bits[3]) 
    564     reversed = (len(bits) == 5) 
     575    if len(bits) < 4: 
     576        raise TemplateSyntaxError, "'for' statements should have at least four words: %s" % token.contents 
     577 
     578    reversed = bits[-1] == 'reversed' 
     579    in_index = reversed and -3 or -2 
     580    if bits[in_index] != 'in': 
     581        raise TemplateSyntaxError, "'for' statements should use the format 'for x in y': %s" % token.contents 
     582 
     583    loopvars = re.sub(r' *, *', ',', ' '.join(bits[1:in_index])).split(',') 
     584    for var in loopvars: 
     585        if not var or ' ' in var: 
     586            raise TemplateSyntaxError, "'for' tag received an invalid argument: %s" % token.contents 
     587 
     588    sequence = parser.compile_filter(bits[in_index+1]) 
    565589    nodelist_loop = parser.parse(('endfor',)) 
    566590    parser.delete_first_token() 
    567     return ForNode(loopvar, sequence, reversed, nodelist_loop) 
     591    return ForNode(loopvars, sequence, reversed, nodelist_loop) 
    568592do_for = register.tag("for", do_for) 
    569593 
  • django/branches/unicode/docs/add_ons.txt

    r5054 r5444  
    77problems. 
    88 
    9 This code lives in ``django/contrib`` in the Django distribution. Here's a 
    10 rundown of the packages in ``contrib``: 
     9This code lives in ``django/contrib`` in the Django distribution. This document 
     10gives a rundown of the packages in ``contrib``, along with any dependencies 
     11those packages have. 
    1112 
    1213.. admonition:: Note 
     
    2728.. _Tutorial 2: ../tutorial02/ 
    2829 
     30Requires the auth_ and contenttypes_ contrib packages to be installed. 
     31 
    2932auth 
    3033==== 
     
    145148.. _flatpages documentation: ../flatpages/ 
    146149 
     150Requires the sites_ contrib package to be installed as well. 
     151 
    147152localflavor 
    148153=========== 
  • django/branches/unicode/docs/db-api.txt

    r5386 r5444  
    134134 
    135135The ``save()`` method has no return value. 
     136 
     137Updating ``ForeignKey`` fields works exactly the same way; simply assign an 
     138object of the right type to the field in question:: 
     139 
     140    joe = Author.objects.create(name="Joe") 
     141    entry.author = joe 
     142    entry.save() 
     143     
     144Django will complain if you try to assign an object of the wrong type. 
    136145 
    137146How Django knows to UPDATE vs. INSERT 
     
    12301239    Blog.objects.filter(entry__headline__contains='Lennon') 
    12311240 
    1232 Escaping parenthesis and underscores in LIKE statements 
    1233 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     1241Escaping percent signs and underscores in LIKE statements 
     1242~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    12341243 
    12351244The field lookups that equate to ``LIKE`` SQL statements (``iexact``, 
  • django/branches/unicode/docs/fastcgi.txt

    r4900 r5444  
    204204      Alias /media /home/user/python/django/contrib/admin/media 
    205205      RewriteEngine On 
    206       RewriteRule ^/(media.*)$ /$1 [QSA,L
     206      RewriteRule ^/(media.*)$ /$1 [QSA,L,PT
    207207      RewriteCond %{REQUEST_FILENAME} !-f 
    208208      RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L] 
  • django/branches/unicode/docs/model-api.txt

    r5386 r5444  
    18911891        return row 
    18921892 
    1893 ``connection`` and ``cursor`` simply use the standard `Python DB-API`_. If 
    1894 you're not familiar with the Python DB-API, note that the SQL statement in 
    1895 ``cursor.execute()`` uses placeholders, ``"%s"``, rather than adding parameters 
    1896 directly within the SQL. If you use this technique, the underlying database 
    1897 library will automatically add quotes and escaping to your parameter(s) as 
    1898 necessary. (Also note that Django expects the ``"%s"`` placeholder, *not* the 
    1899 ``"?"`` placeholder, which is used by the SQLite Python bindings. This is for 
    1900 the sake of consistency and sanity.) 
     1893``connection`` and ``cursor`` mostly implement the standard `Python DB-API`_ 
     1894(except when it comes to `transaction handling`_). If you're not familiar with 
     1895the Python DB-API, note that the SQL statement in ``cursor.execute()`` uses 
     1896placeholders, ``"%s"``, rather than adding parameters directly within the SQL. 
     1897If you use this technique, the underlying database library will automatically 
     1898add quotes and escaping to your parameter(s) as necessary. (Also note that 
     1899Django expects the ``"%s"`` placeholder, *not* the ``"?"`` placeholder, which is 
     1900used by the SQLite Python bindings. This is for the sake of consistency and 
     1901sanity.) 
    19011902 
    19021903A final note: If all you want to do is a custom ``WHERE`` clause, you can just 
     
    19061907.. _Python DB-API: http://www.python.org/peps/pep-0249.html 
    19071908.. _Other lookup options: ../db-api/#extra-params-select-where-tables 
     1909.. _transaction handling: ../transactions/ 
    19081910 
    19091911Overriding default model methods 
  • django/branches/unicode/docs/modpython.txt

    r5381 r5444  
    5252 
    5353Also, if you've manually altered your ``PYTHONPATH`` to put your Django project 
    54 on it, you'll need to tell mod_python:: 
    55  
    56     PythonPath "['/path/to/project'] + sys.path" 
     54on it, you'll need to tell mod_python: 
     55 
     56.. parsed-literal:: 
     57 
     58    <Location "/mysite/"> 
     59        SetHandler python-program 
     60        PythonHandler django.core.handlers.modpython 
     61        SetEnv DJANGO_SETTINGS_MODULE mysite.settings 
     62        PythonDebug On 
     63        **PythonPath "['/path/to/project'] + sys.path"** 
     64    </Location> 
    5765 
    5866.. caution:: 
  • django/branches/unicode/docs/newforms.txt

    r5386 r5444  
    300300empty string, because ``nick_name`` is ``CharField``, and ``CharField``\s treat 
    301301empty values as an empty string. Each field type knows what its "blank" value 
    302 is -- e.g., for ``DateField``, it's ``None`` instead of the empty string. 
     302is -- e.g., for ``DateField``, it's ``None`` instead of the empty string. For 
     303full details on each field's behavior in this case, see the "Empty value" note 
     304for each field in the "Built-in ``Field`` classes" section below. 
    303305 
    304306Behavior of unbound forms 
    305307~~~~~~~~~~~~~~~~~~~~~~~~~ 
    306308 
    307 It's meaningless to request "clean" data in a form with no data, but, for the 
     309It's meaningless to request "cleaned" data in a form with no data, but, for the 
    308310record, here's what happens with unbound forms:: 
    309311 
     
    607609 
    608610Let's put this all together and use the ``ContactForm`` example in a Django 
    609 view and template. This example view displays the contact form by default and 
    610 validates/processes it if accessed via a POST request:: 
     611view and template. 
     612 
     613Simple view example 
     614~~~~~~~~~~~~~~~~~~~ 
     615 
     616This example view displays the contact form by default and validates/processes 
     617it if accessed via a POST request:: 
    611618 
    612619    def contact(request): 
     
    620627        return render_to_response('contact.html', {'form': form}) 
    621628 
    622 Simple template output 
    623 ~~~~~~~~~~~~~~~~~~~~~~ 
    624  
    625 The template, ``contact.html``, is responsible for displaying the form as HTML. 
    626 To do this, we can use the techniques outlined in the "Outputting forms as HTML" 
    627 section above. 
     629Simple template example 
     630~~~~~~~~~~~~~~~~~~~~~~~ 
     631 
     632The template in the above view example, ``contact.html``, is responsible for 
     633displaying the form as HTML. To do this, we can use the techniques outlined in 
     634the "Outputting forms as HTML" section above. 
    628635 
    629636The simplest way to display a form's HTML is to use the variable on its own, 
     
    678685This iteration technique is useful if you want to apply the same HTML 
    679686formatting to each field, or if you don't know the names of the form fields 
    680 ahead of time. Note that the fields will be listed in the order in which 
     687ahead of time. Note that the fields will be iterated over in the order in which 
    681688they're defined in the ``Form`` class. 
    682689 
     
    702709----------------- 
    703710 
    704 If you subclass a custom ``Form`` class, the resulting ``Form`` class will 
     711If you have multiple ``Form`` classes that share fields, you can use 
     712subclassing to remove redundancy. 
     713 
     714When you subclass a custom ``Form`` class, the resulting subclass will 
    705715include all fields of the parent class(es), followed by the fields you define 
    706716in the subclass. 
     
    12021212mentioned above (``required``, ``label``, ``initial``, ``widget``, 
    12031213``help_text``). 
     1214 
     1215A simple example 
     1216~~~~~~~~~~~~~~~~ 
     1217 
     1218Here's a simple example of a custom field that validates its input is a string 
     1219containing comma-separated e-mail addresses, with at least one address. We'll 
     1220keep it simple and assume e-mail validation is contained in a function called 
     1221``is_valid_email()``. The full class:: 
     1222 
     1223    from django import newforms as forms 
     1224 
     1225    class MultiEmailField(forms.Field): 
     1226        def clean(self, value): 
     1227            emails = value.split(',') 
     1228            for email in emails: 
     1229                if not is_valid_email(email): 
     1230                    raise forms.ValidationError('%s is not a valid e-mail address.' % email) 
     1231            if not emails: 
     1232                raise forms.ValidationError('Enter at least one e-mail address.') 
     1233            return emails 
     1234 
     1235Let's alter the ongoing ``ContactForm`` example to demonstrate how you'd use 
     1236this in a form. Simply use ``MultiEmailField`` instead of ``forms.EmailField``, 
     1237like so:: 
     1238 
     1239    class ContactForm(forms.Form): 
     1240        subject = forms.CharField(max_length=100) 
     1241        message = forms.CharField() 
     1242        senders = MultiEmailField() 
     1243        cc_myself = forms.BooleanField() 
    12041244 
    12051245Generating forms for models 
  • django/branches/unicode/docs/templates.txt

    r5381 r5444  
    9292then converting line breaks to ``<p>`` tags. 
    9393 
    94 Some filters take arguments. A filter argument looks like this: 
    95 ``{{ bio|truncatewords:"30" }}``. This will display the first 30 words of the 
    96 ``bio`` variable. Filter arguments always are in double quotes. 
     94Some filters take arguments. A filter argument looks like this: ``{{ 
     95bio|truncatewords:30 }}``. This will display the first 30 words of the ``bio`` 
     96variable. 
     97 
     98Filter arguments that contain spaces must be quoted; for example, to join a list 
     99with commas and spaced you'd use ``{{ list|join:", " }}``. 
    97100 
    98101The `Built-in filter reference`_ below describes all the built-in filters. 
     
    445448 
    446449Loop over each item in an array.  For example, to display a list of athletes 
    447 given ``athlete_list``:: 
     450provided in ``athlete_list``:: 
    448451 
    449452    <ul> 
     
    453456    </ul> 
    454457 
    455 You can also loop over a list in reverse by using ``{% for obj in list reversed %}``. 
     458You can loop over a list in reverse by using ``{% for obj in list reversed %}``. 
     459 
     460**New in Django development version** 
     461If you need to loop over a list of lists, you can unpack the values 
     462in eachs sub-list into a set of known names. For example, if your context contains 
     463a list of (x,y) coordinates called ``points``, you could use the following 
     464to output the list of points::  
     465 
     466    {% for x, y in points %} 
     467        There is a point at {{ x }},{{ y }} 
     468    {% endfor %} 
     469     
     470This can also be useful if you need to access the items in a dictionary.  
     471For example, if your context contained a dictionary ``data``, the following 
     472would display the keys and values of the dictionary:: 
     473 
     474    {% for key, value in data.items %} 
     475        {{ key }}: {{ value }} 
     476    {% endfor %} 
    456477 
    457478The for loop sets a number of variables available within the loop: 
  • django/branches/unicode/tests/regressiontests/templates/tests.py

    r5343 r5444  
    296296            'for-tag-vars03': ("{% for val in values %}{{ forloop.revcounter }}{% endfor %}", {"values": [6, 6, 6]}, "321"), 
    297297            'for-tag-vars04': ("{% for val in values %}{{ forloop.revcounter0 }}{% endfor %}", {"values": [6, 6, 6]}, "210"), 
     298            'for-tag-unpack01': ("{% for key,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"), 
     299            'for-tag-unpack03': ("{% for key, value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"), 
     300            'for-tag-unpack04': ("{% for key , value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"), 
     301            'for-tag-unpack05': ("{% for key ,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"), 
     302            'for-tag-unpack06': ("{% for key value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError), 
     303            'for-tag-unpack07': ("{% for key,,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError), 
     304            'for-tag-unpack08': ("{% for key,value, in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError), 
     305            # Ensure that a single loopvar doesn't truncate the list in val. 
     306            'for-tag-unpack09': ("{% for val in items %}{{ val.0 }}:{{ val.1 }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"), 
     307            # Otherwise, silently truncate if the length of loopvars differs to the length of each set of items. 
     308            'for-tag-unpack10': ("{% for x,y in items %}{{ x }}:{{ y }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2, 'orange'))}, "one:1/two:2/"), 
     309            'for-tag-unpack11': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, ("one:1,/two:2,/", "one:1,INVALID/two:2,INVALID/")), 
     310            'for-tag-unpack12': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2))}, ("one:1,carrot/two:2,/", "one:1,carrot/two:2,INVALID/")), 
     311            'for-tag-unpack13': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2, 'cheese'))}, ("one:1,carrot/two:2,cheese/", "one:1,carrot/two:2,cheese/")), 
    298312 
    299313            ### IF TAG ################################################################