Changeset 5444
- Timestamp:
- 06/09/07 09:08:14 (2 years ago)
- Files:
-
- django/branches/unicode (modified) (1 prop)
- django/branches/unicode/django/template/defaulttags.py (modified) (8 diffs)
- django/branches/unicode/docs/add_ons.txt (modified) (3 diffs)
- django/branches/unicode/docs/db-api.txt (modified) (2 diffs)
- django/branches/unicode/docs/fastcgi.txt (modified) (1 diff)
- django/branches/unicode/docs/model-api.txt (modified) (2 diffs)
- django/branches/unicode/docs/modpython.txt (modified) (1 diff)
- django/branches/unicode/docs/newforms.txt (modified) (6 diffs)
- django/branches/unicode/docs/templates.txt (modified) (3 diffs)
- django/branches/unicode/tests/regressiontests/templates/tests.py (modified) (1 diff)
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 7 7 from django.utils.encoding import smart_str 8 8 import sys 9 import re 9 10 10 11 register = Library() … … 63 64 64 65 class ForNode(Node): 65 def __init__(self, loopvar , sequence, reversed, nodelist_loop):66 self.loopvar , self.sequence = loopvar, sequence66 def __init__(self, loopvars, sequence, reversed, nodelist_loop): 67 self.loopvars, self.sequence = loopvars, sequence 67 68 self.reversed = reversed 68 69 self.nodelist_loop = nodelist_loop … … 74 75 reversed = '' 75 76 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) 77 78 78 79 def __iter__(self): … … 109 110 yield data[index] 110 111 values = reverse(values) 112 unpack = len(self.loopvars) > 1 111 113 for i, item in enumerate(values): 112 114 context['forloop'] = { … … 122 124 'parentloop': parentloop, 123 125 } 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 125 131 for node in self.nodelist_loop: 126 132 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() 127 140 context.pop() 128 141 return nodelist.render(context) … … 488 501 parser.delete_first_token() 489 502 return FilterNode(filter_expr, nodelist) 490 filter = register.tag("filter", do_filter)503 do_filter = register.tag("filter", do_filter) 491 504 492 505 #@register.tag … … 532 545 </ul> 533 546 534 You can alsoloop over a list in reverse by using547 You can loop over a list in reverse by using 535 548 ``{% 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 %} 536 555 537 556 The for loop sets a number of variables available within the loop: … … 554 573 """ 555 574 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]) 565 589 nodelist_loop = parser.parse(('endfor',)) 566 590 parser.delete_first_token() 567 return ForNode(loopvar , sequence, reversed, nodelist_loop)591 return ForNode(loopvars, sequence, reversed, nodelist_loop) 568 592 do_for = register.tag("for", do_for) 569 593 django/branches/unicode/docs/add_ons.txt
r5054 r5444 7 7 problems. 8 8 9 This code lives in ``django/contrib`` in the Django distribution. Here's a 10 rundown of the packages in ``contrib``: 9 This code lives in ``django/contrib`` in the Django distribution. This document 10 gives a rundown of the packages in ``contrib``, along with any dependencies 11 those packages have. 11 12 12 13 .. admonition:: Note … … 27 28 .. _Tutorial 2: ../tutorial02/ 28 29 30 Requires the auth_ and contenttypes_ contrib packages to be installed. 31 29 32 auth 30 33 ==== … … 145 148 .. _flatpages documentation: ../flatpages/ 146 149 150 Requires the sites_ contrib package to be installed as well. 151 147 152 localflavor 148 153 =========== django/branches/unicode/docs/db-api.txt
r5386 r5444 134 134 135 135 The ``save()`` method has no return value. 136 137 Updating ``ForeignKey`` fields works exactly the same way; simply assign an 138 object 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 144 Django will complain if you try to assign an object of the wrong type. 136 145 137 146 How Django knows to UPDATE vs. INSERT … … 1230 1239 Blog.objects.filter(entry__headline__contains='Lennon') 1231 1240 1232 Escaping p arenthesis and underscores in LIKE statements1233 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1241 Escaping percent signs and underscores in LIKE statements 1242 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1234 1243 1235 1244 The field lookups that equate to ``LIKE`` SQL statements (``iexact``, django/branches/unicode/docs/fastcgi.txt
r4900 r5444 204 204 Alias /media /home/user/python/django/contrib/admin/media 205 205 RewriteEngine On 206 RewriteRule ^/(media.*)$ /$1 [QSA,L ]206 RewriteRule ^/(media.*)$ /$1 [QSA,L,PT] 207 207 RewriteCond %{REQUEST_FILENAME} !-f 208 208 RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L] django/branches/unicode/docs/model-api.txt
r5386 r5444 1891 1891 return row 1892 1892 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 1895 the Python DB-API, note that the SQL statement in ``cursor.execute()`` uses 1896 placeholders, ``"%s"``, rather than adding parameters directly within the SQL. 1897 If you use this technique, the underlying database library will automatically 1898 add quotes and escaping to your parameter(s) as necessary. (Also note that 1899 Django expects the ``"%s"`` placeholder, *not* the ``"?"`` placeholder, which is 1900 used by the SQLite Python bindings. This is for the sake of consistency and 1901 sanity.) 1901 1902 1902 1903 A final note: If all you want to do is a custom ``WHERE`` clause, you can just … … 1906 1907 .. _Python DB-API: http://www.python.org/peps/pep-0249.html 1907 1908 .. _Other lookup options: ../db-api/#extra-params-select-where-tables 1909 .. _transaction handling: ../transactions/ 1908 1910 1909 1911 Overriding default model methods django/branches/unicode/docs/modpython.txt
r5381 r5444 52 52 53 53 Also, 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" 54 on 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> 57 65 58 66 .. caution:: django/branches/unicode/docs/newforms.txt
r5386 r5444 300 300 empty string, because ``nick_name`` is ``CharField``, and ``CharField``\s treat 301 301 empty 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. 302 is -- e.g., for ``DateField``, it's ``None`` instead of the empty string. For 303 full details on each field's behavior in this case, see the "Empty value" note 304 for each field in the "Built-in ``Field`` classes" section below. 303 305 304 306 Behavior of unbound forms 305 307 ~~~~~~~~~~~~~~~~~~~~~~~~~ 306 308 307 It's meaningless to request "clean " data in a form with no data, but, for the309 It's meaningless to request "cleaned" data in a form with no data, but, for the 308 310 record, here's what happens with unbound forms:: 309 311 … … 607 609 608 610 Let'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:: 611 view and template. 612 613 Simple view example 614 ~~~~~~~~~~~~~~~~~~~ 615 616 This example view displays the contact form by default and validates/processes 617 it if accessed via a POST request:: 611 618 612 619 def contact(request): … … 620 627 return render_to_response('contact.html', {'form': form}) 621 628 622 Simple template output623 ~~~~~~~~~~~~~~~~~~~~~~ 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.629 Simple template example 630 ~~~~~~~~~~~~~~~~~~~~~~~ 631 632 The template in the above view example, ``contact.html``, is responsible for 633 displaying the form as HTML. To do this, we can use the techniques outlined in 634 the "Outputting forms as HTML" section above. 628 635 629 636 The simplest way to display a form's HTML is to use the variable on its own, … … 678 685 This iteration technique is useful if you want to apply the same HTML 679 686 formatting 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 listedin the order in which687 ahead of time. Note that the fields will be iterated over in the order in which 681 688 they're defined in the ``Form`` class. 682 689 … … 702 709 ----------------- 703 710 704 If you subclass a custom ``Form`` class, the resulting ``Form`` class will 711 If you have multiple ``Form`` classes that share fields, you can use 712 subclassing to remove redundancy. 713 714 When you subclass a custom ``Form`` class, the resulting subclass will 705 715 include all fields of the parent class(es), followed by the fields you define 706 716 in the subclass. … … 1202 1212 mentioned above (``required``, ``label``, ``initial``, ``widget``, 1203 1213 ``help_text``). 1214 1215 A simple example 1216 ~~~~~~~~~~~~~~~~ 1217 1218 Here's a simple example of a custom field that validates its input is a string 1219 containing comma-separated e-mail addresses, with at least one address. We'll 1220 keep 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 1235 Let's alter the ongoing ``ContactForm`` example to demonstrate how you'd use 1236 this in a form. Simply use ``MultiEmailField`` instead of ``forms.EmailField``, 1237 like 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() 1204 1244 1205 1245 Generating forms for models django/branches/unicode/docs/templates.txt
r5381 r5444 92 92 then converting line breaks to ``<p>`` tags. 93 93 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. 94 Some filters take arguments. A filter argument looks like this: ``{{ 95 bio|truncatewords:30 }}``. This will display the first 30 words of the ``bio`` 96 variable. 97 98 Filter arguments that contain spaces must be quoted; for example, to join a list 99 with commas and spaced you'd use ``{{ list|join:", " }}``. 97 100 98 101 The `Built-in filter reference`_ below describes all the built-in filters. … … 445 448 446 449 Loop over each item in an array. For example, to display a list of athletes 447 given ``athlete_list``::450 provided in ``athlete_list``:: 448 451 449 452 <ul> … … 453 456 </ul> 454 457 455 You can also loop over a list in reverse by using ``{% for obj in list reversed %}``. 458 You can loop over a list in reverse by using ``{% for obj in list reversed %}``. 459 460 **New in Django development version** 461 If you need to loop over a list of lists, you can unpack the values 462 in eachs sub-list into a set of known names. For example, if your context contains 463 a list of (x,y) coordinates called ``points``, you could use the following 464 to output the list of points:: 465 466 {% for x, y in points %} 467 There is a point at {{ x }},{{ y }} 468 {% endfor %} 469 470 This can also be useful if you need to access the items in a dictionary. 471 For example, if your context contained a dictionary ``data``, the following 472 would display the keys and values of the dictionary:: 473 474 {% for key, value in data.items %} 475 {{ key }}: {{ value }} 476 {% endfor %} 456 477 457 478 The for loop sets a number of variables available within the loop: django/branches/unicode/tests/regressiontests/templates/tests.py
r5343 r5444 296 296 'for-tag-vars03': ("{% for val in values %}{{ forloop.revcounter }}{% endfor %}", {"values": [6, 6, 6]}, "321"), 297 297 '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/")), 298 312 299 313 ### IF TAG ################################################################
