Changeset 5463
- Timestamp:
- 06/11/07 10:53:42 (1 year ago)
- Files:
-
- django/branches/boulder-oracle-sprint/AUTHORS (modified) (4 diffs)
- django/branches/boulder-oracle-sprint/django/conf/global_settings.py (modified) (1 diff)
- django/branches/boulder-oracle-sprint/django/conf/locale/nl/LC_MESSAGES/django.mo (modified) (previous)
- django/branches/boulder-oracle-sprint/django/conf/locale/nl/LC_MESSAGES/django.po (modified) (1 diff)
- django/branches/boulder-oracle-sprint/django/core/management.py (modified) (2 diffs)
- django/branches/boulder-oracle-sprint/django/db/backends/postgresql/base.py (modified) (1 diff)
- django/branches/boulder-oracle-sprint/django/db/backends/postgresql_psycopg2/base.py (modified) (1 diff)
- django/branches/boulder-oracle-sprint/django/db/backends/util.py (modified) (1 diff)
- django/branches/boulder-oracle-sprint/django/__init__.py (modified) (1 diff)
- django/branches/boulder-oracle-sprint/django/template/defaulttags.py (modified) (8 diffs)
- django/branches/boulder-oracle-sprint/django/views/debug.py (modified) (3 diffs)
- django/branches/boulder-oracle-sprint/docs/add_ons.txt (modified) (3 diffs)
- django/branches/boulder-oracle-sprint/docs/authentication.txt (modified) (1 diff)
- django/branches/boulder-oracle-sprint/docs/db-api.txt (modified) (4 diffs)
- django/branches/boulder-oracle-sprint/docs/fastcgi.txt (modified) (1 diff)
- django/branches/boulder-oracle-sprint/docs/man (copied) (copied from django/trunk/docs/man)
- django/branches/boulder-oracle-sprint/docs/man/django-admin.1 (copied) (copied from django/trunk/docs/man/django-admin.1)
- django/branches/boulder-oracle-sprint/docs/model-api.txt (modified) (3 diffs)
- django/branches/boulder-oracle-sprint/docs/modpython.txt (modified) (1 diff)
- django/branches/boulder-oracle-sprint/docs/newforms.txt (modified) (6 diffs)
- django/branches/boulder-oracle-sprint/docs/templates.txt (modified) (3 diffs)
- django/branches/boulder-oracle-sprint/scripts/rpm-install.sh (modified) (1 diff)
- django/branches/boulder-oracle-sprint/tests/regressiontests/serializers_regress/tests.py (modified) (2 diffs)
- django/branches/boulder-oracle-sprint/tests/regressiontests/templates/tests.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/boulder-oracle-sprint/AUTHORS
r5422 r5463 74 74 Ian Clelland <clelland@gmail.com> 75 75 crankycoder@gmail.com 76 Pete Crosier <pete.crosier@gmail.com> 76 77 Matt Croydon <http://www.postneo.com/> 77 78 flavio.curella@gmail.com … … 131 132 Antti Kaihola <http://akaihola.blogspot.com/> 132 133 Ben Dean Kawamura <ben.dean.kawamura@gmail.com> 134 ian.g.kelly@gmail.com 133 135 Garth Kidd <http://www.deadlybloodyserious.com/> 134 136 kilian <kilian.cavalotti@lip6.fr> … … 170 172 mmarshall 171 173 Eric Moritz <http://eric.themoritzfamily.com/> 174 mrmachine <real.human@mrmachine.net> 172 175 Robin Munn <http://www.geekforgod.com/> 173 176 Robert Myers <myer0052@gmail.com> … … 235 238 Dan Watson <http://theidioteque.net/> 236 239 Chris Wesseling <Chris.Wesseling@cwi.nl> 240 James Wheare <django@sparemint.com> 237 241 charly.wilhelm@gmail.com 238 242 Rachel Willmer <http://www.willmer.com/kb/> django/branches/boulder-oracle-sprint/django/conf/global_settings.py
r5384 r5463 242 242 # The User-Agent string to use when checking for URL validity through the 243 243 # isExistingURL validator. 244 URL_VALIDATOR_USER_AGENT = "Django/0.96pre (http://www.djangoproject.com)" 244 from django import get_version 245 URL_VALIDATOR_USER_AGENT = "Django/%s (http://www.djangoproject.com)" % get_version() 245 246 246 247 ############## django/branches/boulder-oracle-sprint/django/conf/locale/nl/LC_MESSAGES/django.po
r4695 r5463 2203 2203 2204 2204 #: utils/timesince.py:16 2205 # In the timesince context it is stilistically wrong to use the plural for hour in Dutch. 2205 2206 msgid "hour" 2206 2207 msgid_plural "hours" 2207 2208 msgstr[0] "uur" 2208 msgstr[1] "u ren"2209 msgstr[1] "uur" 2209 2210 2210 2211 #: utils/timesince.py:17 django/branches/boulder-oracle-sprint/django/core/management.py
r5426 r5463 4 4 import django 5 5 from django.core.exceptions import ImproperlyConfigured 6 import os, re, shutil, sys, textwrap7 6 from optparse import OptionParser 8 7 from django.utils import termcolors 8 import os, re, shutil, sys, textwrap 9 9 10 10 # For Python 2.3 11 11 if not hasattr(__builtins__, 'set'): 12 12 from sets import Set as set 13 14 # For backwards compatibility: get_version() used to be in this module. 15 get_version = django.get_version 13 16 14 17 MODULE_TEMPLATE = ''' {%% if perms.%(app)s.%(addperm)s or perms.%(app)s.%(changeperm)s %%} … … 97 100 # field as the field to which it points. 98 101 get_rel_data_type = lambda f: (f.get_internal_type() in ('AutoField', 'PositiveIntegerField', 'PositiveSmallIntegerField')) and 'IntegerField' or f.get_internal_type() 99 100 def get_version():101 "Returns the version as a human-format string."102 from django import VERSION103 v = '.'.join([str(i) for i in VERSION[:-1]])104 if VERSION[-1]:105 v += '-' + VERSION[-1]106 return v107 102 108 103 def get_sql_create(app): django/branches/boulder-oracle-sprint/django/db/backends/postgresql/base.py
r5307 r5463 239 239 output = [] 240 240 for model in model_list: 241 # Use `coalesce` to set the sequence for each model to the max pk value if there are records, 242 # or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true 243 # if there are records (as the max pk value is already in use), otherwise set it to false. 241 244 for f in model._meta.fields: 242 245 if isinstance(f, models.AutoField): 243 output.append("%s setval('%s', (%s max(%s) %s %s));" % \246 output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ 244 247 (style.SQL_KEYWORD('SELECT'), 245 248 style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))), 246 style.SQL_KEYWORD('SELECT'),247 249 style.SQL_FIELD(quote_name(f.column)), 250 style.SQL_FIELD(quote_name(f.column)), 251 style.SQL_KEYWORD('IS NOT'), 248 252 style.SQL_KEYWORD('FROM'), 249 253 style.SQL_TABLE(quote_name(model._meta.db_table)))) 250 254 break # Only one AutoField is allowed per model, so don't bother continuing. 251 255 for f in model._meta.many_to_many: 252 output.append("%s setval('%s', (%s max(%s) %s %s));" % \256 output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ 253 257 (style.SQL_KEYWORD('SELECT'), 254 258 style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())), 255 style.SQL_KEYWORD('SELECT'),256 259 style.SQL_FIELD(quote_name('id')), 260 style.SQL_FIELD(quote_name('id')), 261 style.SQL_KEYWORD('IS NOT'), 257 262 style.SQL_KEYWORD('FROM'), 258 263 style.SQL_TABLE(f.m2m_db_table()))) django/branches/boulder-oracle-sprint/django/db/backends/postgresql_psycopg2/base.py
r5235 r5463 196 196 output = [] 197 197 for model in model_list: 198 # Use `coalesce` to set the sequence for each model to the max pk value if there are records, 199 # or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true 200 # if there are records (as the max pk value is already in use), otherwise set it to false. 198 201 for f in model._meta.fields: 199 202 if isinstance(f, models.AutoField): 200 output.append("%s setval('%s', (%s max(%s) %s %s));" % \203 output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ 201 204 (style.SQL_KEYWORD('SELECT'), 202 205 style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))), 203 style.SQL_KEYWORD('SELECT'),204 206 style.SQL_FIELD(quote_name(f.column)), 207 style.SQL_FIELD(quote_name(f.column)), 208 style.SQL_KEYWORD('IS NOT'), 205 209 style.SQL_KEYWORD('FROM'), 206 210 style.SQL_TABLE(quote_name(model._meta.db_table)))) 207 211 break # Only one AutoField is allowed per model, so don't bother continuing. 208 212 for f in model._meta.many_to_many: 209 output.append("%s setval('%s', (%s max(%s) %s %s));" % \213 output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ 210 214 (style.SQL_KEYWORD('SELECT'), 211 215 style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())), 212 style.SQL_KEYWORD('SELECT'),213 216 style.SQL_FIELD(quote_name('id')), 217 style.SQL_FIELD(quote_name('id')), 218 style.SQL_KEYWORD('IS NOT'), 214 219 style.SQL_KEYWORD('FROM'), 215 220 style.SQL_TABLE(f.m2m_db_table()))) django/branches/boulder-oracle-sprint/django/db/backends/util.py
r5307 r5463 93 93 94 94 def typecast_decimal(s): 95 if s is None :95 if s is None or s == '': 96 96 return None 97 97 return decimal.Decimal(s) django/branches/boulder-oracle-sprint/django/__init__.py
r4935 r5463 1 1 VERSION = (0, 97, 'pre') 2 3 def get_version(): 4 "Returns the version as a human-format string." 5 v = '.'.join([str(i) for i in VERSION[:-1]]) 6 if VERSION[-1]: 7 v += '-' + VERSION[-1] 8 return v django/branches/boulder-oracle-sprint/django/template/defaulttags.py
r5393 r5463 6 6 from django.conf import settings 7 7 import sys 8 import re 9 10 if not hasattr(__builtins__, 'reversed'): 11 # For Python 2.3. 12 # From http://www.python.org/doc/current/tut/node11.html 13 def reversed(data): 14 for index in xrange(len(data)-1, -1, -1): 15 yield data[index] 16 8 17 9 18 register = Library() … … 62 71 63 72 class ForNode(Node): 64 def __init__(self, loopvar , sequence, reversed, nodelist_loop):65 self.loopvar , self.sequence = loopvar, sequence73 def __init__(self, loopvars, sequence, reversed, nodelist_loop): 74 self.loopvars, self.sequence = loopvars, sequence 66 75 self.reversed = reversed 67 76 self.nodelist_loop = nodelist_loop … … 73 82 reversed = '' 74 83 return "<For Node: for %s in %s, tail_len: %d%s>" % \ 75 ( self.loopvar, self.sequence, len(self.nodelist_loop), reversed)84 (', '.join( self.loopvars ), self.sequence, len(self.nodelist_loop), reversed) 76 85 77 86 def __iter__(self): … … 103 112 len_values = len(values) 104 113 if self.reversed: 105 # From http://www.python.org/doc/current/tut/node11.html 106 def reverse(data): 107 for index in range(len(data)-1, -1, -1): 108 yield data[index] 109 values = reverse(values) 114 values = reversed(values) 115 unpack = len(self.loopvars) > 1 110 116 for i, item in enumerate(values): 111 117 context['forloop'] = { … … 121 127 'parentloop': parentloop, 122 128 } 123 context[self.loopvar] = item 129 if unpack: 130 # If there are multiple loop variables, unpack the item into them. 131 context.update(dict(zip(self.loopvars, item))) 132 else: 133 context[self.loopvars[0]] = item 124 134 for node in self.nodelist_loop: 125 135 nodelist.append(node.render(context)) 136 if unpack: 137 # The loop variables were pushed on to the context so pop them 138 # off again. This is necessary because the tag lets the length 139 # of loopvars differ to the length of each set of items and we 140 # don't want to leave any vars from the previous loop on the 141 # context. 142 context.pop() 126 143 context.pop() 127 144 return nodelist.render(context) … … 487 504 parser.delete_first_token() 488 505 return FilterNode(filter_expr, nodelist) 489 filter = register.tag("filter", do_filter)506 do_filter = register.tag("filter", do_filter) 490 507 491 508 #@register.tag … … 531 548 </ul> 532 549 533 You can alsoloop over a list in reverse by using550 You can loop over a list in reverse by using 534 551 ``{% for obj in list reversed %}``. 552 553 You can also unpack multiple values from a two-dimensional array:: 554 555 {% for key,value in dict.items %} 556 {{ key }}: {{ value }} 557 {% endfor %} 535 558 536 559 The for loop sets a number of variables available within the loop: … … 553 576 """ 554 577 bits = token.contents.split() 555 if len(bits) == 5 and bits[4] != 'reversed': 556 raise TemplateSyntaxError, "'for' statements with five words should end in 'reversed': %s" % token.contents 557 if len(bits) not in (4, 5): 558 raise TemplateSyntaxError, "'for' statements should have either four or five words: %s" % token.contents 559 if bits[2] != 'in': 560 raise TemplateSyntaxError, "'for' statement must contain 'in' as the second word: %s" % token.contents 561 loopvar = bits[1] 562 sequence = parser.compile_filter(bits[3]) 563 reversed = (len(bits) == 5) 578 if len(bits) < 4: 579 raise TemplateSyntaxError, "'for' statements should have at least four words: %s" % token.contents 580 581 reversed = bits[-1] == 'reversed' 582 in_index = reversed and -3 or -2 583 if bits[in_index] != 'in': 584 raise TemplateSyntaxError, "'for' statements should use the format 'for x in y': %s" % token.contents 585 586 loopvars = re.sub(r' *, *', ',', ' '.join(bits[1:in_index])).split(',') 587 for var in loopvars: 588 if not var or ' ' in var: 589 raise TemplateSyntaxError, "'for' tag received an invalid argument: %s" % token.contents 590 591 sequence = parser.compile_filter(bits[in_index+1]) 564 592 nodelist_loop = parser.parse(('endfor',)) 565 593 parser.delete_first_token() 566 return ForNode(loopvar , sequence, reversed, nodelist_loop)594 return ForNode(loopvars, sequence, reversed, nodelist_loop) 567 595 do_for = register.tag("for", do_for) 568 596 django/branches/boulder-oracle-sprint/django/views/debug.py
r5062 r5463 3 3 from django.utils.html import escape 4 4 from django.http import HttpResponseServerError, HttpResponseNotFound 5 import os, re 5 import os, re, sys 6 6 7 7 HIDDEN_SETTINGS = re.compile('SECRET|PASSWORD|PROFANITIES_LIST') … … 132 132 'request_protocol': request.is_secure() and "https" or "http", 133 133 'settings': get_safe_settings(), 134 'sys_executable' : sys.executable, 135 'sys_version_info' : '%d.%d.%d' % sys.version_info[0:3], 134 136 'template_info': template_info, 135 137 'template_does_not_exist': template_does_not_exist, … … 335 337 <td>{{ lastframe.filename|escape }} in {{ lastframe.function|escape }}, line {{ lastframe.lineno }}</td> 336 338 </tr> 339 <tr> 340 <th>Python Executable:</th> 341 <td>{{ sys_executable|escape }}</td> 342 </tr> 343 <tr> 344 <th>Python Version:</th> 345 <td>{{ sys_version_info }}</td> 346 </tr> 337 347 </table> 338 348 </div> django/branches/boulder-oracle-sprint/docs/add_ons.txt
r5047 r5463 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/boulder-oracle-sprint/docs/authentication.txt
r5100 r5463 731 731 ------------------- 732 732 733 Three basic permissions -- add, c reate and delete -- are automatically created733 Three basic permissions -- add, change and delete -- are automatically created 734 734 for each Django model that has a ``class Admin`` set. Behind the scenes, these 735 735 permissions are added to the ``auth_permission`` database table when you run django/branches/boulder-oracle-sprint/docs/db-api.txt
r5384 r5463 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 … … 380 389 underlying SQL statement, and the whole thing is enclosed in a ``NOT()``. 381 390 382 This example excludes all entries whose ``pub_date`` is the current date/time391 This example excludes all entries whose ``pub_date`` is later than 2005-1-3 383 392 AND whose ``headline`` is "Hello":: 384 393 … … 390 399 WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello') 391 400 392 This example excludes all entries whose ``pub_date`` is the current date/time393 OR whose ``headline`` is"Hello"::401 This example excludes all entries whose ``pub_date`` is later than 2005-1-3 402 AND whose headline is NOT "Hello":: 394 403 395 404 Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello') … … 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/boulder-oracle-sprint/docs/fastcgi.txt
r4906 r5463 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/boulder-oracle-sprint/docs/model-api.txt
r5384 r5463 447 447 448 448 The admin represents this as an ``<input type="text">`` (a single-line input). 449 450 ``URLField`` takes an optional argument, ``maxlength``, the maximum length (in 451 characters) of the field. The maxlength is enforced at the database level and 452 in Django's validation. If you don't specify ``maxlength``, a default of 200 453 is used. 449 454 450 455 ``USStateField`` … … 1878 1883 return row 1879 1884 1880 ``connection`` and ``cursor`` simply use the standard `Python DB-API`_. If 1881 you're not familiar with the Python DB-API, note that the SQL statement in 1882 ``cursor.execute()`` uses placeholders, ``"%s"``, rather than adding parameters 1883 directly within the SQL. If you use this technique, the underlying database 1884 library will automatically add quotes and escaping to your parameter(s) as 1885 necessary. (Also note that Django expects the ``"%s"`` placeholder, *not* the 1886 ``"?"`` placeholder, which is used by the SQLite Python bindings. This is for 1887 the sake of consistency and sanity.) 1885 ``connection`` and ``cursor`` mostly implement the standard `Python DB-API`_ 1886 (except when it comes to `transaction handling`_). If you're not familiar with 1887 the Python DB-API, note that the SQL statement in ``cursor.execute()`` uses 1888 placeholders, ``"%s"``, rather than adding parameters directly within the SQL. 1889 If you use this technique, the underlying database library will automatically 1890 add quotes and escaping to your parameter(s) as necessary. (Also note that 1891 Django expects the ``"%s"`` placeholder, *not* the ``"?"`` placeholder, which is 1892 used by the SQLite Python bindings. This is for the sake of consistency and 1893 sanity.) 1888 1894 1889 1895 A final note: If all you want to do is a custom ``WHERE`` clause, you can just … … 1893 1899 .. _Python DB-API: http://www.python.org/peps/pep-0249.html 1894 1900 .. _Other lookup options: ../db-api/#extra-params-select-where-tables 1901 .. _transaction handling: ../transactions/ 1895 1902 1896 1903 Overriding default model methods django/branches/boulder-oracle-sprint/docs/modpython.txt
r5384 r5463 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/boulder-oracle-sprint/docs/newforms.txt
r5384 r5463 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. 305 306 You can write code to perform validation for particular form fields (based on 307 their name) or for the form as a whole (considering combinations of various 308 fields). More information about this is in the `Custom form and field 309 validation`_ section, below. 303 310 304 311 Behavior of unbound forms 305 312 ~~~~~~~~~~~~~~~~~~~~~~~~~ 306 313 307 It's meaningless to request "clean " data in a form with no data, but, for the314 It's meaningless to request "cleaned" data in a form with no data, but, for the 308 315 record, here's what happens with unbound forms:: 309 316 … … 607 614 608 615 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:: 616 view and template. 617 618 Simple view example 619 ~~~~~~~~~~~~~~~~~~~ 620 621 This example view displays the contact form by default and validates/processes 622 it if accessed via a POST request:: 611 623 612 624 def contact(request): … … 620 632 return render_to_response('contact.html', {'form': form}) 621 633 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.634 Simple template example 635 ~~~~~~~~~~~~~~~~~~~~~~~ 636 637 The template in the above view example, ``contact.html``, is responsible for 638 displaying the form as HTML. To do this, we can use the techniques outlined in 639 the "Outputting forms as HTML" section above. 628 640 629 641 The simplest way to display a form's HTML is to use the variable on its own, … … 678 690 This iteration technique is useful if you want to apply the same HTML 679 691 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 which692 ahead of time. Note that the fields will be iterated over in the order in which 681 693 they're defined in the ``Form`` class. 682 694 … … 702 714 ----------------- 703 715 704 If you subclass a custom ``Form`` class, the resulting ``Form`` class will 716 If you have multiple ``Form`` classes that share fields, you can use 717 subclassing to remove redundancy. 718 719 When you subclass a custom ``Form`` class, the resulting subclass will 705 720 include all fields of the parent class(es), followed by the fields you define 706 721 in the subclass. … … 1202 1217 mentioned above (``required``, ``label``, ``initial``, ``widget``, 1203 1218 ``help_text``). 1219 1220 Custom form and field validation 1221 --------------------------------- 1222 1223 Form validation happens when the data is cleaned. If you want to customise 1224 this process, there are various places you can change, each one serving a 1225 different purpose. Thee types of cleaning methods are run during form 1226 processing. These are normally executed when you call the ``is_valid()`` 1227 method on a form. There are other things that can kick of cleaning and 1228 validation (accessing the ``errors`` attribute or calling ``full_clean()`` 1229 directly), but normally they won't be needed. 1230 1231 In general, any cleaning method can raise ``ValidationError`` if there is a 1232 problem with the data it is processing, passing the relevant error message to 1233 the ``ValidationError`` constructor. If no ``ValidationError`` is raised, the 1234 method should return the cleaned (normalised) data as a Python object. 1235 1236 If you detect multiple errors during a cleaning method and wish to signal all 1237 of them to the form submittor, it is possible to pass a list of errors to the 1238 ``ValidationError`` constructor. 1239 1240 The three types of cleaning methods are: 1241 1242 * The ``clean()`` method on a Field subclass. This is responsible 1243 for cleaning the data in a way that is generic for that type of field. 1244 For example, a FloatField will turn the data into a Python ``float`` or 1245 raise a ``ValidationError``. 1246 1247 * The ``clean_<fieldname>()`` method in a form subclass -- where 1248 ``<fieldname>`` is replaced with the name of the form field attribute. 1249 This method does any cleaning that is specific to that particular 1250 attribute, unrelated to the type of field that it is. This method is not 1251 passed any parameters. You will need to look up the value of the field 1252 in ``self.cleaned_data`` and remember that it will be a Python object 1253 at this point, not the original string submitted in the form (it will be 1254 in ``cleaned_data`` because the general field ``clean()`` method, above, 1255 has already cleaned the data once). 1256 1257 For example, if you wanted to validate that the contents of a 1258 ``CharField`` called ``serialnumber`` was unique, 1259 ``clean_serialnumber()`` would be the right place to do this. You don't 1260 need a specific field (it's just a ``CharField``), but you want a 1261 formfield-specific piece of validation and, possibly, 1262 cleaning/normalizing the data. 1263 1264 * The Form subclass's ``clean()`` method. This method can perform 1265 any validation that requires access to multiple fields from the form at 1266 once. This is where you might put in things to check that if field ``A`` 1267 is supplied, field ``B`` must contain a valid email address and the 1268 like. The data that this method returns is the final ``cleaned_data`` 1269 attribute for the form, so don't forget to return the full list of 1270 cleaned data if you override this method (by default, ``Form.clean()`` 1271 just returns ``self.cleaned_data``). 1272 1273 Note that any errors raised by your ``Form.clean()`` override will not 1274 be associated with any field in particular. They go into a special 1275 "field" (called ``__all__``, which you can access via the 1276 ``non_field_errors()`` method if you need to. 1277 1278 These methods are run in the order given above, one field at a time. That is, 1279 for each field in the form (in the order they are declared in the form 1280 definition), the ``Field.clean()`` method (or it's override) is run, then 1281 ``clean_<fieldname>()``. Finally, once those two methods are run for every 1282 field, the ``Form.clean()`` method, or it's override, is executed. 1283 1284 As mentioned above, any of these methods can raise a ``ValidationError``. For 1285 any field, if the ``Field.clean()`` method raises a ``ValidationError``, any 1286 field-specific cleaning method is not called. However, the cleaning methods 1287 for all remaining fields are still executed. 1288 1289 The ``clean()`` method for the ``Form`` class or subclass is always run. If 1290 that method raises a ``ValidationError``, ``cleaned_data`` will be an empty 1291 dictionary. 1292 1293 The previous paragraph means that if you are overriding ``Form.clean()``, you 1294 should iterate through ``self.cleaned_data.items()``, possibly considering the 1295 ``_errors`` dictionary attribute on the form as well. In this way, you will 1296 already know which fields have passed thei individual validation requirements. 1297 1298 A simple example 1299 ~~~~~~~~~~~~~~~~ 1300 1301 Here's a simple example of a custom field that validates its input is a string 1302 containing comma-separated e-mail addresses, with at least one address. We'll 1303 keep it simple and assume e-mail validation is contained in a function called 1304 ``is_valid_email()``. The full class:: 1305 1306 from django import newforms as forms 1307 1308 class MultiEmailField(forms.Field): 1309 def clean(self, value): 1310 emails = value.split(',') 1311 for email in emails: 1312 if not is_valid_email(email): 1313 raise forms.ValidationError('%s is not a valid e-mail address.' % email) 1314 if not emails: 1315 raise forms.ValidationError('Enter at least one e-mail address.') 1316 return emails 1317 1318 Let's alter the ongoing ``ContactForm`` example to demonstrate how you'd use 1319 this in a form. Simply use ``MultiEmailField`` instead of ``forms.EmailField``, 1320 like so:: 1321 1322 class ContactForm(forms.Form): 1323 subject = forms.CharField(max_length=100) 1324 message = forms.CharField() 1325 senders = MultiEmailField() 1326 cc_myself = forms.BooleanField() 1204 1327 1205 1328 Generating forms for models django/branches/boulder-oracle-sprint/docs/templates.txt
r5384 r5463 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/boulder-oracle-sprint/scripts/rpm-install.sh
r4935 r5463 22 22 sed -e "/\.py[co]$/d" -e "s/\.py$/.py*/" DIRS FILES >INSTALLED_FILES 23 23 24 mkdir -p ${RPM_BUILD_ROOT}/%{_mandir}/man1/ 25 cp docs/man/* ${RPM_BUILD_ROOT}/%{_mandir}/man1/ 26 cat << EOF >> INSTALLED_FILES 27 %doc %{_mandir}/man1/*" 28 EOF django/branches/boulder-oracle-sprint/tests/regressiontests/serializers_regress/tests.py
r5422 r5463 303 303 obj = ComplexModel(field1='first',field2='second',field3='third') 304 304 obj.save() 305 305 306 306 # Serialize then deserialize the test database 307 307 serialized_data = serializers.serialize(format, [obj], indent=2, fields=('field1','field3')) 308 308 result = serializers.deserialize(format, serialized_data).next() 309 309 310 310 # Check that the deserialized object contains data in only the serialized fields. 311 311 self.assertEqual(result.object.field1, 'first') … … 319 319 obj = ComplexModel(field1='first',field2='second',field3='third') 320 320 obj.save() 321 321 322 322 # Serialize the test database to a stream 323 stream = StringIO() 323 stream = StringIO() 324 324 serializers.serialize(format, [obj], indent=2, stream=stream) 325 325 326 326 # Serialize normally for a comparison 327 327 string_data = serializers.serialize(format, [obj], indent=2) 328 328 329 329 # Check that the two are the same 330 self.assertEqual(string_data, stream. buffer())330 self.assertEqual(string_data, stream.getvalue()) 331 331 stream.close() 332 332 333 333 for format in serializers.get_serializer_formats(): 334 334 setattr(SerializerTests, 'test_'+format+'_serializer', curry(serializerTest, format)) 335 335 setattr(SerializerTests, 'test_'+format+'_serializer_fields', curry(fieldsTest, format)) 336 setattr(SerializerTests, 'test_'+format+'_serializer_stream', curry(fieldsTest, format)) 336 if format != 'python': 337 setattr(SerializerTests, 'test_'+format+'_serializer_stream', curry(streamTest, format)) django/branches/boulder-oracle-sprint/tests/regressiontests/templates/tests.py
r5174 r5463 290 290 'for-tag-vars03': ("{% for val in values %}{{ forloop.revcounter }}{% endfor %}", {"values": [6, 6, 6]}, "321"), 291 291 'for-tag-vars04': ("{% for val in values %}{{ forloop.revcounter0 }}{% endfor %}", {"values": [6, 6, 6]}, "210"), 292 'for-tag-unpack01': ("{% for key,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"), 293 'for-tag-unpack03': ("{% for key, value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"), 294 'for-tag-unpack04': ("{% for key , value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"), 295 'for-tag-unpack05': ("{% for key ,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"), 296 'for-tag-unpack06': ("{% for key value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError), 297 'for-tag-unpack07': ("{% for key,,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError), 298 'for-tag-unpack08': ("{% for key,value, in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError), 299 # Ensure that a single loopvar doesn't truncate the list in val. 300 'for-tag-unpack09': ("{% for val in items %}{{ val.0 }}:{{ val.1 }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"), 301 # Otherwise, silently truncate if the length of loopvars differs to the length of each set of items. 302 'for-tag-unpack10': ("{% for x,y in items %}{{ x }}:{{ y }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2, 'orange'))}, "one:1/two:2/"), 303 '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/")), 304 '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/")), 305 '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/")), 292 306 293 307 ### IF TAG ################################################################
