Merged w/trunk up to r10333. This will probably be the last commit to this repo because all important functionality here has been merged into trunk. trunk tip
authorJustin Bronn <jbronn@geodjango.org>
Wed Apr 01 13:05:19 2009 -0500 (3 years ago)
branchtrunk
changeset 53023fdba116ba6
parent 444 694fc407a2e9
parent 529 8324a012725c
Merged w/trunk up to r10333. This will probably be the last commit to this repo because all important functionality here has been merged into trunk.
AUTHORS
MANIFEST.in
django/contrib/gis/db/backend/__init__.py
django/contrib/gis/db/backend/mysql/field.py
django/contrib/gis/db/backend/oracle/__init__.py
django/contrib/gis/db/backend/oracle/field.py
django/contrib/gis/db/backend/oracle/models.py
django/contrib/gis/db/backend/postgis/__init__.py
django/contrib/gis/db/backend/postgis/field.py
django/contrib/gis/db/backend/postgis/models.py
django/contrib/gis/db/backend/spatialite/__init__.py
django/contrib/gis/db/backend/spatialite/creation.py
django/contrib/gis/db/backend/spatialite/field.py
django/contrib/gis/db/backend/spatialite/models.py
django/contrib/gis/db/backend/spatialite/query.py
django/contrib/gis/db/backend/util.py
django/contrib/gis/db/models/aggregates.py
django/contrib/gis/db/models/fields/__init__.py
django/contrib/gis/db/models/mixin.py
django/contrib/gis/db/models/query.py
django/contrib/gis/db/models/sql/aggregates.py
django/contrib/gis/db/models/sql/conversion.py
django/contrib/gis/db/models/sql/query.py
django/contrib/gis/db/models/sql/where.py
django/contrib/gis/models.py
django/contrib/gis/tests/__init__.py
django/contrib/gis/tests/data/cities/cities.prj
django/contrib/gis/tests/data/interstates/interstates.prj
django/contrib/gis/tests/distapp/tests.py
django/contrib/gis/tests/geoapp/models.py
django/contrib/gis/tests/geoapp/tests.py
django/contrib/gis/tests/layermap/tests.py
django/contrib/gis/tests/relatedapp/models.py
django/contrib/gis/tests/relatedapp/tests.py
django/contrib/gis/tests/test_spatialrefsys.py
django/contrib/gis/tests/utils.py
django/contrib/gis/utils/srs.py
django/db/backends/mysql/base.py
django/db/backends/oracle/base.py
django/db/backends/postgresql/base.py
django/db/backends/postgresql_psycopg2/base.py
django/db/backends/sqlite3/base.py
django/db/models/sql/query.py
django/test/testcases.py
docs/ref/models/querysets.txt
tests/regressiontests/backends/tests.py
     1.1 --- a/AUTHORS	Sat Mar 28 12:05:48 2009 -0500
     1.2 +++ b/AUTHORS	Wed Apr 01 13:05:19 2009 -0500
     1.3 @@ -79,7 +79,7 @@
     1.4      Brett Cannon <brett@python.org>
     1.5      Ricardo Javier Cárdenes Medina <ricardo.cardenes@gmail.com>
     1.6      Jeremy Carbaugh <jcarbaugh@gmail.com>
     1.7 -    carljm <carl@dirtcircle.com>
     1.8 +    Carl Meyer <carl@dirtcircle.com>
     1.9      Graham Carlyle <graham.carlyle@maplecroft.net>
    1.10      Antonio Cavedoni <http://cavedoni.com/>
    1.11      C8E
    1.12 @@ -242,6 +242,7 @@
    1.13      konrad@gwu.edu
    1.14      knox <christobzr@gmail.com>
    1.15      David Krauth
    1.16 +    Kevin Kubasik <kevin@kubasik.net>
    1.17      kurtiss@meetro.com
    1.18      Denis Kuzmichyov <kuzmichyov@gmail.com>
    1.19      Panos Laganakos <panos.laganakos@gmail.com>
    1.20 @@ -364,6 +365,7 @@
    1.21      Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
    1.22      Vinay Sajip <vinay_sajip@yahoo.co.uk>
    1.23      Kadesarin Sanjek
    1.24 +    Massimo Scamarcia <massimo.scamarcia@gmail.com>
    1.25      David Schein
    1.26      Bernd Schlapsi
    1.27      scott@staplefish.com
     2.1 --- a/MANIFEST.in	Sat Mar 28 12:05:48 2009 -0500
     2.2 +++ b/MANIFEST.in	Wed Apr 01 13:05:19 2009 -0500
     2.3 @@ -10,6 +10,7 @@
     2.4  recursive-include scripts *
     2.5  recursive-include examples *
     2.6  recursive-include extras *
     2.7 +recursive-include tests *
     2.8  recursive-include django/conf/locale *
     2.9  recursive-include django/contrib/admin/templates *
    2.10  recursive-include django/contrib/admin/media *
     3.1 Binary file django/conf/locale/it/LC_MESSAGES/django.mo has changed
     4.1 --- a/django/conf/locale/it/LC_MESSAGES/django.po	Sat Mar 28 12:05:48 2009 -0500
     4.2 +++ b/django/conf/locale/it/LC_MESSAGES/django.po	Wed Apr 01 13:05:19 2009 -0500
     4.3 @@ -1,4 +1,4 @@
     4.4 -# translation of django.po to Italiano
     4.5 +# translation of django.po to Italian
     4.6  # Italian translation of Django.
     4.7  # Copyright (C) 2006 the Lawrence Journal-World
     4.8  # This file is distributed under the same license as the Django package.
     4.9 @@ -6,8 +6,8 @@
    4.10  msgstr ""
    4.11  "Project-Id-Version: django\n"
    4.12  "Report-Msgid-Bugs-To: \n"
    4.13 -"POT-Creation-Date: 2008-11-14 08:07+0100\n"
    4.14 -"PO-Revision-Date: 2008-11-14 08:10+0100\n"
    4.15 +"POT-Creation-Date: 2009-03-29 14:34+0200\n"
    4.16 +"PO-Revision-Date: 2009-03-29 14:58+0200\n"
    4.17  "Last-Translator: Nicola Larosa <nico@tekNico.net>\n"
    4.18  "Language-Team: Italiano\n"
    4.19  "MIME-Version: 1.0\n"
    4.20 @@ -101,118 +101,122 @@
    4.21  msgstr "ebraico"
    4.22  
    4.23  #: conf/global_settings.py:65
    4.24 +msgid "Hindi"
    4.25 +msgstr "hindi"
    4.26 +
    4.27 +#: conf/global_settings.py:66
    4.28  msgid "Croatian"
    4.29  msgstr "croato"
    4.30  
    4.31 -#: conf/global_settings.py:66
    4.32 +#: conf/global_settings.py:67
    4.33  msgid "Icelandic"
    4.34  msgstr "islandese"
    4.35  
    4.36 -#: conf/global_settings.py:67
    4.37 +#: conf/global_settings.py:68
    4.38  msgid "Italian"
    4.39  msgstr "italiano"
    4.40  
    4.41 -#: conf/global_settings.py:68
    4.42 +#: conf/global_settings.py:69
    4.43  msgid "Japanese"
    4.44  msgstr "giapponese"
    4.45  
    4.46 -#: conf/global_settings.py:69
    4.47 +#: conf/global_settings.py:70
    4.48  msgid "Georgian"
    4.49  msgstr "georgiano"
    4.50  
    4.51 -#: conf/global_settings.py:70
    4.52 +#: conf/global_settings.py:71
    4.53  msgid "Korean"
    4.54  msgstr "coreano"
    4.55  
    4.56 -#: conf/global_settings.py:71
    4.57 +#: conf/global_settings.py:72
    4.58  msgid "Khmer"
    4.59  msgstr "khmer"
    4.60  
    4.61 -#: conf/global_settings.py:72
    4.62 +#: conf/global_settings.py:73
    4.63  msgid "Kannada"
    4.64  msgstr "kannada"
    4.65  
    4.66 -#: conf/global_settings.py:73
    4.67 +#: conf/global_settings.py:74
    4.68  msgid "Latvian"
    4.69  msgstr "lettone"
    4.70  
    4.71 -#: conf/global_settings.py:74
    4.72 +#: conf/global_settings.py:75
    4.73  msgid "Lithuanian"
    4.74  msgstr "lituano"
    4.75  
    4.76 -#: conf/global_settings.py:75
    4.77 +#: conf/global_settings.py:76
    4.78  msgid "Macedonian"
    4.79  msgstr "macedone"
    4.80  
    4.81 -#: conf/global_settings.py:76
    4.82 +#: conf/global_settings.py:77
    4.83  msgid "Dutch"
    4.84  msgstr "olandese"
    4.85  
    4.86 -#: conf/global_settings.py:77
    4.87 +#: conf/global_settings.py:78
    4.88  msgid "Norwegian"
    4.89  msgstr "norvegese"
    4.90  
    4.91 -#: conf/global_settings.py:78
    4.92 +#: conf/global_settings.py:79
    4.93  msgid "Polish"
    4.94  msgstr "polacco"
    4.95  
    4.96 -#: conf/global_settings.py:79
    4.97 +#: conf/global_settings.py:80
    4.98  msgid "Portuguese"
    4.99  msgstr "portoghese"
   4.100  
   4.101 -#: conf/global_settings.py:80
   4.102 +#: conf/global_settings.py:81
   4.103  msgid "Brazilian Portuguese"
   4.104  msgstr "brasiliano portoghese"
   4.105  
   4.106 -#: conf/global_settings.py:81
   4.107 +#: conf/global_settings.py:82
   4.108  msgid "Romanian"
   4.109  msgstr "rumeno"
   4.110  
   4.111 -#: conf/global_settings.py:82
   4.112 +#: conf/global_settings.py:83
   4.113  msgid "Russian"
   4.114  msgstr "russo"
   4.115  
   4.116 -#: conf/global_settings.py:83
   4.117 +#: conf/global_settings.py:84
   4.118  msgid "Slovak"
   4.119  msgstr "slovacco"
   4.120  
   4.121 -#: conf/global_settings.py:84
   4.122 +#: conf/global_settings.py:85
   4.123  msgid "Slovenian"
   4.124  msgstr "sloveno"
   4.125  
   4.126 -#: conf/global_settings.py:85
   4.127 +#: conf/global_settings.py:86
   4.128  msgid "Serbian"
   4.129  msgstr "serbo"
   4.130  
   4.131 -#: conf/global_settings.py:86
   4.132 +#: conf/global_settings.py:87
   4.133  msgid "Swedish"
   4.134  msgstr "svedese"
   4.135  
   4.136 -#: conf/global_settings.py:87
   4.137 +#: conf/global_settings.py:88
   4.138  msgid "Tamil"
   4.139  msgstr "tamil"
   4.140  
   4.141 -#: conf/global_settings.py:88
   4.142 +#: conf/global_settings.py:89
   4.143  msgid "Telugu"
   4.144  msgstr "telugu"
   4.145  
   4.146 -#: conf/global_settings.py:89
   4.147 +#: conf/global_settings.py:90
   4.148  msgid "Thai"
   4.149  msgstr "thai"
   4.150  
   4.151 -#: conf/global_settings.py:90
   4.152 +#: conf/global_settings.py:91
   4.153  msgid "Turkish"
   4.154  msgstr "turco"
   4.155  
   4.156 -#: conf/global_settings.py:91
   4.157 +#: conf/global_settings.py:92
   4.158  msgid "Ukrainian"
   4.159  msgstr "ucraino"
   4.160  
   4.161 -#: conf/global_settings.py:92
   4.162 +#: conf/global_settings.py:93
   4.163  msgid "Simplified Chinese"
   4.164  msgstr "cinese semplificato"
   4.165  
   4.166 -#: conf/global_settings.py:93
   4.167 +#: conf/global_settings.py:94
   4.168  msgid "Traditional Chinese"
   4.169  msgstr "cinese tradizionale"
   4.170  
   4.171 @@ -225,43 +229,47 @@
   4.172  "<h3>Di %s:</h3>\n"
   4.173  "<ul>\n"
   4.174  
   4.175 -#: contrib/admin/filterspecs.py:74 contrib/admin/filterspecs.py:91
   4.176 -#: contrib/admin/filterspecs.py:146 contrib/admin/filterspecs.py:172
   4.177 +#: contrib/admin/filterspecs.py:75 contrib/admin/filterspecs.py:92
   4.178 +#: contrib/admin/filterspecs.py:147 contrib/admin/filterspecs.py:173
   4.179  msgid "All"
   4.180  msgstr "Tutti"
   4.181  
   4.182 -#: contrib/admin/filterspecs.py:112
   4.183 +#: contrib/admin/filterspecs.py:113
   4.184  msgid "Any date"
   4.185  msgstr "Qualsiasi data"
   4.186  
   4.187 -#: contrib/admin/filterspecs.py:113
   4.188 +#: contrib/admin/filterspecs.py:114
   4.189  msgid "Today"
   4.190  msgstr "Oggi"
   4.191  
   4.192 -#: contrib/admin/filterspecs.py:116
   4.193 +#: contrib/admin/filterspecs.py:117
   4.194  msgid "Past 7 days"
   4.195  msgstr "Ultimi 7 giorni"
   4.196  
   4.197 -#: contrib/admin/filterspecs.py:118
   4.198 +#: contrib/admin/filterspecs.py:119
   4.199  msgid "This month"
   4.200  msgstr "Questo mese"
   4.201  
   4.202 -#: contrib/admin/filterspecs.py:120
   4.203 +#: contrib/admin/filterspecs.py:121
   4.204  msgid "This year"
   4.205  msgstr "Quest'anno"
   4.206  
   4.207 -#: contrib/admin/filterspecs.py:146 forms/widgets.py:390
   4.208 +#: contrib/admin/filterspecs.py:147 forms/widgets.py:413
   4.209  msgid "Yes"
   4.210  msgstr "Sì"
   4.211  
   4.212 -#: contrib/admin/filterspecs.py:146 forms/widgets.py:390
   4.213 +#: contrib/admin/filterspecs.py:147 forms/widgets.py:413
   4.214  msgid "No"
   4.215  msgstr "No"
   4.216  
   4.217 -#: contrib/admin/filterspecs.py:153 forms/widgets.py:390
   4.218 +#: contrib/admin/filterspecs.py:154 forms/widgets.py:413
   4.219  msgid "Unknown"
   4.220  msgstr "Sconosciuto"
   4.221  
   4.222 +#: contrib/admin/helpers.py:14
   4.223 +msgid "Action:"
   4.224 +msgstr "Azione:"
   4.225 +
   4.226  #: contrib/admin/models.py:19
   4.227  msgid "action time"
   4.228  msgstr "momento dell'azione"
   4.229 @@ -290,100 +298,117 @@
   4.230  msgid "log entries"
   4.231  msgstr "voci di log"
   4.232  
   4.233 -#: contrib/admin/options.py:60 contrib/admin/options.py:121
   4.234 +#: contrib/admin/options.py:131 contrib/admin/options.py:145
   4.235  msgid "None"
   4.236  msgstr "Nessuno"
   4.237  
   4.238 -#: contrib/admin/options.py:338
   4.239 +#: contrib/admin/options.py:498
   4.240 +#, python-format
   4.241 +msgid "Successfully deleted %(count)d %(items)s."
   4.242 +msgstr "Cancellati con successo %(count)d %(items)s."
   4.243 +
   4.244 +#: contrib/admin/options.py:505 contrib/admin/options.py:1012
   4.245 +msgid "Are you sure?"
   4.246 +msgstr "Sei sicuro?"
   4.247 +
   4.248 +#: contrib/admin/options.py:523
   4.249 +#, python-format
   4.250 +msgid "Delete selected %(verbose_name_plural)s"
   4.251 +msgstr "Cancellati i %(verbose_name_plural)s selezionati"
   4.252 +
   4.253 +#: contrib/admin/options.py:531
   4.254  #, python-format
   4.255  msgid "Changed %s."
   4.256  msgstr "%s modificato."
   4.257  
   4.258 -#: contrib/admin/options.py:338 contrib/admin/options.py:348
   4.259 -#: contrib/comments/templates/comments/preview.html:15 forms/models.py:288
   4.260 +#: contrib/admin/options.py:531 contrib/admin/options.py:541
   4.261 +#: contrib/comments/templates/comments/preview.html:15 forms/models.py:296
   4.262  msgid "and"
   4.263  msgstr "e"
   4.264  
   4.265 -#: contrib/admin/options.py:343
   4.266 +#: contrib/admin/options.py:536
   4.267  #, python-format
   4.268  msgid "Added %(name)s \"%(object)s\"."
   4.269  msgstr "Aggiunti %(name)s \"%(object)s\"."
   4.270  
   4.271 -#: contrib/admin/options.py:347
   4.272 +#: contrib/admin/options.py:540
   4.273  #, python-format
   4.274  msgid "Changed %(list)s for %(name)s \"%(object)s\"."
   4.275  msgstr "Cambiati %(list)s per %(name)s \"%(object)s\"."
   4.276  
   4.277 -#: contrib/admin/options.py:352
   4.278 +#: contrib/admin/options.py:545
   4.279  #, python-format
   4.280  msgid "Deleted %(name)s \"%(object)s\"."
   4.281  msgstr "Cancellati %(name)s \"%(object)s\"."
   4.282  
   4.283 -#: contrib/admin/options.py:356
   4.284 +#: contrib/admin/options.py:549
   4.285  msgid "No fields changed."
   4.286  msgstr "Nessun campo modificato."
   4.287  
   4.288 -#: contrib/admin/options.py:417 contrib/auth/admin.py:51
   4.289 +#: contrib/admin/options.py:610 contrib/auth/admin.py:67
   4.290  #, python-format
   4.291  msgid "The %(name)s \"%(obj)s\" was added successfully."
   4.292  msgstr "%(name)s \"%(obj)s\" è stato aggiunto correttamente."
   4.293  
   4.294 -#: contrib/admin/options.py:421 contrib/admin/options.py:454
   4.295 -#: contrib/auth/admin.py:59
   4.296 +#: contrib/admin/options.py:614 contrib/admin/options.py:647
   4.297 +#: contrib/auth/admin.py:75
   4.298  msgid "You may edit it again below."
   4.299  msgstr "È possibile modificarlo nuovamente qui sotto."
   4.300  
   4.301 -#: contrib/admin/options.py:431 contrib/admin/options.py:464
   4.302 +#: contrib/admin/options.py:624 contrib/admin/options.py:657
   4.303  #, python-format
   4.304  msgid "You may add another %s below."
   4.305  msgstr "Puoi aggiungere un altro %s qui sotto."
   4.306  
   4.307 -#: contrib/admin/options.py:452
   4.308 +#: contrib/admin/options.py:645
   4.309  #, python-format
   4.310  msgid "The %(name)s \"%(obj)s\" was changed successfully."
   4.311  msgstr "%(name)s \"%(obj)s\" modificato correttamente."
   4.312  
   4.313 -#: contrib/admin/options.py:460
   4.314 +#: contrib/admin/options.py:653
   4.315  #, python-format
   4.316  msgid "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
   4.317  msgstr ""
   4.318  "%(name)s \"%(obj)s\" aggiunto correttamente. Puoi modificarlo ancora qui "
   4.319  "sotto."
   4.320  
   4.321 -#: contrib/admin/options.py:528
   4.322 +#: contrib/admin/options.py:774
   4.323  #, python-format
   4.324  msgid "Add %s"
   4.325  msgstr "Aggiungi %s"
   4.326  
   4.327 -#: contrib/admin/options.py:559 contrib/admin/options.py:673
   4.328 +#: contrib/admin/options.py:805 contrib/admin/options.py:990
   4.329  #, python-format
   4.330  msgid "%(name)s object with primary key %(key)r does not exist."
   4.331  msgstr "L'oggetto %(name)s con chiave primaria %(key)r non esiste."
   4.332  
   4.333 -#: contrib/admin/options.py:606
   4.334 +#: contrib/admin/options.py:862
   4.335  #, python-format
   4.336  msgid "Change %s"
   4.337  msgstr "Modifica %s"
   4.338  
   4.339 -#: contrib/admin/options.py:638
   4.340 +#: contrib/admin/options.py:894
   4.341  msgid "Database error"
   4.342  msgstr "Errore nel database"
   4.343  
   4.344 -#: contrib/admin/options.py:688
   4.345 +#: contrib/admin/options.py:930
   4.346 +#, python-format
   4.347 +msgid "%(count)s %(name)s was changed successfully."
   4.348 +msgid_plural "%(count)s %(name)s were changed successfully."
   4.349 +msgstr[0] "%(count)s %(name)s è stato modificato correttamente."
   4.350 +msgstr[1] "%(count)s %(name)s sono stati modificati correttamente."
   4.351 +
   4.352 +#: contrib/admin/options.py:1005
   4.353  #, python-format
   4.354  msgid "The %(name)s \"%(obj)s\" was deleted successfully."
   4.355  msgstr "%(name)s \"%(obj)s\" cancellato correttamente."
   4.356  
   4.357 -#: contrib/admin/options.py:695
   4.358 -msgid "Are you sure?"
   4.359 -msgstr "Sei sicuro?"
   4.360 -
   4.361 -#: contrib/admin/options.py:724
   4.362 +#: contrib/admin/options.py:1041
   4.363  #, python-format
   4.364  msgid "Change history: %s"
   4.365  msgstr "Tracciato delle modifiche: %s"
   4.366  
   4.367 -#: contrib/admin/sites.py:16 contrib/admin/views/decorators.py:14
   4.368 +#: contrib/admin/sites.py:15 contrib/admin/views/decorators.py:14
   4.369  #: contrib/auth/forms.py:80
   4.370  msgid ""
   4.371  "Please enter a correct username and password. Note that both fields are case-"
   4.372 @@ -392,11 +417,11 @@
   4.373  "Inserisci nome utente e password corretti. In entrambi i campi le maiuscole "
   4.374  "sono significative."
   4.375  
   4.376 -#: contrib/admin/sites.py:226 contrib/admin/views/decorators.py:40
   4.377 +#: contrib/admin/sites.py:250 contrib/admin/views/decorators.py:40
   4.378  msgid "Please log in again, because your session has expired."
   4.379  msgstr "Effettua di nuovo l'accesso, perché la tua sessione è scaduta."
   4.380  
   4.381 -#: contrib/admin/sites.py:233 contrib/admin/views/decorators.py:47
   4.382 +#: contrib/admin/sites.py:257 contrib/admin/views/decorators.py:47
   4.383  msgid ""
   4.384  "Looks like your browser isn't configured to accept cookies. Please enable "
   4.385  "cookies, reload this page, and try again."
   4.386 @@ -404,37 +429,37 @@
   4.387  "Il browser non sembra configurato per accettare i cookie. Una volta "
   4.388  "abilitati, ricarica la pagina e riprova."
   4.389  
   4.390 -#: contrib/admin/sites.py:249 contrib/admin/sites.py:255
   4.391 +#: contrib/admin/sites.py:273 contrib/admin/sites.py:279
   4.392  #: contrib/admin/views/decorators.py:66
   4.393  msgid "Usernames cannot contain the '@' character."
   4.394  msgstr "I nomi utente non possono contenere il carattere '@'."
   4.395  
   4.396 -#: contrib/admin/sites.py:252 contrib/admin/views/decorators.py:62
   4.397 +#: contrib/admin/sites.py:276 contrib/admin/views/decorators.py:62
   4.398  #, python-format
   4.399  msgid "Your e-mail address is not your username. Try '%s' instead."
   4.400  msgstr "Il nome utente non è costituito dall'indirizzo e-mail. Prova con '%s'."
   4.401  
   4.402 -#: contrib/admin/sites.py:312
   4.403 +#: contrib/admin/sites.py:336
   4.404  msgid "Site administration"
   4.405  msgstr "Amministrazione sito"
   4.406  
   4.407 -#: contrib/admin/sites.py:325 contrib/admin/templates/admin/login.html:26
   4.408 +#: contrib/admin/sites.py:349 contrib/admin/templates/admin/login.html:26
   4.409  #: contrib/admin/templates/registration/password_reset_complete.html:14
   4.410  #: contrib/admin/views/decorators.py:20
   4.411  msgid "Log in"
   4.412  msgstr "Accedi"
   4.413  
   4.414 -#: contrib/admin/sites.py:372
   4.415 +#: contrib/admin/sites.py:396
   4.416  #, python-format
   4.417  msgid "%s administration"
   4.418  msgstr "Amministrazione %s"
   4.419  
   4.420 -#: contrib/admin/util.py:138
   4.421 +#: contrib/admin/util.py:168
   4.422  #, python-format
   4.423  msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
   4.424  msgstr "Uno o più %(fieldname)s in %(name)s: %(obj)s"
   4.425  
   4.426 -#: contrib/admin/util.py:143
   4.427 +#: contrib/admin/util.py:173
   4.428  #, python-format
   4.429  msgid "One or more %(fieldname)s in %(name)s:"
   4.430  msgstr "Uno o più %(fieldname)s in %(name)s:"
   4.431 @@ -474,10 +499,11 @@
   4.432  
   4.433  #: contrib/admin/templates/admin/500.html:4
   4.434  #: contrib/admin/templates/admin/app_index.html:8
   4.435 -#: contrib/admin/templates/admin/base.html:31
   4.436 +#: contrib/admin/templates/admin/base.html:33
   4.437  #: contrib/admin/templates/admin/change_form.html:17
   4.438 -#: contrib/admin/templates/admin/change_list.html:8
   4.439 +#: contrib/admin/templates/admin/change_list.html:20
   4.440  #: contrib/admin/templates/admin/delete_confirmation.html:6
   4.441 +#: contrib/admin/templates/admin/delete_selected_confirmation.html:6
   4.442  #: contrib/admin/templates/admin/invalid_setup.html:4
   4.443  #: contrib/admin/templates/admin/object_history.html:6
   4.444  #: contrib/admin/templates/admin/auth/user/change_password.html:10
   4.445 @@ -512,24 +538,33 @@
   4.446  "Si è verificato un errore. È stato riportato agli amministratori del sito "
   4.447  "via e-mail e verrà corretto a breve. Grazie per la tua pazienza."
   4.448  
   4.449 +#: contrib/admin/templates/admin/actions.html:4
   4.450 +msgid "Run the selected action"
   4.451 +msgstr "Esegui l'azione selezionata"
   4.452 +
   4.453 +#: contrib/admin/templates/admin/actions.html:4
   4.454 +#: contrib/admin/templates/admin/search_form.html:8
   4.455 +msgid "Go"
   4.456 +msgstr "Vai"
   4.457 +
   4.458  #: contrib/admin/templates/admin/app_index.html:10
   4.459  #: contrib/admin/templates/admin/index.html:19
   4.460  #, python-format
   4.461  msgid "%(name)s"
   4.462  msgstr "%(name)s"
   4.463  
   4.464 -#: contrib/admin/templates/admin/base.html:26
   4.465 +#: contrib/admin/templates/admin/base.html:28
   4.466  msgid "Welcome,"
   4.467  msgstr "Benvenuto,"
   4.468  
   4.469 -#: contrib/admin/templates/admin/base.html:26
   4.470 +#: contrib/admin/templates/admin/base.html:28
   4.471  #: contrib/admin/templates/registration/password_change_done.html:3
   4.472  #: contrib/admin/templates/registration/password_change_form.html:3
   4.473  #: contrib/admindocs/templates/admin_doc/bookmarklets.html:3
   4.474  msgid "Documentation"
   4.475  msgstr "Documentazione"
   4.476  
   4.477 -#: contrib/admin/templates/admin/base.html:26
   4.478 +#: contrib/admin/templates/admin/base.html:28
   4.479  #: contrib/admin/templates/admin/auth/user/change_password.html:13
   4.480  #: contrib/admin/templates/admin/auth/user/change_password.html:46
   4.481  #: contrib/admin/templates/registration/password_change_done.html:3
   4.482 @@ -537,7 +572,7 @@
   4.483  msgid "Change password"
   4.484  msgstr "Cambia la password"
   4.485  
   4.486 -#: contrib/admin/templates/admin/base.html:26
   4.487 +#: contrib/admin/templates/admin/base.html:28
   4.488  #: contrib/admin/templates/registration/password_change_done.html:3
   4.489  #: contrib/admin/templates/registration/password_change_form.html:3
   4.490  msgid "Log out"
   4.491 @@ -568,23 +603,24 @@
   4.492  msgstr "Vedi sul sito"
   4.493  
   4.494  #: contrib/admin/templates/admin/change_form.html:38
   4.495 +#: contrib/admin/templates/admin/change_list.html:49
   4.496  #: contrib/admin/templates/admin/auth/user/change_password.html:22
   4.497  msgid "Please correct the error below."
   4.498  msgid_plural "Please correct the errors below."
   4.499  msgstr[0] "Correggi gli errori qui sotto."
   4.500  msgstr[1] "Correggi gli errori qui sotto."
   4.501  
   4.502 -#: contrib/admin/templates/admin/change_list.html:16
   4.503 +#: contrib/admin/templates/admin/change_list.html:41
   4.504  #, python-format
   4.505  msgid "Add %(name)s"
   4.506  msgstr "Aggiungi %(name)s"
   4.507  
   4.508 -#: contrib/admin/templates/admin/change_list.html:26
   4.509 +#: contrib/admin/templates/admin/change_list.html:60
   4.510  msgid "Filter"
   4.511  msgstr "Filtro"
   4.512  
   4.513  #: contrib/admin/templates/admin/delete_confirmation.html:10
   4.514 -#: contrib/admin/templates/admin/submit_line.html:4 forms/formsets.py:246
   4.515 +#: contrib/admin/templates/admin/submit_line.html:4 forms/formsets.py:251
   4.516  msgid "Delete"
   4.517  msgstr "Cancella"
   4.518  
   4.519 @@ -609,9 +645,32 @@
   4.520  "oggetti collegati seguenti saranno cancellati:"
   4.521  
   4.522  #: contrib/admin/templates/admin/delete_confirmation.html:28
   4.523 +#: contrib/admin/templates/admin/delete_selected_confirmation.html:33
   4.524  msgid "Yes, I'm sure"
   4.525  msgstr "Sì, sono sicuro"
   4.526  
   4.527 +#: contrib/admin/templates/admin/delete_selected_confirmation.html:9
   4.528 +msgid "Delete multiple objects"
   4.529 +msgstr "Cancella più oggetti"
   4.530 +
   4.531 +#: contrib/admin/templates/admin/delete_selected_confirmation.html:15
   4.532 +#, python-format
   4.533 +msgid ""
   4.534 +"Deleting the %(object_name)s would result in deleting related objects, but "
   4.535 +"your account doesn't have permission to delete the following types of "
   4.536 +"objects:"
   4.537 +msgstr ""
   4.538 +"La cancellazione di %(object_name)s causerebbe la "
   4.539 +"cancellazione di oggetti collegati, ma il tuo account non ha i permessi per "
   4.540 +"cancellare gli oggetti dei seguenti tipi:"
   4.541 +
   4.542 +#: contrib/admin/templates/admin/delete_selected_confirmation.html:22
   4.543 +#, python-format
   4.544 +msgid ""
   4.545 +"Are you sure you want to delete the selected %(object_name)s objects? All of "
   4.546 +"the following objects and it's related items will be deleted:"
   4.547 +msgstr "Sicuro di voler cancellare i %(object_name)s selezionati? Tutti i seguenti oggetti, e i loro oggetti collegati, saranno cancellati:"
   4.548 +
   4.549  #: contrib/admin/templates/admin/filter.html:2
   4.550  #, python-format
   4.551  msgid " By %(filter_title)s "
   4.552 @@ -674,7 +733,7 @@
   4.553  msgstr "Azione"
   4.554  
   4.555  #: contrib/admin/templates/admin/object_history.html:30
   4.556 -#: utils/translation/trans_real.py:404
   4.557 +#: utils/translation/trans_real.py:400
   4.558  msgid "DATETIME_FORMAT"
   4.559  msgstr "j F Y, H:i"
   4.560  
   4.561 @@ -690,10 +749,6 @@
   4.562  msgid "Show all"
   4.563  msgstr "Mostra tutto"
   4.564  
   4.565 -#: contrib/admin/templates/admin/search_form.html:8
   4.566 -msgid "Go"
   4.567 -msgstr "Vai"
   4.568 -
   4.569  #: contrib/admin/templates/admin/search_form.html:10
   4.570  #, python-format
   4.571  msgid "1 result"
   4.572 @@ -737,13 +792,13 @@
   4.573  
   4.574  #: contrib/admin/templates/admin/auth/user/add_form.html:20
   4.575  #: contrib/admin/templates/admin/auth/user/change_password.html:33
   4.576 -#: contrib/auth/forms.py:17 contrib/auth/forms.py:60 contrib/auth/forms.py:184
   4.577 +#: contrib/auth/forms.py:17 contrib/auth/forms.py:60 contrib/auth/forms.py:185
   4.578  msgid "Password"
   4.579  msgstr "Password"
   4.580  
   4.581  #: contrib/admin/templates/admin/auth/user/add_form.html:26
   4.582  #: contrib/admin/templates/admin/auth/user/change_password.html:39
   4.583 -#: contrib/auth/forms.py:185
   4.584 +#: contrib/auth/forms.py:186
   4.585  msgid "Password (again)"
   4.586  msgstr "Password (di nuovo)"
   4.587  
   4.588 @@ -913,166 +968,166 @@
   4.589  msgid "Reset my password"
   4.590  msgstr "Reimposta la mia password"
   4.591  
   4.592 -#: contrib/admin/templatetags/admin_list.py:284
   4.593 +#: contrib/admin/templatetags/admin_list.py:299
   4.594  msgid "All dates"
   4.595  msgstr "Tutte le date"
   4.596  
   4.597 -#: contrib/admin/views/main.py:69
   4.598 +#: contrib/admin/views/main.py:70
   4.599  #, python-format
   4.600  msgid "Select %s"
   4.601  msgstr "Scegli %s"
   4.602  
   4.603 -#: contrib/admin/views/main.py:69
   4.604 +#: contrib/admin/views/main.py:70
   4.605  #, python-format
   4.606  msgid "Select %s to change"
   4.607  msgstr "Scegli %s da modificare"
   4.608  
   4.609 -#: contrib/admin/views/template.py:36 contrib/sites/models.py:38
   4.610 +#: contrib/admin/views/template.py:37 contrib/sites/models.py:38
   4.611  msgid "site"
   4.612  msgstr "sito"
   4.613  
   4.614 -#: contrib/admin/views/template.py:38
   4.615 +#: contrib/admin/views/template.py:39
   4.616  msgid "template"
   4.617  msgstr "modello"
   4.618  
   4.619 -#: contrib/admindocs/views.py:57 contrib/admindocs/views.py:59
   4.620 -#: contrib/admindocs/views.py:61
   4.621 +#: contrib/admindocs/views.py:58 contrib/admindocs/views.py:60
   4.622 +#: contrib/admindocs/views.py:62
   4.623  msgid "tag:"
   4.624  msgstr "tag:"
   4.625  
   4.626 -#: contrib/admindocs/views.py:90 contrib/admindocs/views.py:92
   4.627 -#: contrib/admindocs/views.py:94
   4.628 +#: contrib/admindocs/views.py:91 contrib/admindocs/views.py:93
   4.629 +#: contrib/admindocs/views.py:95
   4.630  msgid "filter:"
   4.631  msgstr "filtro:"
   4.632  
   4.633 -#: contrib/admindocs/views.py:154 contrib/admindocs/views.py:156
   4.634 -#: contrib/admindocs/views.py:158
   4.635 +#: contrib/admindocs/views.py:155 contrib/admindocs/views.py:157
   4.636 +#: contrib/admindocs/views.py:159
   4.637  msgid "view:"
   4.638  msgstr "view:"
   4.639  
   4.640 -#: contrib/admindocs/views.py:186
   4.641 +#: contrib/admindocs/views.py:187
   4.642  #, python-format
   4.643  msgid "App %r not found"
   4.644  msgstr "Appl. %r non trovata"
   4.645  
   4.646 -#: contrib/admindocs/views.py:193
   4.647 +#: contrib/admindocs/views.py:194
   4.648  #, python-format
   4.649  msgid "Model %(model_name)r not found in app %(app_label)r"
   4.650  msgstr "Modello %(model_name)r non trovato nell'appl. %(app_label)r"
   4.651  
   4.652 -#: contrib/admindocs/views.py:205
   4.653 +#: contrib/admindocs/views.py:206
   4.654  #, python-format
   4.655  msgid "the related `%(app_label)s.%(data_type)s` object"
   4.656  msgstr "l'oggetto `%(app_label)s.%(data_type)s` collegato"
   4.657  
   4.658 -#: contrib/admindocs/views.py:205 contrib/admindocs/views.py:227
   4.659 -#: contrib/admindocs/views.py:241 contrib/admindocs/views.py:246
   4.660 +#: contrib/admindocs/views.py:206 contrib/admindocs/views.py:228
   4.661 +#: contrib/admindocs/views.py:242 contrib/admindocs/views.py:247
   4.662  msgid "model:"
   4.663  msgstr "modello:"
   4.664  
   4.665 -#: contrib/admindocs/views.py:236
   4.666 +#: contrib/admindocs/views.py:237
   4.667  #, python-format
   4.668  msgid "related `%(app_label)s.%(object_name)s` objects"
   4.669  msgstr "oggetti `%(app_label)s.%(object_name)s` collegati"
   4.670  
   4.671 -#: contrib/admindocs/views.py:241
   4.672 +#: contrib/admindocs/views.py:242
   4.673  #, python-format
   4.674  msgid "all %s"
   4.675  msgstr "tutti %s"
   4.676  
   4.677 -#: contrib/admindocs/views.py:246
   4.678 +#: contrib/admindocs/views.py:247
   4.679  #, python-format
   4.680  msgid "number of %s"
   4.681  msgstr "numero di %s"
   4.682  
   4.683 -#: contrib/admindocs/views.py:251
   4.684 +#: contrib/admindocs/views.py:252
   4.685  #, python-format
   4.686  msgid "Fields on %s objects"
   4.687  msgstr "Campi sugli oggetti %s"
   4.688  
   4.689 -#: contrib/admindocs/views.py:314 contrib/admindocs/views.py:325
   4.690 -#: contrib/admindocs/views.py:327 contrib/admindocs/views.py:333
   4.691 -#: contrib/admindocs/views.py:334 contrib/admindocs/views.py:336
   4.692 +#: contrib/admindocs/views.py:315 contrib/admindocs/views.py:326
   4.693 +#: contrib/admindocs/views.py:328 contrib/admindocs/views.py:334
   4.694 +#: contrib/admindocs/views.py:335 contrib/admindocs/views.py:337
   4.695  msgid "Integer"
   4.696  msgstr "Intero"
   4.697  
   4.698 -#: contrib/admindocs/views.py:315
   4.699 +#: contrib/admindocs/views.py:316
   4.700  msgid "Boolean (Either True or False)"
   4.701  msgstr "Booleano (True o False)"
   4.702  
   4.703 -#: contrib/admindocs/views.py:316 contrib/admindocs/views.py:335
   4.704 +#: contrib/admindocs/views.py:317 contrib/admindocs/views.py:336
   4.705  #, python-format
   4.706  msgid "String (up to %(max_length)s)"
   4.707  msgstr "Stringa (fino a %(max_length)s)"
   4.708  
   4.709 -#: contrib/admindocs/views.py:317
   4.710 +#: contrib/admindocs/views.py:318
   4.711  msgid "Comma-separated integers"
   4.712  msgstr "Interi separati da virgola"
   4.713  
   4.714 -#: contrib/admindocs/views.py:318
   4.715 +#: contrib/admindocs/views.py:319
   4.716  msgid "Date (without time)"
   4.717  msgstr "Data (senza ora)"
   4.718  
   4.719 -#: contrib/admindocs/views.py:319
   4.720 +#: contrib/admindocs/views.py:320
   4.721  msgid "Date (with time)"
   4.722  msgstr "Data (con ora)"
   4.723  
   4.724 -#: contrib/admindocs/views.py:320
   4.725 +#: contrib/admindocs/views.py:321
   4.726  msgid "Decimal number"
   4.727  msgstr "Numero decimale"
   4.728  
   4.729 -#: contrib/admindocs/views.py:321
   4.730 +#: contrib/admindocs/views.py:322
   4.731  msgid "E-mail address"
   4.732  msgstr "Indirizzo e-mail"
   4.733  
   4.734 -#: contrib/admindocs/views.py:322 contrib/admindocs/views.py:323
   4.735 -#: contrib/admindocs/views.py:326
   4.736 +#: contrib/admindocs/views.py:323 contrib/admindocs/views.py:324
   4.737 +#: contrib/admindocs/views.py:327
   4.738  msgid "File path"
   4.739  msgstr "Percorso di file"
   4.740  
   4.741 -#: contrib/admindocs/views.py:324
   4.742 +#: contrib/admindocs/views.py:325
   4.743  msgid "Floating point number"
   4.744  msgstr "Numero decimale"
   4.745  
   4.746 -#: contrib/admindocs/views.py:328 contrib/comments/models.py:58
   4.747 +#: contrib/admindocs/views.py:329 contrib/comments/models.py:58
   4.748  msgid "IP address"
   4.749  msgstr "indirizzo IP"
   4.750  
   4.751 -#: contrib/admindocs/views.py:330
   4.752 +#: contrib/admindocs/views.py:331
   4.753  msgid "Boolean (Either True, False or None)"
   4.754  msgstr "Booleano (True, False o None)"
   4.755  
   4.756 -#: contrib/admindocs/views.py:331
   4.757 +#: contrib/admindocs/views.py:332
   4.758  msgid "Relation to parent model"
   4.759  msgstr "Collegamento a modello padre"
   4.760  
   4.761 -#: contrib/admindocs/views.py:332
   4.762 +#: contrib/admindocs/views.py:333
   4.763  msgid "Phone number"
   4.764  msgstr "Numero di telefono"
   4.765  
   4.766 -#: contrib/admindocs/views.py:337
   4.767 +#: contrib/admindocs/views.py:338
   4.768  msgid "Text"
   4.769  msgstr "Testo"
   4.770  
   4.771 -#: contrib/admindocs/views.py:338
   4.772 +#: contrib/admindocs/views.py:339
   4.773  msgid "Time"
   4.774  msgstr "Ora"
   4.775  
   4.776 -#: contrib/admindocs/views.py:339 contrib/comments/forms.py:21
   4.777 +#: contrib/admindocs/views.py:340 contrib/comments/forms.py:95
   4.778  #: contrib/comments/templates/comments/moderation_queue.html:37
   4.779  #: contrib/flatpages/admin.py:8 contrib/flatpages/models.py:7
   4.780  msgid "URL"
   4.781  msgstr "URL"
   4.782  
   4.783 -#: contrib/admindocs/views.py:340
   4.784 +#: contrib/admindocs/views.py:341
   4.785  msgid "U.S. state (two uppercase letters)"
   4.786  msgstr "Stato USA (due lettere maiuscole)"
   4.787  
   4.788 -#: contrib/admindocs/views.py:341
   4.789 +#: contrib/admindocs/views.py:342
   4.790  msgid "XML text"
   4.791  msgstr "Testo XML"
   4.792  
   4.793 -#: contrib/admindocs/views.py:367
   4.794 +#: contrib/admindocs/views.py:368
   4.795  #, python-format
   4.796  msgid "%s does not appear to be a urlpattern object"
   4.797  msgstr "%s non sembra essere un oggetto urlpattern"
   4.798 @@ -1164,15 +1219,15 @@
   4.799  msgid "Groups"
   4.800  msgstr "Gruppi"
   4.801  
   4.802 -#: contrib/auth/admin.py:64
   4.803 +#: contrib/auth/admin.py:80
   4.804  msgid "Add user"
   4.805  msgstr "Aggiungi utente"
   4.806  
   4.807 -#: contrib/auth/admin.py:90
   4.808 +#: contrib/auth/admin.py:106
   4.809  msgid "Password changed successfully."
   4.810  msgstr "La password è stata cambiata correttamente."
   4.811  
   4.812 -#: contrib/auth/admin.py:96
   4.813 +#: contrib/auth/admin.py:112
   4.814  #, python-format
   4.815  msgid "Change password: %s"
   4.816  msgstr "Cambia la password: %s"
   4.817 @@ -1198,8 +1253,8 @@
   4.818  msgid "A user with that username already exists."
   4.819  msgstr "Un utente con questo nome·è già presente."
   4.820  
   4.821 -#: contrib/auth/forms.py:36 contrib/auth/forms.py:154
   4.822 -#: contrib/auth/forms.py:196
   4.823 +#: contrib/auth/forms.py:36 contrib/auth/forms.py:155
   4.824 +#: contrib/auth/forms.py:197
   4.825  msgid "The two password fields didn't match."
   4.826  msgstr "I due campi password non corrispondono."
   4.827  
   4.828 @@ -1227,24 +1282,24 @@
   4.829  "Questo indirizzo email non è associato ad alcun account utente. Sei sicuro "
   4.830  "di esserti registrato?"
   4.831  
   4.832 -#: contrib/auth/forms.py:134
   4.833 +#: contrib/auth/forms.py:135
   4.834  #, python-format
   4.835  msgid "Password reset on %s"
   4.836  msgstr "Password reimpostata su %s"
   4.837  
   4.838 -#: contrib/auth/forms.py:142
   4.839 +#: contrib/auth/forms.py:143
   4.840  msgid "New password"
   4.841  msgstr "Nuova password"
   4.842  
   4.843 -#: contrib/auth/forms.py:143
   4.844 +#: contrib/auth/forms.py:144
   4.845  msgid "New password confirmation"
   4.846  msgstr "Conferma nuova password"
   4.847  
   4.848 -#: contrib/auth/forms.py:168
   4.849 +#: contrib/auth/forms.py:169
   4.850  msgid "Old password"
   4.851  msgstr "Password attuale"
   4.852  
   4.853 -#: contrib/auth/forms.py:176
   4.854 +#: contrib/auth/forms.py:177
   4.855  msgid "Your old password was entered incorrectly. Please enter it again."
   4.856  msgstr "La password attuale non è stata inserita correttamente: va inserita di nuovo."
   4.857  
   4.858 @@ -1368,7 +1423,7 @@
   4.859  msgid "Logged out"
   4.860  msgstr "Accesso annullato"
   4.861  
   4.862 -#: contrib/auth/management/commands/createsuperuser.py:23 forms/fields.py:428
   4.863 +#: contrib/auth/management/commands/createsuperuser.py:23 forms/fields.py:429
   4.864  msgid "Enter a valid e-mail address."
   4.865  msgstr "Inserisci un indirizzo e-mail valido."
   4.866  
   4.867 @@ -1380,31 +1435,31 @@
   4.868  msgid "Metadata"
   4.869  msgstr "Metadati"
   4.870  
   4.871 -#: contrib/comments/forms.py:19
   4.872 +#: contrib/comments/forms.py:93
   4.873  #: contrib/comments/templates/comments/moderation_queue.html:34
   4.874  msgid "Name"
   4.875  msgstr "Nome"
   4.876  
   4.877 -#: contrib/comments/forms.py:20
   4.878 +#: contrib/comments/forms.py:94
   4.879  msgid "Email address"
   4.880  msgstr "Indirizzo email"
   4.881  
   4.882 -#: contrib/comments/forms.py:22
   4.883 +#: contrib/comments/forms.py:96
   4.884  #: contrib/comments/templates/comments/moderation_queue.html:35
   4.885  msgid "Comment"
   4.886  msgstr "Commento"
   4.887  
   4.888 -#: contrib/comments/forms.py:25
   4.889 -msgid "If you enter anything in this field your comment will be treated as spam"
   4.890 -msgstr "Se inserisci qualcosa in questo campo il tuo commento verrà considerato spam"
   4.891 -
   4.892 -#: contrib/comments/forms.py:125
   4.893 +#: contrib/comments/forms.py:173
   4.894  #, python-format
   4.895  msgid "Watch your mouth! The word %s is not allowed here."
   4.896  msgid_plural "Watch your mouth! The words %s are not allowed here."
   4.897  msgstr[0] "Modera i termini: la parola %s non è ammessa."
   4.898  msgstr[1] "Modera i termini: le parole %s non sono ammesse."
   4.899  
   4.900 +#: contrib/comments/forms.py:180
   4.901 +msgid "If you enter anything in this field your comment will be treated as spam"
   4.902 +msgstr "Se inserisci qualcosa in questo campo il tuo commento verrà considerato spam"
   4.903 +
   4.904  #: contrib/comments/models.py:23
   4.905  msgid "object ID"
   4.906  msgstr "ID dell'oggetto"
   4.907 @@ -2024,6 +2079,82 @@
   4.908  msgid "The Chilean RUT is not valid."
   4.909  msgstr "Il RUT cileno non è valido."
   4.910  
   4.911 +#: contrib/localflavor/cz/cz_regions.py:8
   4.912 +msgid "Prague"
   4.913 +msgstr "Praga"
   4.914 +
   4.915 +#: contrib/localflavor/cz/cz_regions.py:9
   4.916 +msgid "Central Bohemian Region"
   4.917 +msgstr "Regione Boema Centrale"
   4.918 +
   4.919 +#: contrib/localflavor/cz/cz_regions.py:10
   4.920 +msgid "South Bohemian Region"
   4.921 +msgstr "Regione Boema del Sud"
   4.922 +
   4.923 +#: contrib/localflavor/cz/cz_regions.py:11
   4.924 +msgid "Pilsen Region"
   4.925 +msgstr "Regione di Pilsen"
   4.926 +
   4.927 +#: contrib/localflavor/cz/cz_regions.py:12
   4.928 +msgid "Carlsbad Region"
   4.929 +msgstr "Regione di Carlsbad"
   4.930 +
   4.931 +#: contrib/localflavor/cz/cz_regions.py:13
   4.932 +msgid "Usti Region"
   4.933 +msgstr "Regione di Usti"
   4.934 +
   4.935 +#: contrib/localflavor/cz/cz_regions.py:14
   4.936 +msgid "Liberec Region"
   4.937 +msgstr "Regione di Liberec"
   4.938 +
   4.939 +#: contrib/localflavor/cz/cz_regions.py:15
   4.940 +msgid "Hradec Region"
   4.941 +msgstr "Regione di Hradec"
   4.942 +
   4.943 +#: contrib/localflavor/cz/cz_regions.py:16
   4.944 +msgid "Pardubice Region"
   4.945 +msgstr "Regione di Pardubice"
   4.946 +
   4.947 +#: contrib/localflavor/cz/cz_regions.py:17
   4.948 +msgid "Vysocina Region"
   4.949 +msgstr "Regione di Vysocina"
   4.950 +
   4.951 +#: contrib/localflavor/cz/cz_regions.py:18
   4.952 +msgid "South Moravian Region"
   4.953 +msgstr "Regione della Moravia del Sud"
   4.954 +
   4.955 +#: contrib/localflavor/cz/cz_regions.py:19
   4.956 +msgid "Olomouc Region"
   4.957 +msgstr "Regione di Olomouc"
   4.958 +
   4.959 +#: contrib/localflavor/cz/cz_regions.py:20
   4.960 +msgid "Zlin Region"
   4.961 +msgstr "Regione di Zlin"
   4.962 +
   4.963 +#: contrib/localflavor/cz/cz_regions.py:21
   4.964 +msgid "Moravian-Silesian Region"
   4.965 +msgstr "Regione della Moravia-Silesia"
   4.966 +
   4.967 +#: contrib/localflavor/cz/forms.py:27 contrib/localflavor/sk/forms.py:30
   4.968 +msgid "Enter a postal code in the format XXXXX or XXX XX."
   4.969 +msgstr "Inserisci un codice postale nel formato XXXXX o XXX XX ."
   4.970 +
   4.971 +#: contrib/localflavor/cz/forms.py:47
   4.972 +msgid "Enter a birth number in the format XXXXXX/XXXX or XXXXXXXXXX."
   4.973 +msgstr "Inserisci un numero di nascita nel formato XXXXXX/XXXX o XXXXXXXXXX."
   4.974 +
   4.975 +#: contrib/localflavor/cz/forms.py:48
   4.976 +msgid "Invalid optional parameter Gender, valid values are 'f' and 'm'"
   4.977 +msgstr "Parametro opzionale 'Sesso' non valido, i valori validi sono 'f' ed 'm'"
   4.978 +
   4.979 +#: contrib/localflavor/cz/forms.py:49
   4.980 +msgid "Enter a valid birth number."
   4.981 +msgstr "Inserisci un numero di nascita valido."
   4.982 +
   4.983 +#: contrib/localflavor/cz/forms.py:106
   4.984 +msgid "Enter a valid IC number."
   4.985 +msgstr "Inserisci un numero di IC valido."
   4.986 +
   4.987  #: contrib/localflavor/de/de_states.py:5
   4.988  msgid "Baden-Wuerttemberg"
   4.989  msgstr "Baden-Wuerttemberg"
   4.990 @@ -2948,10 +3079,6 @@
   4.991  msgid "Enter a valid postal code in the format XXXXXX"
   4.992  msgstr "Inserisci un codice postale valido nel formato XXXXXX."
   4.993  
   4.994 -#: contrib/localflavor/sk/forms.py:30
   4.995 -msgid "Enter a postal code in the format XXXXX or XXX XX."
   4.996 -msgstr "Inserisci un codice postale nel formato XXXXX o XXX XX ."
   4.997 -
   4.998  #: contrib/localflavor/sk/sk_districts.py:8
   4.999  msgid "Banska Bystrica"
  4.1000  msgstr "Banska Bystrica"
  4.1001 @@ -3702,52 +3829,56 @@
  4.1002  msgid "sites"
  4.1003  msgstr "siti"
  4.1004  
  4.1005 -#: db/models/fields/__init__.py:348 db/models/fields/__init__.py:683
  4.1006 +#: db/models/fields/__init__.py:356 db/models/fields/__init__.py:700
  4.1007  msgid "This value must be an integer."
  4.1008  msgstr "Questo valore deve essere un intero."
  4.1009  
  4.1010 -#: db/models/fields/__init__.py:379
  4.1011 +#: db/models/fields/__init__.py:387
  4.1012  msgid "This value must be either True or False."
  4.1013  msgstr "Questo valore deve essere True o False."
  4.1014  
  4.1015 -#: db/models/fields/__init__.py:412
  4.1016 +#: db/models/fields/__init__.py:420
  4.1017  msgid "This field cannot be null."
  4.1018  msgstr "Questo campo non può essere nullo."
  4.1019  
  4.1020 -#: db/models/fields/__init__.py:428
  4.1021 +#: db/models/fields/__init__.py:436
  4.1022  msgid "Enter only digits separated by commas."
  4.1023  msgstr "Inserisci solo cifre separate da virgole."
  4.1024  
  4.1025 -#: db/models/fields/__init__.py:459
  4.1026 +#: db/models/fields/__init__.py:467
  4.1027  msgid "Enter a valid date in YYYY-MM-DD format."
  4.1028  msgstr "Inserisci una data valida in formato AAAA-MM-GG."
  4.1029  
  4.1030 -#: db/models/fields/__init__.py:468
  4.1031 +#: db/models/fields/__init__.py:476
  4.1032  #, python-format
  4.1033  msgid "Invalid date: %s"
  4.1034  msgstr "Data non valida: %s"
  4.1035  
  4.1036 -#: db/models/fields/__init__.py:532 db/models/fields/__init__.py:550
  4.1037 +#: db/models/fields/__init__.py:540 db/models/fields/__init__.py:558
  4.1038  msgid "Enter a valid date/time in YYYY-MM-DD HH:MM[:ss[.uuuuuu]] format."
  4.1039  msgstr "Inserisci una data/ora valida nel formato AAAA-MM-GG OO:MM[ss[.uuuuuu]]."
  4.1040  
  4.1041 -#: db/models/fields/__init__.py:586
  4.1042 +#: db/models/fields/__init__.py:594
  4.1043  msgid "This value must be a decimal number."
  4.1044  msgstr "Questo valore deve essere un numero decimale."
  4.1045  
  4.1046 -#: db/models/fields/__init__.py:719
  4.1047 +#: db/models/fields/__init__.py:676
  4.1048 +msgid "This value must be a float."
  4.1049 +msgstr "Questo valore deve essere un numero a virgola mobile."
  4.1050 +
  4.1051 +#: db/models/fields/__init__.py:736
  4.1052  msgid "This value must be either None, True or False."
  4.1053  msgstr "Questo valore deve essere None, True o False."
  4.1054  
  4.1055 -#: db/models/fields/__init__.py:817 db/models/fields/__init__.py:831
  4.1056 +#: db/models/fields/__init__.py:839 db/models/fields/__init__.py:853
  4.1057  msgid "Enter a valid time in HH:MM[:ss[.uuuuuu]] format."
  4.1058  msgstr "Inserisci un ora valida nel formato OO:MM[ss[.uuuuuu]]."
  4.1059  
  4.1060 -#: db/models/fields/related.py:761
  4.1061 +#: db/models/fields/related.py:787
  4.1062  msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
  4.1063  msgstr "Tieni premuto \"Control\", o \"Command\" su Mac, per selezionarne più di uno."
  4.1064  
  4.1065 -#: db/models/fields/related.py:838
  4.1066 +#: db/models/fields/related.py:865
  4.1067  #, python-format
  4.1068  msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
  4.1069  msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid."
  4.1070 @@ -3809,109 +3940,111 @@
  4.1071  msgid "Ensure that there are no more than %s digits before the decimal point."
  4.1072  msgstr "Assicurarsi che non vi siano più di %s cifre prima della virgola."
  4.1073  
  4.1074 -#: forms/fields.py:287 forms/fields.py:849
  4.1075 +#: forms/fields.py:288 forms/fields.py:850
  4.1076  msgid "Enter a valid date."
  4.1077  msgstr "Inserisci una data valida."
  4.1078  
  4.1079 -#: forms/fields.py:321 forms/fields.py:850
  4.1080 +#: forms/fields.py:322 forms/fields.py:851
  4.1081  msgid "Enter a valid time."
  4.1082  msgstr "Inserisci un ora valida."
  4.1083  
  4.1084 -#: forms/fields.py:360
  4.1085 +#: forms/fields.py:361
  4.1086  msgid "Enter a valid date/time."
  4.1087  msgstr "Inserisci una coppia data/ora valida."
  4.1088  
  4.1089 -#: forms/fields.py:446
  4.1090 +#: forms/fields.py:447
  4.1091  msgid "No file was submitted. Check the encoding type on the form."
  4.1092  msgstr "Non è stato inviato alcun file. Verifica il tipo di codifica della form."
  4.1093  
  4.1094 -#: forms/fields.py:447
  4.1095 +#: forms/fields.py:448
  4.1096  msgid "No file was submitted."
  4.1097  msgstr "Nessun file è stato inviato."
  4.1098  
  4.1099 -#: forms/fields.py:448
  4.1100 +#: forms/fields.py:449
  4.1101  msgid "The submitted file is empty."
  4.1102  msgstr "Il file inviato è vuoto."
  4.1103  
  4.1104 -#: forms/fields.py:477
  4.1105 +#: forms/fields.py:478
  4.1106  msgid ""
  4.1107  "Upload a valid image. The file you uploaded was either not an image or a "
  4.1108  "corrupted image."
  4.1109  msgstr "Carica un'immagine valida. Il file caricato non è un'immagine o è corrotto."
  4.1110  
  4.1111 -#: forms/fields.py:538
  4.1112 +#: forms/fields.py:539
  4.1113  msgid "Enter a valid URL."
  4.1114  msgstr "Inserisci una URL valida."
  4.1115  
  4.1116 -#: forms/fields.py:539
  4.1117 +#: forms/fields.py:540
  4.1118  msgid "This URL appears to be a broken link."
  4.1119  msgstr "Questa URL non sembra funzionare."
  4.1120  
  4.1121 -#: forms/fields.py:618 forms/fields.py:696
  4.1122 +#: forms/fields.py:619 forms/fields.py:697
  4.1123  #, python-format
  4.1124  msgid "Select a valid choice. %(value)s is not one of the available choices."
  4.1125  msgstr "Scegli un'opzione valida. '%(value)s non compare tra quelle disponibili."
  4.1126  
  4.1127 -#: forms/fields.py:697 forms/fields.py:758 forms/models.py:720
  4.1128 +#: forms/fields.py:698 forms/fields.py:759 forms/models.py:729
  4.1129  msgid "Enter a list of values."
  4.1130  msgstr "Inserisci una lista di valori."
  4.1131  
  4.1132 -#: forms/fields.py:878
  4.1133 +#: forms/fields.py:879
  4.1134  msgid "Enter a valid IPv4 address."
  4.1135  msgstr "Inserisci un indirizzo IPv4 valido."
  4.1136  
  4.1137 -#: forms/fields.py:888
  4.1138 +#: forms/fields.py:889
  4.1139  msgid "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."
  4.1140  msgstr ""
  4.1141  "Inserisci uno 'slug' valido contenente lettere, cifre, sottolineati o "
  4.1142  "trattini."
  4.1143  
  4.1144 -#: forms/formsets.py:242 forms/formsets.py:244
  4.1145 +#: forms/formsets.py:247 forms/formsets.py:249
  4.1146  msgid "Order"
  4.1147  msgstr "Ordine"
  4.1148  
  4.1149 -#: forms/models.py:281 forms/models.py:290
  4.1150 +#: forms/models.py:289 forms/models.py:298
  4.1151  #, python-format
  4.1152  msgid "%(model_name)s with this %(field_label)s already exists."
  4.1153  msgstr "%(model_name)s con questo %(field_label)s esiste già."
  4.1154  
  4.1155 -#: forms/models.py:587
  4.1156 +#: forms/models.py:602
  4.1157  msgid "The inline foreign key did not match the parent instance primary key."
  4.1158 -msgstr "La foreign key inline non concorda con la chiave primaria dell'istanza principale."
  4.1159 -
  4.1160 -#: forms/models.py:650
  4.1161 +msgstr ""
  4.1162 +"La foreign key inline non concorda con la chiave primaria dell'istanza "
  4.1163 +"principale."
  4.1164 +
  4.1165 +#: forms/models.py:659
  4.1166  msgid "Select a valid choice. That choice is not one of the available choices."
  4.1167  msgstr ""
  4.1168  "Scegli un'opzione valida. La scelta effettuata non compare tra quelle "
  4.1169  "disponibili."
  4.1170  
  4.1171 -#: forms/models.py:721
  4.1172 +#: forms/models.py:730
  4.1173  #, python-format
  4.1174  msgid "Select a valid choice. %s is not one of the available choices."
  4.1175  msgstr "Scegli un'opzione valida. %s non compare tra quelle disponibili."
  4.1176  
  4.1177 -#: template/defaultfilters.py:741
  4.1178 +#: template/defaultfilters.py:751
  4.1179  msgid "yes,no,maybe"
  4.1180  msgstr "sì,no,forse"
  4.1181  
  4.1182 -#: template/defaultfilters.py:772
  4.1183 +#: template/defaultfilters.py:782
  4.1184  #, python-format
  4.1185  msgid "%(size)d byte"
  4.1186  msgid_plural "%(size)d bytes"
  4.1187  msgstr[0] "%(size)d byte"
  4.1188  msgstr[1] "%(size)d byte"
  4.1189  
  4.1190 -#: template/defaultfilters.py:774
  4.1191 +#: template/defaultfilters.py:784
  4.1192  #, python-format
  4.1193  msgid "%.1f KB"
  4.1194  msgstr "%.1f KB"
  4.1195  
  4.1196 -#: template/defaultfilters.py:776
  4.1197 +#: template/defaultfilters.py:786
  4.1198  #, python-format
  4.1199  msgid "%.1f MB"
  4.1200  msgstr "%.1f MB"
  4.1201  
  4.1202 -#: template/defaultfilters.py:777
  4.1203 +#: template/defaultfilters.py:787
  4.1204  #, python-format
  4.1205  msgid "%.1f GB"
  4.1206  msgstr "%.1f GB"
  4.1207 @@ -4174,19 +4307,19 @@
  4.1208  msgid ", %(number)d %(type)s"
  4.1209  msgstr ", %(number)d %(type)s"
  4.1210  
  4.1211 -#: utils/translation/trans_real.py:403
  4.1212 +#: utils/translation/trans_real.py:399
  4.1213  msgid "DATE_FORMAT"
  4.1214  msgstr "j F Y"
  4.1215  
  4.1216 -#: utils/translation/trans_real.py:405
  4.1217 +#: utils/translation/trans_real.py:401
  4.1218  msgid "TIME_FORMAT"
  4.1219  msgstr "H:i"
  4.1220  
  4.1221 -#: utils/translation/trans_real.py:421
  4.1222 +#: utils/translation/trans_real.py:417
  4.1223  msgid "YEAR_MONTH_FORMAT"
  4.1224  msgstr "Y F"
  4.1225  
  4.1226 -#: utils/translation/trans_real.py:422
  4.1227 +#: utils/translation/trans_real.py:418
  4.1228  msgid "MONTH_DAY_FORMAT"
  4.1229  msgstr "F j"
  4.1230  
     5.1 Binary file django/conf/locale/pl/LC_MESSAGES/django.mo has changed
     6.1 --- a/django/conf/locale/pl/LC_MESSAGES/django.po	Sat Mar 28 12:05:48 2009 -0500
     6.2 +++ b/django/conf/locale/pl/LC_MESSAGES/django.po	Wed Apr 01 13:05:19 2009 -0500
     6.3 @@ -5,7 +5,7 @@
     6.4  msgstr ""
     6.5  "Project-Id-Version: Django\n"
     6.6  "Report-Msgid-Bugs-To: \n"
     6.7 -"POT-Creation-Date: 2009-03-25 09:18+0100\n"
     6.8 +"POT-Creation-Date: 2009-03-31 09:52+0200\n"
     6.9  "PO-Revision-Date: 2008-02-25 15:53+0100\n"
    6.10  "Last-Translator: Jarek Zgoda <jarek.zgoda@gmail.com>\n"
    6.11  "MIME-Version: 1.0\n"
    6.12 @@ -320,7 +320,7 @@
    6.13  msgstr "Zmieniono %s"
    6.14  
    6.15  #: contrib/admin/options.py:531 contrib/admin/options.py:541
    6.16 -#: contrib/comments/templates/comments/preview.html:15 forms/models.py:296
    6.17 +#: contrib/comments/templates/comments/preview.html:15 forms/models.py:306
    6.18  msgid "and"
    6.19  msgstr "i"
    6.20  
    6.21 @@ -463,27 +463,27 @@
    6.22  msgid "One or more %(fieldname)s in %(name)s:"
    6.23  msgstr "Jedno lub więcej %(fieldname)s w %(name)s:"
    6.24  
    6.25 -#: contrib/admin/widgets.py:70
    6.26 +#: contrib/admin/widgets.py:71
    6.27  msgid "Date:"
    6.28  msgstr "Data:"
    6.29  
    6.30 -#: contrib/admin/widgets.py:70
    6.31 +#: contrib/admin/widgets.py:71
    6.32  msgid "Time:"
    6.33  msgstr "Czas:"
    6.34  
    6.35 -#: contrib/admin/widgets.py:94
    6.36 +#: contrib/admin/widgets.py:95
    6.37  msgid "Currently:"
    6.38  msgstr "Teraz:"
    6.39  
    6.40 -#: contrib/admin/widgets.py:94
    6.41 +#: contrib/admin/widgets.py:95
    6.42  msgid "Change:"
    6.43  msgstr "Zmień:"
    6.44  
    6.45 -#: contrib/admin/widgets.py:123
    6.46 +#: contrib/admin/widgets.py:124
    6.47  msgid "Lookup"
    6.48  msgstr "Szukaj"
    6.49  
    6.50 -#: contrib/admin/widgets.py:230
    6.51 +#: contrib/admin/widgets.py:236
    6.52  msgid "Add Another"
    6.53  msgstr "Dodaj kolejny"
    6.54  
    6.55 @@ -565,8 +565,8 @@
    6.56  msgstr "Dokumentacja"
    6.57  
    6.58  #: contrib/admin/templates/admin/base.html:28
    6.59 -#: contrib/admin/templates/admin/auth/user/change_password.html:13
    6.60 -#: contrib/admin/templates/admin/auth/user/change_password.html:46
    6.61 +#: contrib/admin/templates/admin/auth/user/change_password.html:14
    6.62 +#: contrib/admin/templates/admin/auth/user/change_password.html:47
    6.63  #: contrib/admin/templates/registration/password_change_done.html:3
    6.64  #: contrib/admin/templates/registration/password_change_form.html:3
    6.65  msgid "Change password"
    6.66 @@ -604,7 +604,7 @@
    6.67  
    6.68  #: contrib/admin/templates/admin/change_form.html:38
    6.69  #: contrib/admin/templates/admin/change_list.html:49
    6.70 -#: contrib/admin/templates/admin/auth/user/change_password.html:22
    6.71 +#: contrib/admin/templates/admin/auth/user/change_password.html:23
    6.72  msgid "Please correct the error below."
    6.73  msgid_plural "Please correct the errors below."
    6.74  msgstr[0] "Proszę popraw poniższy błąd."
    6.75 @@ -621,7 +621,7 @@
    6.76  msgstr "Filtr"
    6.77  
    6.78  #: contrib/admin/templates/admin/delete_confirmation.html:10
    6.79 -#: contrib/admin/templates/admin/submit_line.html:4 forms/formsets.py:251
    6.80 +#: contrib/admin/templates/admin/submit_line.html:4 forms/formsets.py:276
    6.81  msgid "Delete"
    6.82  msgstr "Usuń"
    6.83  
    6.84 @@ -794,23 +794,23 @@
    6.85  msgstr "Nazwa użytkownika"
    6.86  
    6.87  #: contrib/admin/templates/admin/auth/user/add_form.html:20
    6.88 -#: contrib/admin/templates/admin/auth/user/change_password.html:33
    6.89 +#: contrib/admin/templates/admin/auth/user/change_password.html:34
    6.90  #: contrib/auth/forms.py:17 contrib/auth/forms.py:60 contrib/auth/forms.py:185
    6.91  msgid "Password"
    6.92  msgstr "Hasło"
    6.93  
    6.94  #: contrib/admin/templates/admin/auth/user/add_form.html:26
    6.95 -#: contrib/admin/templates/admin/auth/user/change_password.html:39
    6.96 +#: contrib/admin/templates/admin/auth/user/change_password.html:40
    6.97  #: contrib/auth/forms.py:186
    6.98  msgid "Password (again)"
    6.99  msgstr "Hasło (powtórz)"
   6.100  
   6.101  #: contrib/admin/templates/admin/auth/user/add_form.html:27
   6.102 -#: contrib/admin/templates/admin/auth/user/change_password.html:40
   6.103 +#: contrib/admin/templates/admin/auth/user/change_password.html:41
   6.104  msgid "Enter the same password as above, for verification."
   6.105  msgstr "Podaj powyższe hasło w celu weryfikacji."
   6.106  
   6.107 -#: contrib/admin/templates/admin/auth/user/change_password.html:26
   6.108 +#: contrib/admin/templates/admin/auth/user/change_password.html:27
   6.109  #, python-format
   6.110  msgid "Enter a new password for the user <strong>%(username)s</strong>."
   6.111  msgstr "Podaj nowe hasło dla użytkownika <strong>%(username)s</strong>."
   6.112 @@ -1231,7 +1231,7 @@
   6.113  msgstr "Zmień hasło: %s"
   6.114  
   6.115  #: contrib/auth/forms.py:15 contrib/auth/forms.py:48
   6.116 -#: contrib/auth/models.py:127
   6.117 +#: contrib/auth/models.py:128
   6.118  msgid ""
   6.119  "Required. 30 characters or fewer. Alphanumeric characters only (letters, "
   6.120  "digits and underscores)."
   6.121 @@ -1321,31 +1321,31 @@
   6.122  msgid "group"
   6.123  msgstr "grupa"
   6.124  
   6.125 -#: contrib/auth/models.py:91 contrib/auth/models.py:137
   6.126 +#: contrib/auth/models.py:91 contrib/auth/models.py:138
   6.127  msgid "groups"
   6.128  msgstr "grupy"
   6.129  
   6.130 -#: contrib/auth/models.py:127
   6.131 +#: contrib/auth/models.py:128
   6.132  msgid "username"
   6.133  msgstr "użytkownik"
   6.134  
   6.135 -#: contrib/auth/models.py:128
   6.136 +#: contrib/auth/models.py:129
   6.137  msgid "first name"
   6.138  msgstr "imię"
   6.139  
   6.140 -#: contrib/auth/models.py:129
   6.141 +#: contrib/auth/models.py:130
   6.142  msgid "last name"
   6.143  msgstr "nazwisko"
   6.144  
   6.145 -#: contrib/auth/models.py:130
   6.146 +#: contrib/auth/models.py:131
   6.147  msgid "e-mail address"
   6.148  msgstr "adres e-mail"
   6.149  
   6.150 -#: contrib/auth/models.py:131
   6.151 +#: contrib/auth/models.py:132
   6.152  msgid "password"
   6.153  msgstr "hasło"
   6.154  
   6.155 -#: contrib/auth/models.py:131
   6.156 +#: contrib/auth/models.py:132
   6.157  msgid ""
   6.158  "Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
   6.159  "password form</a>."
   6.160 @@ -1353,19 +1353,19 @@
   6.161  "Użyj '[algo]$[salt]$[hexdigest]' lub <a href=\"password/\">formularza zmiany "
   6.162  "hasła</a>."
   6.163  
   6.164 -#: contrib/auth/models.py:132
   6.165 +#: contrib/auth/models.py:133
   6.166  msgid "staff status"
   6.167  msgstr "w zespole"
   6.168  
   6.169 -#: contrib/auth/models.py:132
   6.170 +#: contrib/auth/models.py:133
   6.171  msgid "Designates whether the user can log into this admin site."
   6.172  msgstr "Oznacza czy użytkownik może zalogować się do panelu admina."
   6.173  
   6.174 -#: contrib/auth/models.py:133
   6.175 +#: contrib/auth/models.py:134
   6.176  msgid "active"
   6.177  msgstr "aktywny"
   6.178  
   6.179 -#: contrib/auth/models.py:133
   6.180 +#: contrib/auth/models.py:134
   6.181  msgid ""
   6.182  "Designates whether this user should be treated as active. Unselect this "
   6.183  "instead of deleting accounts."
   6.184 @@ -1373,11 +1373,11 @@
   6.185  "Oznacza czy użytkownika należy uważać za aktywnego. Odznacz to, zamiast "
   6.186  "usuwać konta."
   6.187  
   6.188 -#: contrib/auth/models.py:134
   6.189 +#: contrib/auth/models.py:135
   6.190  msgid "superuser status"
   6.191  msgstr "status administratora"
   6.192  
   6.193 -#: contrib/auth/models.py:134
   6.194 +#: contrib/auth/models.py:135
   6.195  msgid ""
   6.196  "Designates that this user has all permissions without explicitly assigning "
   6.197  "them."
   6.198 @@ -1385,15 +1385,15 @@
   6.199  "Oznacza, że ten użytkownik ma wszystkie uprawnienia bez jawnego "
   6.200  "przypisywania ich."
   6.201  
   6.202 -#: contrib/auth/models.py:135
   6.203 +#: contrib/auth/models.py:136
   6.204  msgid "last login"
   6.205  msgstr "ostatnio zalogowany"
   6.206  
   6.207 -#: contrib/auth/models.py:136
   6.208 +#: contrib/auth/models.py:137
   6.209  msgid "date joined"
   6.210  msgstr "data przyłączenia"
   6.211  
   6.212 -#: contrib/auth/models.py:138
   6.213 +#: contrib/auth/models.py:139
   6.214  msgid ""
   6.215  "In addition to the permissions manually assigned, this user will also get "
   6.216  "all permissions granted to each group he/she is in."
   6.217 @@ -1401,19 +1401,19 @@
   6.218  "Oprócz uprawnień przypisanych bezpośrednio użytkownikowi otrzyma on "
   6.219  "uprawnienia grup, do których należy."
   6.220  
   6.221 -#: contrib/auth/models.py:139
   6.222 +#: contrib/auth/models.py:140
   6.223  msgid "user permissions"
   6.224  msgstr "uprawnienia użytkownika"
   6.225  
   6.226 -#: contrib/auth/models.py:143
   6.227 +#: contrib/auth/models.py:144
   6.228  msgid "user"
   6.229  msgstr "użytkownik"
   6.230  
   6.231 -#: contrib/auth/models.py:144
   6.232 +#: contrib/auth/models.py:145
   6.233  msgid "users"
   6.234  msgstr "użytkownicy"
   6.235  
   6.236 -#: contrib/auth/models.py:300
   6.237 +#: contrib/auth/models.py:301
   6.238  msgid "message"
   6.239  msgstr "wiadomość"
   6.240  
   6.241 @@ -3872,14 +3872,14 @@
   6.242  msgid "Enter a valid time in HH:MM[:ss[.uuuuuu]] format."
   6.243  msgstr "Proszę wpisać poprawną godzinę w formacie HH:MM[:ss[.uuuuuu]]."
   6.244  
   6.245 -#: db/models/fields/related.py:787
   6.246 +#: db/models/fields/related.py:792
   6.247  msgid ""
   6.248  "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
   6.249  msgstr ""
   6.250  "Przytrzymaj wciśnięty klawisz \"Ctrl\" lub \"Command\" na Mac'u aby "
   6.251  "zaznaczyć więcej niż jeden wybór."
   6.252  
   6.253 -#: db/models/fields/related.py:865
   6.254 +#: db/models/fields/related.py:870
   6.255  #, python-format
   6.256  msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
   6.257  msgid_plural ""
   6.258 @@ -3949,11 +3949,11 @@
   6.259  msgid "Ensure that there are no more than %s digits before the decimal point."
   6.260  msgstr "Upewnij się, że jest nie więcej niż %s miejsc przed przecinkiem."
   6.261  
   6.262 -#: forms/fields.py:288 forms/fields.py:850
   6.263 +#: forms/fields.py:288 forms/fields.py:855
   6.264  msgid "Enter a valid date."
   6.265  msgstr "Wpisz poprawną datę."
   6.266  
   6.267 -#: forms/fields.py:322 forms/fields.py:851
   6.268 +#: forms/fields.py:322 forms/fields.py:856
   6.269  msgid "Enter a valid time."
   6.270  msgstr "Wpisz poprawną godzinę."
   6.271  
   6.272 @@ -3973,7 +3973,15 @@
   6.273  msgid "The submitted file is empty."
   6.274  msgstr "Wysłany plik jest pusty."
   6.275  
   6.276 -#: forms/fields.py:478
   6.277 +#: forms/fields.py:450
   6.278 +#, python-format
   6.279 +msgid ""
   6.280 +"Ensure this filename has at most %(max)d characters (it has %(length)d)."
   6.281 +msgstr ""
   6.282 +"Upewnij się, że nazwa tego pliku ma co najwyżej %(max)d znaków (ma długość %"
   6.283 +"(length)d)."
   6.284 +
   6.285 +#: forms/fields.py:483
   6.286  msgid ""
   6.287  "Upload a valid image. The file you uploaded was either not an image or a "
   6.288  "corrupted image."
   6.289 @@ -3981,60 +3989,66 @@
   6.290  "Wgraj poprawny plik graficzny. Ten, który został wgrany, nie jest obrazem, "
   6.291  "albo jest uszkodzony."
   6.292  
   6.293 -#: forms/fields.py:539
   6.294 +#: forms/fields.py:544
   6.295  msgid "Enter a valid URL."
   6.296  msgstr "Wpisz poprawny URL."
   6.297  
   6.298 -#: forms/fields.py:540
   6.299 +#: forms/fields.py:545
   6.300  msgid "This URL appears to be a broken link."
   6.301  msgstr "Ten odnośnik jest nieprawidłowy."
   6.302  
   6.303 -#: forms/fields.py:619 forms/fields.py:697
   6.304 +#: forms/fields.py:624 forms/fields.py:702
   6.305  #, python-format
   6.306  msgid "Select a valid choice. %(value)s is not one of the available choices."
   6.307  msgstr ""
   6.308  "Wybierz poprawną wartość. %(value)s nie jest jednym z dostępnych wyborów."
   6.309  
   6.310 -#: forms/fields.py:698 forms/fields.py:759 forms/models.py:729
   6.311 +#: forms/fields.py:703 forms/fields.py:764 forms/models.py:764
   6.312  msgid "Enter a list of values."
   6.313  msgstr "Podaj listę wartości."
   6.314  
   6.315 -#: forms/fields.py:879
   6.316 +#: forms/fields.py:884
   6.317  msgid "Enter a valid IPv4 address."
   6.318  msgstr "Wprowadź poprawny adres IPv4."
   6.319  
   6.320 -#: forms/fields.py:889
   6.321 +#: forms/fields.py:894
   6.322  msgid ""
   6.323  "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."
   6.324  msgstr "To pole może zawierać jedynie litery, cyfry, podkreślenia i myślniki."
   6.325  
   6.326 -#: forms/formsets.py:247 forms/formsets.py:249
   6.327 +#: forms/formsets.py:272 forms/formsets.py:274
   6.328  msgid "Order"
   6.329  msgstr "Porządek"
   6.330  
   6.331 -#: forms/models.py:289 forms/models.py:298
   6.332 +#: forms/models.py:299 forms/models.py:308
   6.333  #, python-format
   6.334  msgid "%(model_name)s with this %(field_label)s already exists."
   6.335  msgstr "%(field_label)s już istnieje w %(model_name)s."
   6.336  
   6.337 -#: forms/models.py:602
   6.338 +#: forms/models.py:639
   6.339  msgid "The inline foreign key did not match the parent instance primary key."
   6.340  msgstr "Osadzony klucz obcy nie pasuje do klucza głównego obiektu rodzica."
   6.341  
   6.342 -#: forms/models.py:659
   6.343 +#: forms/models.py:694
   6.344  msgid "Select a valid choice. That choice is not one of the available choices."
   6.345  msgstr "Wybierz poprawną wartość. Podana nie jest jednym z dostępnych wyborów."
   6.346  
   6.347 -#: forms/models.py:730
   6.348 +#: forms/models.py:765
   6.349  #, python-format
   6.350  msgid "Select a valid choice. %s is not one of the available choices."
   6.351  msgstr "Wybierz poprawną wartość. %s nie jest jednym z dostępnych wyborów."
   6.352  
   6.353 -#: template/defaultfilters.py:751
   6.354 +#: forms/models.py:767
   6.355 +#, python-format
   6.356 +msgid "\"%s\" is not a valid value for a primary key."
   6.357 +msgstr "\"%s\" nie jest poprawną wartością klucza głównego."
   6.358 +
   6.359 +
   6.360 +#: template/defaultfilters.py:757
   6.361  msgid "yes,no,maybe"
   6.362  msgstr "tak,nie,może"
   6.363  
   6.364 -#: template/defaultfilters.py:782
   6.365 +#: template/defaultfilters.py:788
   6.366  #, python-format
   6.367  msgid "%(size)d byte"
   6.368  msgid_plural "%(size)d bytes"
   6.369 @@ -4042,17 +4056,17 @@
   6.370  msgstr[1] "%(size)d bajty"
   6.371  msgstr[2] "%(size)d bajtów"
   6.372  
   6.373 -#: template/defaultfilters.py:784
   6.374 +#: template/defaultfilters.py:790
   6.375  #, python-format
   6.376  msgid "%.1f KB"
   6.377  msgstr "%.1f KB"
   6.378  
   6.379 -#: template/defaultfilters.py:786
   6.380 +#: template/defaultfilters.py:792
   6.381  #, python-format
   6.382  msgid "%.1f MB"
   6.383  msgstr "%.1f MB"
   6.384  
   6.385 -#: template/defaultfilters.py:787
   6.386 +#: template/defaultfilters.py:793
   6.387  #, python-format
   6.388  msgid "%.1f GB"
   6.389  msgstr "%.1f GB"
   6.390 @@ -4307,16 +4321,16 @@
   6.391  msgstr[1] "minuty"
   6.392  msgstr[2] "minut"
   6.393  
   6.394 -#: utils/timesince.py:43
   6.395 +#: utils/timesince.py:45
   6.396  msgid "minutes"
   6.397  msgstr "minuty"
   6.398  
   6.399 -#: utils/timesince.py:48
   6.400 +#: utils/timesince.py:50
   6.401  #, python-format
   6.402  msgid "%(number)d %(type)s"
   6.403  msgstr "%(number)d %(type)s"
   6.404  
   6.405 -#: utils/timesince.py:54
   6.406 +#: utils/timesince.py:56
   6.407  #, python-format
   6.408  msgid ", %(number)d %(type)s"
   6.409  msgstr ", %(number)d %(type)s"
     7.1 --- a/django/contrib/admin/__init__.py	Sat Mar 28 12:05:48 2009 -0500
     7.2 +++ b/django/contrib/admin/__init__.py	Wed Apr 01 13:05:19 2009 -0500
     7.3 @@ -15,7 +15,7 @@
     7.4      may want.
     7.5      """
     7.6      # Bail out if autodiscover didn't finish loading from a previous call so
     7.7 -    # that we avoid running autodiscover again when the URLConf is loaded by
     7.8 +    # that we avoid running autodiscover again when the URLconf is loaded by
     7.9      # the exception handler to resolve the handler500 view.  This prevents an
    7.10      # admin.py module with errors from re-registering models and raising a
    7.11      # spurious AlreadyRegistered exception (see #8245).
     8.1 --- a/django/contrib/admin/filterspecs.py	Sat Mar 28 12:05:48 2009 -0500
     8.2 +++ b/django/contrib/admin/filterspecs.py	Wed Apr 01 13:05:19 2009 -0500
     8.3 @@ -90,7 +90,7 @@
     8.4          yield {'selected': self.lookup_val is None,
     8.5                 'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
     8.6                 'display': _('All')}
     8.7 -        for k, v in self.field.choices:
     8.8 +        for k, v in self.field.flatchoices:
     8.9              yield {'selected': smart_unicode(k) == self.lookup_val,
    8.10                      'query_string': cl.get_query_string({self.lookup_kwarg: k}),
    8.11                      'display': v}
     9.1 --- a/django/contrib/admin/media/css/changelists.css	Sat Mar 28 12:05:48 2009 -0500
     9.2 +++ b/django/contrib/admin/media/css/changelists.css	Wed Apr 01 13:05:19 2009 -0500
     9.3 @@ -228,11 +228,20 @@
     9.4      border-right: 1px solid #ddd;
     9.5  }
     9.6  
     9.7 +#changelist table input {
     9.8 +    margin: 0;
     9.9 +}
    9.10 +
    9.11 +#changelist table tbody tr.selected {
    9.12 +    background-color: #FFFFCC;
    9.13 +}
    9.14 +
    9.15  #changelist .actions {
    9.16 -    color: #666;
    9.17 +    color: #999;
    9.18      padding: 3px;
    9.19 +    border-top: 1px solid #fff;
    9.20      border-bottom: 1px solid #ddd;
    9.21 -    background: #e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x;
    9.22 +    background: white url(../img/admin/nav-bg-reverse.gif) 0 -10px repeat-x;
    9.23  }
    9.24  
    9.25  #changelist .actions:last-child {
    9.26 @@ -241,15 +250,20 @@
    9.27  
    9.28  #changelist .actions select {
    9.29      border: 1px solid #aaa;
    9.30 -    margin: 0 0.5em;
    9.31 +    margin-left: 0.5em;
    9.32      padding: 1px 2px;
    9.33  }
    9.34  
    9.35  #changelist .actions label {
    9.36      font-size: 11px;
    9.37 -    margin: 0 0.5em;
    9.38 +    margin-left: 0.5em;
    9.39  }
    9.40  
    9.41  #changelist #action-toggle {
    9.42      display: none;
    9.43  }
    9.44 +
    9.45 +#changelist .actions .button {
    9.46 +    font-size: 11px;
    9.47 +    padding: 1px 2px;
    9.48 +}
    10.1 --- a/django/contrib/admin/media/js/actions.js	Sat Mar 28 12:05:48 2009 -0500
    10.2 +++ b/django/contrib/admin/media/js/actions.js	Wed Apr 01 13:05:19 2009 -0500
    10.3 @@ -1,19 +1,37 @@
    10.4  var Actions = {
    10.5      init: function() {
    10.6 -        selectAll = document.getElementById('action-toggle');
    10.7 +        var selectAll = document.getElementById('action-toggle');
    10.8          if (selectAll) {
    10.9              selectAll.style.display = 'inline';
   10.10              addEvent(selectAll, 'click', function() {
   10.11                  Actions.checker(selectAll.checked);
   10.12              });
   10.13          }
   10.14 +        var changelistTable = document.getElementsBySelector('#changelist table')[0];
   10.15 +        addEvent(changelistTable, 'click', function(e) {
   10.16 +            if (!e) { var e = window.event; }
   10.17 +            var target = e.target ? e.target : e.srcElement;
   10.18 +            if (target.nodeType == 3) { target = target.parentNode; }
   10.19 +            if (target.className == 'action-select') {
   10.20 +                var tr = target.parentNode.parentNode;
   10.21 +                Actions.toggleRow(tr, target.checked);
   10.22 +            }
   10.23 +        });
   10.24 +    },
   10.25 +    toggleRow: function(tr, checked) {
   10.26 +        if (checked && tr.className.indexOf('selected') == -1) {
   10.27 +            tr.className += ' selected';
   10.28 +        } else if (!checked) {
   10.29 +            tr.className = tr.className.replace(' selected', '');
   10.30 +        }  
   10.31      },
   10.32      checker: function(checked) {
   10.33 -        actionCheckboxes = document.getElementsBySelector('tr input.action-select');
   10.34 +        var actionCheckboxes = document.getElementsBySelector('tr input.action-select');
   10.35          for(var i = 0; i < actionCheckboxes.length; i++) {
   10.36              actionCheckboxes[i].checked = checked;
   10.37 +            Actions.toggleRow(actionCheckboxes[i].parentNode.parentNode, checked);
   10.38          }
   10.39      }
   10.40 -}
   10.41 +};
   10.42  
   10.43  addEvent(window, 'load', Actions.init);
    11.1 --- a/django/contrib/admin/options.py	Sat Mar 28 12:05:48 2009 -0500
    11.2 +++ b/django/contrib/admin/options.py	Wed Apr 01 13:05:19 2009 -0500
    11.3 @@ -791,7 +791,7 @@
    11.4          opts = model._meta
    11.5  
    11.6          try:
    11.7 -            obj = model._default_manager.get(pk=unquote(object_id))
    11.8 +            obj = self.queryset(request).get(pk=unquote(object_id))
    11.9          except model.DoesNotExist:
   11.10              # Don't raise Http404 just yet, because we haven't checked
   11.11              # permissions yet. We don't want an unauthenticated user to be able
   11.12 @@ -976,7 +976,7 @@
   11.13          app_label = opts.app_label
   11.14  
   11.15          try:
   11.16 -            obj = self.model._default_manager.get(pk=unquote(object_id))
   11.17 +            obj = self.queryset(request).get(pk=unquote(object_id))
   11.18          except self.model.DoesNotExist:
   11.19              # Don't raise Http404 just yet, because we haven't checked
   11.20              # permissions yet. We don't want an unauthenticated user to be able
    12.1 --- a/django/contrib/admin/sites.py	Sat Mar 28 12:05:48 2009 -0500
    12.2 +++ b/django/contrib/admin/sites.py	Wed Apr 01 13:05:19 2009 -0500
    12.3 @@ -24,7 +24,7 @@
    12.4  class AdminSite(object):
    12.5      """
    12.6      An AdminSite object encapsulates an instance of the Django admin application, ready
    12.7 -    to be hooked in to your URLConf. Models are registered with the AdminSite using the
    12.8 +    to be hooked in to your URLconf. Models are registered with the AdminSite using the
    12.9      register() method, and the root() method can then be used as a Django view function
   12.10      that presents a full admin interface for the collection of registered models.
   12.11      """
   12.12 @@ -398,7 +398,8 @@
   12.13              'root_path': self.root_path,
   12.14          }
   12.15          context.update(extra_context or {})
   12.16 -        return render_to_response(self.app_index_template or 'admin/app_index.html', context,
   12.17 +        return render_to_response(self.app_index_template or ('admin/%s/app_index.html' % app_label,
   12.18 +            'admin/app_index.html'), context,
   12.19              context_instance=template.RequestContext(request)
   12.20          )
   12.21  
    13.1 --- a/django/contrib/admin/templates/admin/auth/user/change_password.html	Sat Mar 28 12:05:48 2009 -0500
    13.2 +++ b/django/contrib/admin/templates/admin/auth/user/change_password.html	Wed Apr 01 13:05:19 2009 -0500
    13.3 @@ -8,6 +8,7 @@
    13.4  {% block breadcrumbs %}{% if not is_popup %}
    13.5  <div class="breadcrumbs">
    13.6       <a href="../../../../">{% trans "Home" %}</a> &rsaquo;
    13.7 +     <a href="../../../">{{ opts.app_label|capfirst|escape }}</a> &rsaquo;
    13.8       <a href="../../">{{ opts.verbose_name_plural|capfirst }}</a> &rsaquo;
    13.9       <a href="../">{{ original|truncatewords:"18" }}</a> &rsaquo;
   13.10       {% trans 'Change password' %}
    14.1 --- a/django/contrib/admin/templatetags/admin_list.py	Sat Mar 28 12:05:48 2009 -0500
    14.2 +++ b/django/contrib/admin/templatetags/admin_list.py	Wed Apr 01 13:05:19 2009 -0500
    14.3 @@ -70,7 +70,7 @@
    14.4  
    14.5  def result_headers(cl):
    14.6      lookup_opts = cl.lookup_opts
    14.7 -    
    14.8 +
    14.9      for i, field_name in enumerate(cl.list_display):
   14.10          attr = None
   14.11          try:
   14.12 @@ -97,7 +97,7 @@
   14.13                              raise AttributeError, \
   14.14                                  "'%s' model or '%s' objects have no attribute '%s'" % \
   14.15                                      (lookup_opts.object_name, cl.model_admin.__class__, field_name)
   14.16 -                
   14.17 +
   14.18                  try:
   14.19                      header = attr.short_description
   14.20                  except AttributeError:
   14.21 @@ -205,8 +205,8 @@
   14.22                      result_repr = EMPTY_CHANGELIST_VALUE
   14.23              # Fields with choices are special: Use the representation
   14.24              # of the choice.
   14.25 -            elif f.choices:
   14.26 -                result_repr = dict(f.choices).get(field_val, EMPTY_CHANGELIST_VALUE)
   14.27 +            elif f.flatchoices:
   14.28 +                result_repr = dict(f.flatchoices).get(field_val, EMPTY_CHANGELIST_VALUE)
   14.29              else:
   14.30                  result_repr = escape(field_val)
   14.31          if force_unicode(result_repr) == '':
   14.32 @@ -237,7 +237,7 @@
   14.33                  result_repr = conditional_escape(result_repr)
   14.34              yield mark_safe(u'<td%s>%s</td>' % (row_class, result_repr))
   14.35      if form:
   14.36 -        yield mark_safe(force_unicode(form[cl.model._meta.pk.attname]))
   14.37 +        yield mark_safe(force_unicode(form[cl.model._meta.pk.name]))
   14.38  
   14.39  def results(cl):
   14.40      if cl.formset:
    15.1 --- a/django/contrib/admin/validation.py	Sat Mar 28 12:05:48 2009 -0500
    15.2 +++ b/django/contrib/admin/validation.py	Wed Apr 01 13:05:19 2009 -0500
    15.3 @@ -76,7 +76,7 @@
    15.4                  field = opts.get_field_by_name(field_name)[0]
    15.5              except models.FieldDoesNotExist:
    15.6                  raise ImproperlyConfigured("'%s.list_editable[%d]' refers to a "
    15.7 -                    "field, '%s', not defiend on %s."
    15.8 +                    "field, '%s', not defined on %s."
    15.9                      % (cls.__name__, idx, field_name, model.__name__))
   15.10              if field_name not in cls.list_display:
   15.11                  raise ImproperlyConfigured("'%s.list_editable[%d]' refers to "
    16.1 --- a/django/contrib/admin/widgets.py	Sat Mar 28 12:05:48 2009 -0500
    16.2 +++ b/django/contrib/admin/widgets.py	Wed Apr 01 13:05:19 2009 -0500
    16.3 @@ -12,6 +12,7 @@
    16.4  from django.utils.safestring import mark_safe
    16.5  from django.utils.encoding import force_unicode
    16.6  from django.conf import settings
    16.7 +from django.core.urlresolvers import reverse, NoReverseMatch
    16.8  
    16.9  class FilteredSelectMultiple(forms.SelectMultiple):
   16.10      """
   16.11 @@ -219,13 +220,18 @@
   16.12  
   16.13      def render(self, name, value, *args, **kwargs):
   16.14          rel_to = self.rel.to
   16.15 -        related_url = '../../../%s/%s/' % (rel_to._meta.app_label, rel_to._meta.object_name.lower())
   16.16 +        info = (rel_to._meta.app_label, rel_to._meta.object_name.lower())
   16.17 +        try:
   16.18 +            related_info = (self.admin_site.name,) + info
   16.19 +            related_url = reverse('%sadmin_%s_%s_add' % related_info)
   16.20 +        except NoReverseMatch:
   16.21 +            related_url = '../../../%s/%s/add/' % info
   16.22          self.widget.choices = self.choices
   16.23          output = [self.widget.render(name, value, *args, **kwargs)]
   16.24          if rel_to in self.admin_site._registry: # If the related object has an admin interface:
   16.25              # TODO: "id_" is hard-coded here. This should instead use the correct
   16.26              # API to determine the ID dynamically.
   16.27 -            output.append(u'<a href="%sadd/" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
   16.28 +            output.append(u'<a href="%s" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
   16.29                  (related_url, name))
   16.30              output.append(u'<img src="%simg/admin/icon_addlink.gif" width="10" height="10" alt="%s"/></a>' % (settings.ADMIN_MEDIA_PREFIX, _('Add Another')))
   16.31          return mark_safe(u''.join(output))
    17.1 --- a/django/contrib/admindocs/views.py	Sat Mar 28 12:05:48 2009 -0500
    17.2 +++ b/django/contrib/admindocs/views.py	Wed Apr 01 13:05:19 2009 -0500
    17.3 @@ -264,7 +264,7 @@
    17.4          else:
    17.5              site_obj = GenericSite()
    17.6          for dir in settings_mod.TEMPLATE_DIRS:
    17.7 -            template_file = os.path.join(dir, "%s.html" % template)
    17.8 +            template_file = os.path.join(dir, template)
    17.9              templates.append({
   17.10                  'file': template_file,
   17.11                  'exists': os.path.exists(template_file),
    18.1 --- a/django/contrib/auth/admin.py	Sat Mar 28 12:05:48 2009 -0500
    18.2 +++ b/django/contrib/auth/admin.py	Wed Apr 01 13:05:19 2009 -0500
    18.3 @@ -27,7 +27,7 @@
    18.4      add_form = UserCreationForm
    18.5      change_password_form = AdminPasswordChangeForm
    18.6      list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
    18.7 -    list_filter = ('is_staff', 'is_superuser')
    18.8 +    list_filter = ('is_staff', 'is_superuser', 'is_active')
    18.9      search_fields = ('username', 'first_name', 'last_name', 'email')
   18.10      ordering = ('username',)
   18.11      filter_horizontal = ('user_permissions',)
    19.1 --- a/django/contrib/auth/decorators.py	Sat Mar 28 12:05:48 2009 -0500
    19.2 +++ b/django/contrib/auth/decorators.py	Wed Apr 01 13:05:19 2009 -0500
    19.3 @@ -56,8 +56,19 @@
    19.4          self.test_func = test_func
    19.5          self.login_url = login_url
    19.6          self.redirect_field_name = redirect_field_name
    19.7 -        update_wrapper(self, view_func)
    19.8          
    19.9 +        # We can't blindly apply update_wrapper because it udpates __dict__ and 
   19.10 +        # if the view function is already a _CheckLogin object then 
   19.11 +        # self.test_func and friends will get stomped. However, we also can't 
   19.12 +        # *not* update the wrapper's dict because then view function attributes
   19.13 +        # don't get updated into the wrapper. So we need to split the
   19.14 +        # difference: don't let update_wrapper update __dict__, but then update
   19.15 +        # the (parts of) __dict__ that we care about ourselves.
   19.16 +        update_wrapper(self, view_func, updated=())
   19.17 +        for k in view_func.__dict__:
   19.18 +            if k not in self.__dict__:
   19.19 +                self.__dict__[k] = view_func.__dict__[k]
   19.20 +
   19.21      def __get__(self, obj, cls=None):
   19.22          view_func = self.view_func.__get__(obj, cls)
   19.23          return _CheckLogin(view_func, self.test_func, self.login_url, self.redirect_field_name)
    20.1 --- a/django/contrib/auth/models.py	Sat Mar 28 12:05:48 2009 -0500
    20.2 +++ b/django/contrib/auth/models.py	Wed Apr 01 13:05:19 2009 -0500
    20.3 @@ -111,6 +111,7 @@
    20.4          u.is_active = True
    20.5          u.is_superuser = True
    20.6          u.save()
    20.7 +        return u
    20.8  
    20.9      def make_random_password(self, length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'):
   20.10          "Generates a random password with the given length and given allowed_chars"
    21.1 --- a/django/contrib/auth/tests/__init__.py	Sat Mar 28 12:05:48 2009 -0500
    21.2 +++ b/django/contrib/auth/tests/__init__.py	Wed Apr 01 13:05:19 2009 -0500
    21.3 @@ -1,6 +1,6 @@
    21.4  from django.contrib.auth.tests.basic import BASIC_TESTS
    21.5  from django.contrib.auth.tests.views \
    21.6 -        import PasswordResetTest, ChangePasswordTest
    21.7 +        import PasswordResetTest, ChangePasswordTest, LoginTest, LogoutTest
    21.8  from django.contrib.auth.tests.forms import FORM_TESTS
    21.9  from django.contrib.auth.tests.remote_user \
   21.10          import RemoteUserTest, RemoteUserNoCreateTest, RemoteUserCustomTest
   21.11 @@ -14,4 +14,6 @@
   21.12      'FORM_TESTS': FORM_TESTS,
   21.13      'TOKEN_GENERATOR_TESTS': TOKEN_GENERATOR_TESTS,
   21.14      'CHANGEPASSWORD_TESTS': ChangePasswordTest,
   21.15 +    'LOGIN_TESTS': LoginTest,
   21.16 +    'LOGOUT_TESTS': LogoutTest,
   21.17  }
    22.1 --- a/django/contrib/auth/tests/basic.py	Sat Mar 28 12:05:48 2009 -0500
    22.2 +++ b/django/contrib/auth/tests/basic.py	Wed Apr 01 13:05:19 2009 -0500
    22.3 @@ -24,6 +24,8 @@
    22.4  False
    22.5  >>> u.is_active
    22.6  True
    22.7 +>>> u.is_superuser
    22.8 +False
    22.9  
   22.10  >>> a = AnonymousUser()
   22.11  >>> a.is_authenticated()
   22.12 @@ -32,11 +34,22 @@
   22.13  False
   22.14  >>> a.is_active
   22.15  False
   22.16 +>>> a.is_superuser
   22.17 +False
   22.18  >>> a.groups.all()
   22.19  []
   22.20  >>> a.user_permissions.all()
   22.21  []
   22.22  
   22.23 +# superuser tests.
   22.24 +>>> super = User.objects.create_superuser('super', 'super@example.com', 'super')
   22.25 +>>> super.is_superuser
   22.26 +True
   22.27 +>>> super.is_active
   22.28 +True
   22.29 +>>> super.is_staff
   22.30 +True
   22.31 +
   22.32  #
   22.33  # Tests for createsuperuser management command.
   22.34  # It's nearly impossible to test the interactive mode -- a command test helper
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/django/contrib/auth/tests/urls.py	Wed Apr 01 13:05:19 2009 -0500
    23.3 @@ -0,0 +1,9 @@
    23.4 +from django.conf.urls.defaults import patterns
    23.5 +from django.contrib.auth.urls import urlpatterns
    23.6 +
    23.7 +# special urls for auth test cases
    23.8 +urlpatterns += patterns('',
    23.9 +    (r'^logout/custom_query/$', 'django.contrib.auth.views.logout', dict(redirect_field_name='follow')),
   23.10 +    (r'^logout/next_page/$', 'django.contrib.auth.views.logout', dict(next_page='/somewhere/')),
   23.11 +)
   23.12 +
    24.1 --- a/django/contrib/auth/tests/views.py	Sat Mar 28 12:05:48 2009 -0500
    24.2 +++ b/django/contrib/auth/tests/views.py	Wed Apr 01 13:05:19 2009 -0500
    24.3 @@ -1,11 +1,14 @@
    24.4 -
    24.5  import os
    24.6  import re
    24.7  
    24.8  from django.conf import settings
    24.9 +from django.contrib.auth import SESSION_KEY
   24.10 +from django.contrib.auth.forms import AuthenticationForm
   24.11 +from django.contrib.sites.models import Site, RequestSite
   24.12  from django.contrib.auth.models import User
   24.13  from django.test import TestCase
   24.14  from django.core import mail
   24.15 +from django.core.urlresolvers import reverse
   24.16  
   24.17  class PasswordResetTest(TestCase):
   24.18      fixtures = ['authtestdata.json']
   24.19 @@ -47,8 +50,8 @@
   24.20  
   24.21      def test_confirm_invalid(self):
   24.22          url, path = self._test_confirm_start()
   24.23 -        # Lets munge the token in the path, but keep the same length,
   24.24 -        # in case the URL conf will reject a different length
   24.25 +        # Let's munge the token in the path, but keep the same length,
   24.26 +        # in case the URLconf will reject a different length.
   24.27          path = path[:-5] + ("0"*4) + path[-1]
   24.28  
   24.29          response = self.client.get(path)
   24.30 @@ -162,3 +165,71 @@
   24.31          self.fail_login()
   24.32          self.login(password='password1')
   24.33  
   24.34 +class LoginTest(TestCase):
   24.35 +    fixtures = ['authtestdata.json']
   24.36 +    urls = 'django.contrib.auth.urls'
   24.37 +
   24.38 +    def setUp(self):
   24.39 +        self.old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS
   24.40 +        settings.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), 'templates'),)
   24.41 +
   24.42 +    def tearDown(self):
   24.43 +        settings.TEMPLATE_DIRS = self.old_TEMPLATE_DIRS
   24.44 +
   24.45 +    def test_current_site_in_context_after_login(self):
   24.46 +        response = self.client.get(reverse('django.contrib.auth.views.login'))
   24.47 +        self.assertEquals(response.status_code, 200)
   24.48 +        site = Site.objects.get_current()
   24.49 +        self.assertEquals(response.context['site'], site)
   24.50 +        self.assertEquals(response.context['site_name'], site.name)
   24.51 +        self.assert_(isinstance(response.context['form'], AuthenticationForm), 
   24.52 +                     'Login form is not an AuthenticationForm')
   24.53 +        
   24.54 +class LogoutTest(TestCase):
   24.55 +    fixtures = ['authtestdata.json']
   24.56 +    urls = 'django.contrib.auth.tests.urls'
   24.57 +
   24.58 +    def login(self, password='password'):
   24.59 +        response = self.client.post('/login/', {
   24.60 +            'username': 'testclient',
   24.61 +            'password': password
   24.62 +            }
   24.63 +        )
   24.64 +        self.assertEquals(response.status_code, 302)
   24.65 +        self.assert_(response['Location'].endswith(settings.LOGIN_REDIRECT_URL))
   24.66 +        self.assert_(SESSION_KEY in self.client.session)
   24.67 +
   24.68 +    def confirm_logged_out(self):
   24.69 +        self.assert_(SESSION_KEY not in self.client.session)
   24.70 +
   24.71 +    def test_logout_default(self):
   24.72 +        "Logout without next_page option renders the default template"
   24.73 +        self.login()
   24.74 +        response = self.client.get('/logout/')
   24.75 +        self.assertEquals(200, response.status_code)
   24.76 +        self.assert_('Logged out' in response.content)
   24.77 +        self.confirm_logged_out()
   24.78 +
   24.79 +    def test_logout_with_next_page_specified(self): 
   24.80 +        "Logout with next_page option given redirects to specified resource"
   24.81 +        self.login()
   24.82 +        response = self.client.get('/logout/next_page/')
   24.83 +        self.assertEqual(response.status_code, 302)
   24.84 +        self.assert_(response['Location'].endswith('/somewhere/'))
   24.85 +        self.confirm_logged_out()
   24.86 +
   24.87 +    def test_logout_with_redirect_argument(self):
   24.88 +        "Logout with query string redirects to specified resource"
   24.89 +        self.login()
   24.90 +        response = self.client.get('/logout/?next=/login/')
   24.91 +        self.assertEqual(response.status_code, 302)
   24.92 +        self.assert_(response['Location'].endswith('/login/'))
   24.93 +        self.confirm_logged_out()
   24.94 +
   24.95 +    def test_logout_with_custom_redirect_argument(self):
   24.96 +        "Logout with custom query string redirects to specified resource"
   24.97 +        self.login()
   24.98 +        response = self.client.get('/logout/custom_query/?follow=/somewhere/')
   24.99 +        self.assertEqual(response.status_code, 302)
  24.100 +        self.assert_(response['Location'].endswith('/somewhere/'))
  24.101 +        self.confirm_logged_out()
  24.102 \ No newline at end of file
    25.1 --- a/django/contrib/auth/views.py	Sat Mar 28 12:05:48 2009 -0500
    25.2 +++ b/django/contrib/auth/views.py	Wed Apr 01 13:05:19 2009 -0500
    25.3 @@ -38,16 +38,23 @@
    25.4      return render_to_response(template_name, {
    25.5          'form': form,
    25.6          redirect_field_name: redirect_to,
    25.7 +        'site': current_site,
    25.8          'site_name': current_site.name,
    25.9      }, context_instance=RequestContext(request))
   25.10  login = never_cache(login)
   25.11  
   25.12 -def logout(request, next_page=None, template_name='registration/logged_out.html'):
   25.13 +def logout(request, next_page=None, template_name='registration/logged_out.html', redirect_field_name=REDIRECT_FIELD_NAME):
   25.14      "Logs out the user and displays 'You are logged out' message."
   25.15      from django.contrib.auth import logout
   25.16      logout(request)
   25.17      if next_page is None:
   25.18 -        return render_to_response(template_name, {'title': _('Logged out')}, context_instance=RequestContext(request))
   25.19 +        redirect_to = request.REQUEST.get(redirect_field_name, '')
   25.20 +        if redirect_to:
   25.21 +            return HttpResponseRedirect(redirect_to)
   25.22 +        else:
   25.23 +            return render_to_response(template_name, {
   25.24 +                'title': _('Logged out')
   25.25 +            }, context_instance=RequestContext(request))
   25.26      else:
   25.27          # Redirect to this page until the session has been cleared.
   25.28          return HttpResponseRedirect(next_page or request.path)
    26.1 --- a/django/contrib/contenttypes/generic.py	Sat Mar 28 12:05:48 2009 -0500
    26.2 +++ b/django/contrib/contenttypes/generic.py	Wed Apr 01 13:05:19 2009 -0500
    26.3 @@ -253,6 +253,8 @@
    26.4  
    26.5          def add(self, *objs):
    26.6              for obj in objs:
    26.7 +                if not isinstance(obj, self.model):
    26.8 +                    raise TypeError, "'%s' instance expected" % self.model._meta.object_name
    26.9                  setattr(obj, self.content_type_field_name, self.content_type)
   26.10                  setattr(obj, self.object_id_field_name, self.pk_val)
   26.11                  obj.save()
    27.1 --- a/django/contrib/formtools/test_urls.py	Sat Mar 28 12:05:48 2009 -0500
    27.2 +++ b/django/contrib/formtools/test_urls.py	Wed Apr 01 13:05:19 2009 -0500
    27.3 @@ -1,9 +1,7 @@
    27.4 +"""
    27.5 +This is a URLconf to be loaded by tests.py. Add any URLs needed for tests only.
    27.6  """
    27.7  
    27.8 -This is a urlconf to be loaded by tests.py. Add any urls needed
    27.9 -for tests only.
   27.10 -
   27.11 -"""
   27.12  from django.conf.urls.defaults import *
   27.13  from django.contrib.formtools.tests import *
   27.14  
    28.1 --- a/django/contrib/gis/admin/widgets.py	Sat Mar 28 12:05:48 2009 -0500
    28.2 +++ b/django/contrib/gis/admin/widgets.py	Wed Apr 01 13:05:19 2009 -0500
    28.3 @@ -21,7 +21,7 @@
    28.4  
    28.5          # Defaulting the WKT value to a blank string -- this
    28.6          # will be tested in the JavaScript and the appropriate
    28.7 -        # interfaace will be constructed.
    28.8 +        # interface will be constructed.
    28.9          self.params['wkt'] = ''
   28.10  
   28.11          # If a string reaches here (via a validation error on another
   28.12 @@ -46,7 +46,7 @@
   28.13              # Transforming the geometry to the projection used on the
   28.14              # OpenLayers map.
   28.15              srid = self.params['srid']
   28.16 -            if value.srid != srid: 
   28.17 +            if value.srid != srid:
   28.18                  try:
   28.19                      ogr = value.ogr
   28.20                      ogr.transform(srid)
   28.21 @@ -55,14 +55,14 @@
   28.22                      wkt = ''
   28.23              else:
   28.24                  wkt = value.wkt
   28.25 -               
   28.26 +
   28.27              # Setting the parameter WKT with that of the transformed
   28.28              # geometry.
   28.29              self.params['wkt'] = wkt
   28.30  
   28.31          return loader.render_to_string(self.template, self.params,
   28.32                                         context_instance=geo_context)
   28.33 -    
   28.34 +
   28.35      def map_options(self):
   28.36          "Builds the map options hash for the OpenLayers template."
   28.37  
   28.38 @@ -74,8 +74,8 @@
   28.39  
   28.40          # An array of the parameter name, the name of their OpenLayers
   28.41          # counterpart, and the type of variable they are.
   28.42 -        map_types = [('srid', 'projection', 'srid'), 
   28.43 -                     ('display_srid', 'displayProjection', 'srid'), 
   28.44 +        map_types = [('srid', 'projection', 'srid'),
   28.45 +                     ('display_srid', 'displayProjection', 'srid'),
   28.46                       ('units', 'units', str),
   28.47                       ('max_resolution', 'maxResolution', float),
   28.48                       ('max_extent', 'maxExtent', 'bounds'),
    29.1 --- a/django/contrib/gis/db/backend/mysql/field.py	Sat Mar 28 12:05:48 2009 -0500
    29.2 +++ b/django/contrib/gis/db/backend/mysql/field.py	Wed Apr 01 13:05:19 2009 -0500
    29.3 @@ -13,20 +13,20 @@
    29.4      def _geom_index(self, style, db_table):
    29.5          """
    29.6          Creates a spatial index for the geometry column.  If MyISAM tables are
    29.7 -        used an R-Tree index is created, otherwise a B-Tree index is created. 
    29.8 +        used an R-Tree index is created, otherwise a B-Tree index is created.
    29.9          Thus, for best spatial performance, you should use MyISAM tables
   29.10 -        (which do not support transactions).  For more information, see Ch. 
   29.11 +        (which do not support transactions).  For more information, see Ch.
   29.12          16.6.1 of the MySQL 5.0 documentation.
   29.13          """
   29.14  
   29.15          # Getting the index name.
   29.16          idx_name = '%s_%s_id' % (db_table, self.column)
   29.17 -        
   29.18 -        sql = style.SQL_KEYWORD('CREATE SPATIAL INDEX ') + \
   29.19 -              style.SQL_TABLE(qn(idx_name)) + \
   29.20 -              style.SQL_KEYWORD(' ON ') + \
   29.21 -              style.SQL_TABLE(qn(db_table)) + '(' + \
   29.22 -              style.SQL_FIELD(qn(self.column)) + ');'
   29.23 +
   29.24 +        sql = (style.SQL_KEYWORD('CREATE SPATIAL INDEX ') +
   29.25 +               style.SQL_TABLE(qn(idx_name)) +
   29.26 +               style.SQL_KEYWORD(' ON ') +
   29.27 +               style.SQL_TABLE(qn(db_table)) + '(' +
   29.28 +               style.SQL_FIELD(qn(self.column)) + ');')
   29.29          return sql
   29.30  
   29.31      def post_create_sql(self, style, db_table):
   29.32 @@ -46,8 +46,8 @@
   29.33  
   29.34      def get_placeholder(self, value):
   29.35          """
   29.36 -        The placeholder here has to include MySQL's WKT constructor.  Because 
   29.37 -        MySQL does not support spatial transformations, there is no need to 
   29.38 +        The placeholder here has to include MySQL's WKT constructor.  Because
   29.39 +        MySQL does not support spatial transformations, there is no need to
   29.40          modify the placeholder based on the contents of the given value.
   29.41          """
   29.42          return '%s(%%s)' % GEOM_FROM_TEXT
    30.1 --- a/django/contrib/gis/db/backend/oracle/field.py	Sat Mar 28 12:05:48 2009 -0500
    30.2 +++ b/django/contrib/gis/db/backend/oracle/field.py	Wed Apr 01 13:05:19 2009 -0500
    30.3 @@ -39,18 +39,18 @@
    30.4  
    30.5          # Constructing the SQL that will be used to insert information about
    30.6          # the geometry column into the USER_GSDO_GEOM_METADATA table.
    30.7 -        meta_sql = style.SQL_KEYWORD('INSERT INTO ') + \
    30.8 -                   style.SQL_TABLE('USER_SDO_GEOM_METADATA') + \
    30.9 -                   ' (%s, %s, %s, %s)\n  ' % tuple(map(qn, ['TABLE_NAME', 'COLUMN_NAME', 'DIMINFO', 'SRID'])) + \
   30.10 -                   style.SQL_KEYWORD(' VALUES ') + '(\n    ' + \
   30.11 -                   style.SQL_TABLE(gqn(db_table)) + ',\n    ' + \
   30.12 -                   style.SQL_FIELD(gqn(self.column)) + ',\n    ' + \
   30.13 -                   style.SQL_KEYWORD("MDSYS.SDO_DIM_ARRAY") + '(\n      ' + \
   30.14 -                   style.SQL_KEYWORD("MDSYS.SDO_DIM_ELEMENT") + \
   30.15 -                   ("('LONG', %s, %s, %s),\n      " % (self._extent[0], self._extent[2], self._tolerance)) + \
   30.16 -                   style.SQL_KEYWORD("MDSYS.SDO_DIM_ELEMENT") + \
   30.17 -                   ("('LAT', %s, %s, %s)\n    ),\n" % (self._extent[1], self._extent[3], self._tolerance)) + \
   30.18 -                   '    %s\n  );' % self.srid
   30.19 +        meta_sql = (style.SQL_KEYWORD('INSERT INTO ') +
   30.20 +                    style.SQL_TABLE('USER_SDO_GEOM_METADATA') +
   30.21 +                    ' (%s, %s, %s, %s)\n  ' % tuple(map(qn, ['TABLE_NAME', 'COLUMN_NAME', 'DIMINFO', 'SRID'])) +
   30.22 +                    style.SQL_KEYWORD(' VALUES ') + '(\n    ' +
   30.23 +                    style.SQL_TABLE(gqn(db_table)) + ',\n    ' +
   30.24 +                    style.SQL_FIELD(gqn(self.column)) + ',\n    ' +
   30.25 +                    style.SQL_KEYWORD("MDSYS.SDO_DIM_ARRAY") + '(\n      ' +
   30.26 +                    style.SQL_KEYWORD("MDSYS.SDO_DIM_ELEMENT") +
   30.27 +                    ("('LONG', %s, %s, %s),\n      " % (self._extent[0], self._extent[2], self._tolerance)) +
   30.28 +                    style.SQL_KEYWORD("MDSYS.SDO_DIM_ELEMENT") +
   30.29 +                    ("('LAT', %s, %s, %s)\n    ),\n" % (self._extent[1], self._extent[3], self._tolerance)) +
   30.30 +                    '    %s\n  );' % self.srid)
   30.31          return meta_sql
   30.32  
   30.33      def _geom_index(self, style, db_table):
   30.34 @@ -59,14 +59,14 @@
   30.35          # Getting the index name, Oracle doesn't allow object
   30.36          # names > 30 characters.
   30.37          idx_name = truncate_name('%s_%s_id' % (db_table, self.column), 30)
   30.38 -        
   30.39 -        sql = style.SQL_KEYWORD('CREATE INDEX ') + \
   30.40 -              style.SQL_TABLE(qn(idx_name)) + \
   30.41 -              style.SQL_KEYWORD(' ON ') + \
   30.42 -              style.SQL_TABLE(qn(db_table)) + '(' + \
   30.43 -              style.SQL_FIELD(qn(self.column)) + ') ' + \
   30.44 -              style.SQL_KEYWORD('INDEXTYPE IS ') + \
   30.45 -              style.SQL_TABLE('MDSYS.SPATIAL_INDEX') + ';'
   30.46 +
   30.47 +        sql = (style.SQL_KEYWORD('CREATE INDEX ') +
   30.48 +               style.SQL_TABLE(qn(idx_name)) +
   30.49 +               style.SQL_KEYWORD(' ON ') +
   30.50 +               style.SQL_TABLE(qn(db_table)) + '(' +
   30.51 +               style.SQL_FIELD(qn(self.column)) + ') ' +
   30.52 +               style.SQL_KEYWORD('INDEXTYPE IS ') +
   30.53 +               style.SQL_TABLE('MDSYS.SPATIAL_INDEX') + ';')
   30.54          return sql
   30.55  
   30.56      def post_create_sql(self, style, db_table):
   30.57 @@ -86,7 +86,7 @@
   30.58      def db_type(self):
   30.59          "The Oracle geometric data type is MDSYS.SDO_GEOMETRY."
   30.60          return 'MDSYS.SDO_GEOMETRY'
   30.61 -        
   30.62 +
   30.63      def get_placeholder(self, value):
   30.64          """
   30.65          Provides a proper substitution value for Geometries that are not in the
    31.1 --- a/django/contrib/gis/db/backend/postgis/field.py	Sat Mar 28 12:05:48 2009 -0500
    31.2 +++ b/django/contrib/gis/db/backend/postgis/field.py	Wed Apr 01 13:05:19 2009 -0500
    31.3 @@ -19,35 +19,35 @@
    31.4          Takes the style object (provides syntax highlighting) and the
    31.5          database table as parameters.
    31.6          """
    31.7 -        sql = style.SQL_KEYWORD('SELECT ') + \
    31.8 -              style.SQL_TABLE('AddGeometryColumn') + '(' + \
    31.9 -              style.SQL_TABLE(gqn(db_table)) + ', ' + \
   31.10 -              style.SQL_FIELD(gqn(self.column)) + ', ' + \
   31.11 -              style.SQL_FIELD(str(self.srid)) + ', ' + \
   31.12 -              style.SQL_COLTYPE(gqn(self.geom_type)) + ', ' + \
   31.13 -              style.SQL_KEYWORD(str(self.dim)) + ');'
   31.14 +        sql = (style.SQL_KEYWORD('SELECT ') +
   31.15 +               style.SQL_TABLE('AddGeometryColumn') + '(' +
   31.16 +               style.SQL_TABLE(gqn(db_table)) + ', ' +
   31.17 +               style.SQL_FIELD(gqn(self.column)) + ', ' +
   31.18 +               style.SQL_FIELD(str(self.srid)) + ', ' +
   31.19 +               style.SQL_COLTYPE(gqn(self.geom_type)) + ', ' +
   31.20 +               style.SQL_KEYWORD(str(self.dim)) + ');')
   31.21  
   31.22          if not self.null:
   31.23              # Add a NOT NULL constraint to the field
   31.24 -            sql += '\n' + \
   31.25 -                   style.SQL_KEYWORD('ALTER TABLE ') + \
   31.26 -                   style.SQL_TABLE(qn(db_table)) + \
   31.27 -                   style.SQL_KEYWORD(' ALTER ') + \
   31.28 -                   style.SQL_FIELD(qn(self.column)) + \
   31.29 -                   style.SQL_KEYWORD(' SET NOT NULL') + ';'
   31.30 +            sql += ('\n' +
   31.31 +                    style.SQL_KEYWORD('ALTER TABLE ') +
   31.32 +                    style.SQL_TABLE(qn(db_table)) +
   31.33 +                    style.SQL_KEYWORD(' ALTER ') +
   31.34 +                    style.SQL_FIELD(qn(self.column)) +
   31.35 +                    style.SQL_KEYWORD(' SET NOT NULL') + ';')
   31.36          return sql
   31.37 -    
   31.38 +
   31.39      def _geom_index(self, style, db_table,
   31.40                      index_type='GIST', index_opts='GIST_GEOMETRY_OPS'):
   31.41          "Creates a GiST index for this geometry field."
   31.42 -        sql = style.SQL_KEYWORD('CREATE INDEX ') + \
   31.43 -              style.SQL_TABLE(qn('%s_%s_id' % (db_table, self.column))) + \
   31.44 -              style.SQL_KEYWORD(' ON ') + \
   31.45 -              style.SQL_TABLE(qn(db_table)) + \
   31.46 -              style.SQL_KEYWORD(' USING ') + \
   31.47 -              style.SQL_COLTYPE(index_type) + ' ( ' + \
   31.48 -              style.SQL_FIELD(qn(self.column)) + ' ' + \
   31.49 -              style.SQL_KEYWORD(index_opts) + ' );'
   31.50 +        sql = (style.SQL_KEYWORD('CREATE INDEX ') +
   31.51 +              style.SQL_TABLE(qn('%s_%s_id' % (db_table, self.column))) +
   31.52 +              style.SQL_KEYWORD(' ON ') +
   31.53 +              style.SQL_TABLE(qn(db_table)) +
   31.54 +              style.SQL_KEYWORD(' USING ') +
   31.55 +              style.SQL_COLTYPE(index_type) + ' ( ' +
   31.56 +              style.SQL_FIELD(qn(self.column)) + ' ' +
   31.57 +              style.SQL_KEYWORD(index_opts) + ' );')
   31.58          return sql
   31.59  
   31.60      def post_create_sql(self, style, db_table):
   31.61 @@ -69,10 +69,10 @@
   31.62  
   31.63      def _post_delete_sql(self, style, db_table):
   31.64          "Drops the geometry column."
   31.65 -        sql = style.SQL_KEYWORD('SELECT ') + \
   31.66 -            style.SQL_KEYWORD('DropGeometryColumn') + '(' + \
   31.67 -            style.SQL_TABLE(gqn(db_table)) + ', ' + \
   31.68 -            style.SQL_FIELD(gqn(self.column)) +  ');'
   31.69 +        sql = (style.SQL_KEYWORD('SELECT ') +
   31.70 +               style.SQL_KEYWORD('DropGeometryColumn') + '(' +
   31.71 +               style.SQL_TABLE(gqn(db_table)) + ', ' +
   31.72 +               style.SQL_FIELD(gqn(self.column)) +  ');')
   31.73          return sql
   31.74  
   31.75      def db_type(self):
    32.1 --- a/django/contrib/gis/db/backend/spatialite/__init__.py	Sat Mar 28 12:05:48 2009 -0500
    32.2 +++ b/django/contrib/gis/db/backend/spatialite/__init__.py	Wed Apr 01 13:05:19 2009 -0500
    32.3 @@ -4,21 +4,30 @@
    32.4  from django.conf import settings
    32.5  from django.db.backends.signals import connection_created
    32.6  
    32.7 -from django.contrib.gis.db.backend.adaptor import WKTAdaptor
    32.8  from django.contrib.gis.db.backend.base import BaseSpatialBackend
    32.9 +from django.contrib.gis.db.backend.spatialite.adaptor import SpatiaLiteAdaptor
   32.10  from django.contrib.gis.db.backend.spatialite.creation import create_test_spatial_db
   32.11  from django.contrib.gis.db.backend.spatialite.field import SpatiaLiteField
   32.12  from django.contrib.gis.db.backend.spatialite.models import GeometryColumns, SpatialRefSys
   32.13  from django.contrib.gis.db.backend.spatialite.query import *
   32.14  
   32.15 +# Here we are figuring out the path to the SpatiLite library (`libspatialite`).
   32.16 +# If it's not in the system PATH, it may be set manually in the settings via
   32.17 +# the `SPATIALITE_LIBRARY_PATH` setting.
   32.18  spatialite_lib = getattr(settings, 'SPATIALITE_LIBRARY_PATH', find_library('spatialite'))
   32.19  if spatialite_lib:
   32.20      def initialize_spatialite(sender=None, **kwargs):
   32.21 +        """
   32.22 +        This function initializes the pysqlite2 connection to enable the
   32.23 +        loading of extensions, and to load up the SpatiaLite library
   32.24 +        extension.
   32.25 +        """
   32.26          from django.db import connection
   32.27          connection.connection.enable_load_extension(True)
   32.28 -        connection.cursor().execute("select load_extension(%s)", (spatialite_lib,))
   32.29 +        connection.cursor().execute("SELECT load_extension(%s)", (spatialite_lib,))
   32.30      connection_created.connect(initialize_spatialite)
   32.31  else:
   32.32 +    # No SpatiaLite library found.
   32.33      raise Exception('Unable to locate SpatiaLite, needed to use GeoDjango with sqlite3.')
   32.34  
   32.35  SpatialBackend = BaseSpatialBackend(name='spatialite', spatialite=True,
   32.36 @@ -43,7 +52,7 @@
   32.37                                      translate=TRANSLATE,
   32.38                                      union=UNION,
   32.39                                      unionagg=UNIONAGG,
   32.40 -                                    Adaptor=WKTAdaptor,
   32.41 +                                    Adaptor=SpatiaLiteAdaptor,
   32.42                                      Field=SpatiaLiteField,
   32.43                                      GeometryColumns=GeometryColumns,
   32.44                                      SpatialRefSys=SpatialRefSys,
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/django/contrib/gis/db/backend/spatialite/adaptor.py	Wed Apr 01 13:05:19 2009 -0500
    33.3 @@ -0,0 +1,8 @@
    33.4 +from django.db.backends.sqlite3.base import Database
    33.5 +from django.contrib.gis.db.backend.adaptor import WKTAdaptor
    33.6 +
    33.7 +class SpatiaLiteAdaptor(WKTAdaptor):
    33.8 +    "SQLite adaptor for geometry objects."
    33.9 +    def __conform__(self, protocol):
   33.10 +        if protocol is Database.PrepareProtocol:
   33.11 +            return str(self)
    34.1 --- a/django/contrib/gis/db/backend/spatialite/creation.py	Sat Mar 28 12:05:48 2009 -0500
    34.2 +++ b/django/contrib/gis/db/backend/spatialite/creation.py	Wed Apr 01 13:05:19 2009 -0500
    34.3 @@ -1,18 +1,12 @@
    34.4  import os
    34.5 -
    34.6  from django.conf import settings
    34.7  from django.core.management import call_command
    34.8  from django.db import connection
    34.9 -from django.db.backends.creation import TEST_DATABASE_PREFIX
   34.10 -from django.contrib.gis.db.backend.util import getstatusoutput
   34.11 -
   34.12 -def spatialite_bin():
   34.13 -    return getattr(settings, 'SPATIALITE', 'spatialite')
   34.14  
   34.15  def spatialite_init_file():
   34.16 -    # SPATIALITE_SQL_FILE may be placed in settings to tell
   34.17 +    # SPATIALITE_SQL may be placed in settings to tell
   34.18      # GeoDjango to use a specific user-supplied file.
   34.19 -    return getattr(settings, 'SPATIALITE_SQL_FILE', 'init_spatialite-2.2.sql')
   34.20 +    return getattr(settings, 'SPATIALITE_SQL', 'init_spatialite-2.2.sql')
   34.21  
   34.22  def create_test_spatial_db(verbosity=1, autoclobber=False, interactive=False):
   34.23      "Creates a spatial database based on the settings."
   34.24 @@ -21,40 +15,47 @@
   34.25      if settings.DATABASE_ENGINE != 'sqlite3':
   34.26          raise Exception('SpatiaLite database creation only supported on sqlite3 platform.')
   34.27  
   34.28 -    db_name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
   34.29 +    # Getting the test database name using the the SQLite backend's
   34.30 +    # `_create_test_db`.  Unless `TEST_DATABASE_NAME` is defined,
   34.31 +    # it returns ":memory:".
   34.32 +    db_name = connection.creation._create_test_db(verbosity, autoclobber)
   34.33  
   34.34 -    # Now adding in the PostGIS routines.
   34.35 -    load_spatialite_sql(db_name, verbosity=verbosity)
   34.36 -
   34.37 -    if verbosity >= 1: print 'Creation of spatial database %s successful.' % db_name
   34.38 +    # Closing out the current connection to the database set in
   34.39 +    # originally in the settings.  This makes it so `initialize_spatialite`
   34.40 +    # function will be run on the connection for the _test_ database instead.
   34.41 +    connection.close()
   34.42  
   34.43      # Point to the new database
   34.44 -    connection.close()
   34.45      settings.DATABASE_NAME = db_name
   34.46      connection.settings_dict["DATABASE_NAME"] = db_name
   34.47      can_rollback = connection.creation._rollback_works()
   34.48      settings.DATABASE_SUPPORTS_TRANSACTIONS = can_rollback
   34.49      connection.settings_dict["DATABASE_SUPPORTS_TRANSACTIONS"] = can_rollback
   34.50  
   34.51 +    # Finally, loading up the SpatiaLite SQL file.
   34.52 +    load_spatialite_sql(db_name, verbosity=verbosity)
   34.53 +
   34.54 +    if verbosity >= 1:
   34.55 +        print 'Creation of spatial database %s successful.' % db_name
   34.56 +
   34.57      # Syncing the database
   34.58      call_command('syncdb', verbosity=verbosity, interactive=interactive)
   34.59  
   34.60  def load_spatialite_sql(db_name, verbosity=1):
   34.61      """
   34.62 -    This routine loads up the SpatiaLite SQL file init_spatialite-2.2.sql.
   34.63 +    This routine loads up the SpatiaLite SQL file.
   34.64      """
   34.65 -    if os.path.isabs(db_name):
   34.66 -        db_file = db_name
   34.67 -    else:
   34.68 -        db_file = os.path.join(os.getcwd(), db_name)
   34.69 +    # Getting the location of the SpatiaLite SQL file, and confirming
   34.70 +    # it exists.
   34.71 +    spatialite_sql = spatialite_init_file()
   34.72 +    if not os.path.isfile(spatialite_sql):
   34.73 +        raise Exception('Could not find the SpatiaLite initialization SQL file: %s' % spatialite_sql)
   34.74  
   34.75 -    cmd = '%(spatialite)s %(db_file)s < %(sql_file)s'
   34.76 -    params = {'spatialite' : spatialite_bin(),
   34.77 -              'db_file' : db_file, 
   34.78 -              'sql_file' : spatialite_init_file(),
   34.79 -              }
   34.80 -
   34.81 -    status, output = getstatusoutput(cmd % params)
   34.82 -    if status:
   34.83 -        raise Exception("Error executing 'spatialite' command: %s\n" % output)
   34.84 -
   34.85 +    # Opening up the SpatiaLite SQL initialization file and executing
   34.86 +    # as a script.
   34.87 +    sql_fh = open(spatialite_sql, 'r')
   34.88 +    try:
   34.89 +        cur = connection.cursor()
   34.90 +        cur.executescript(sql_fh.read())
   34.91 +    finally:
   34.92 +        sql_fh.close()
    35.1 --- a/django/contrib/gis/db/backend/spatialite/field.py	Sat Mar 28 12:05:48 2009 -0500
    35.2 +++ b/django/contrib/gis/db/backend/spatialite/field.py	Wed Apr 01 13:05:19 2009 -0500
    35.3 @@ -19,33 +19,22 @@
    35.4          Takes the style object (provides syntax highlighting) and the
    35.5          database table as parameters.
    35.6          """
    35.7 -        sql = style.SQL_KEYWORD('SELECT ') + \
    35.8 -              style.SQL_TABLE('AddGeometryColumn') + '(' + \
    35.9 -              style.SQL_TABLE(gqn(db_table)) + ', ' + \
   35.10 -              style.SQL_FIELD(gqn(self.column)) + ', ' + \
   35.11 -              style.SQL_FIELD(str(self.srid)) + ', ' + \
   35.12 -              style.SQL_COLTYPE(gqn(self.geom_type)) + ', ' + \
   35.13 -              style.SQL_KEYWORD(str(self.dim)) + ');'
   35.14 +        sql = (style.SQL_KEYWORD('SELECT ') +
   35.15 +               style.SQL_TABLE('AddGeometryColumn') + '(' +
   35.16 +               style.SQL_TABLE(gqn(db_table)) + ', ' +
   35.17 +               style.SQL_FIELD(gqn(self.column)) + ', ' +
   35.18 +               style.SQL_FIELD(str(self.srid)) + ', ' +
   35.19 +               style.SQL_COLTYPE(gqn(self.geom_type)) + ', ' +
   35.20 +               style.SQL_KEYWORD(str(self.dim)) + ');')
   35.21  
   35.22 -        # XXX Alas, sqlite3 does not support this kind of ALTER.
   35.23 -        # XXX Maybe we should create the column in the usual
   35.24 -        # XXX way and use RecoverGeometryColumn() instead?
   35.25 -        #if not self.null:
   35.26 -        #    # Add a NOT NULL constraint to the field
   35.27 -        #    sql += '\n' + \
   35.28 -        #           style.SQL_KEYWORD('ALTER TABLE ') + \
   35.29 -        #           style.SQL_TABLE(gqn(db_table)) + \
   35.30 -        #           style.SQL_KEYWORD(' ALTER ') + \
   35.31 -        #           style.SQL_FIELD(gqn(self.column)) + \
   35.32 -        #           style.SQL_KEYWORD(' SET NOT NULL') + ';'
   35.33          return sql
   35.34 -    
   35.35 +
   35.36      def _geom_index(self, style, db_table):
   35.37          "Creates a spatial index for this geometry field."
   35.38 -        sql = style.SQL_KEYWORD('SELECT ') + \
   35.39 -              style.SQL_TABLE('CreateSpatialIndex') + '(' + \
   35.40 -              style.SQL_TABLE(gqn(db_table)) + ', ' + \
   35.41 -              style.SQL_FIELD(gqn(self.column)) + ');'
   35.42 +        sql = (style.SQL_KEYWORD('SELECT ') +
   35.43 +              style.SQL_TABLE('CreateSpatialIndex') + '(' +
   35.44 +              style.SQL_TABLE(gqn(db_table)) + ', ' +
   35.45 +              style.SQL_FIELD(gqn(self.column)) + ');')
   35.46          return sql
   35.47  
   35.48      def post_create_sql(self, style, db_table):
   35.49 @@ -66,10 +55,10 @@
   35.50  
   35.51      def _post_delete_sql(self, style, db_table):
   35.52          "Drops the geometry column."
   35.53 -        sql = style.SQL_KEYWORD('SELECT ') + \
   35.54 -            style.SQL_KEYWORD('DropGeometryColumn') + '(' + \
   35.55 -            style.SQL_TABLE(gqn(db_table)) + ', ' + \
   35.56 -            style.SQL_FIELD(gqn(self.column)) +  ');'
   35.57 +        sql = (style.SQL_KEYWORD('SELECT ') +
   35.58 +               style.SQL_KEYWORD('DropGeometryColumn') + '(' +
   35.59 +               style.SQL_TABLE(gqn(db_table)) + ', ' +
   35.60 +               style.SQL_FIELD(gqn(self.column)) +  ');')
   35.61          return sql
   35.62  
   35.63      def db_type(self):
   35.64 @@ -83,7 +72,7 @@
   35.65          """
   35.66          Provides a proper substitution value for Geometries that are not in the
   35.67          SRID of the field.  Specifically, this routine will substitute in the
   35.68 -        Transform() function call.
   35.69 +        Transform() and GeomFromText() function call(s).
   35.70          """
   35.71          if value is None or value.srid == self.srid:
   35.72              return '%s(%%s,%s)' % (GEOM_FROM_TEXT, self.srid)
    36.1 --- a/django/contrib/gis/db/backend/util.py	Sat Mar 28 12:05:48 2009 -0500
    36.2 +++ b/django/contrib/gis/db/backend/util.py	Wed Apr 01 13:05:19 2009 -0500
    36.3 @@ -1,3 +1,8 @@
    36.4 +"""
    36.5 +A collection of utility routines and classes used by the spatial
    36.6 +backends.
    36.7 +"""
    36.8 +
    36.9  def getstatusoutput(cmd):
   36.10      """
   36.11      Executes a shell command on the platform using subprocess.Popen and
    37.1 --- a/django/contrib/gis/db/models/__init__.py	Sat Mar 28 12:05:48 2009 -0500
    37.2 +++ b/django/contrib/gis/db/models/__init__.py	Wed Apr 01 13:05:19 2009 -0500
    37.3 @@ -7,14 +7,8 @@
    37.4  # The GeoManager
    37.5  from django.contrib.gis.db.models.manager import GeoManager
    37.6  
    37.7 -# The GeoQ object
    37.8 -from django.contrib.gis.db.models.query import GeoQ
    37.9 -
   37.10  # The geographic-enabled fields.
   37.11  from django.contrib.gis.db.models.fields import \
   37.12       GeometryField, PointField, LineStringField, PolygonField, \
   37.13       MultiPointField, MultiLineStringField, MultiPolygonField, \
   37.14       GeometryCollectionField
   37.15 -
   37.16 -# The geographic mixin class.
   37.17 -from mixin import GeoMixin
    38.1 --- a/django/contrib/gis/db/models/fields/__init__.py	Sat Mar 28 12:05:48 2009 -0500
    38.2 +++ b/django/contrib/gis/db/models/fields/__init__.py	Wed Apr 01 13:05:19 2009 -0500
    38.3 @@ -13,7 +13,6 @@
    38.4      warn('This attribute has been deprecated, pleas use "%s" instead.' % func.__name__[1:])
    38.5      return property(func)
    38.6  
    38.7 -#TODO: Flesh out widgets; consider adding support for OGR Geometry proxies.
    38.8  class GeometryField(SpatialBackend.Field):
    38.9      "The base GIS field -- maps to the OpenGIS Specification Geometry type."
   38.10  
   38.11 @@ -57,17 +56,14 @@
   38.12          kwargs['verbose_name'] = verbose_name
   38.13  
   38.14          super(GeometryField, self).__init__(**kwargs) # Calling the parent initializtion function
   38.15 -    
   38.16 -    # These properties are for backwards-compatibility.
   38.17 +
   38.18 +    # The following properties are for formerly private variables that are now
   38.19 +    # public for GeometryField.  Because of their use by third-party applications,
   38.20 +    # a deprecation warning is issued to notify them to use new attribute name.
   38.21      def _deprecated_warning(self, old_name, new_name):
   38.22          from warnings import warn
   38.23          warn('The `%s` attribute name is deprecated, please update your code to use `%s` instead.' %
   38.24               (old_name, new_name))
   38.25 -        
   38.26 -    @property
   38.27 -    def _dim(self):
   38.28 -        self._deprecated_warning('_dim', 'dim')
   38.29 -        return self.dim
   38.30  
   38.31      @property
   38.32      def _geom(self):
   38.33 @@ -84,16 +80,6 @@
   38.34          self._deprecated_warning('_srid', 'srid')
   38.35          return self.srid
   38.36  
   38.37 -    @property
   38.38 -    def _unit(self):
   38.39 -        self._deprecated_warning('_unit', 'units')
   38.40 -        return self.units
   38.41 -    
   38.42 -    @property
   38.43 -    def _unit_name(self):
   38.44 -        self._deprecated_warning('_unit_name', 'units_name')
   38.45 -        return self.units_name
   38.46 -
   38.47      ### Routines specific to GeometryField ###
   38.48      @property
   38.49      def geodetic(self):
    39.1 --- a/django/contrib/gis/db/models/mixin.py	Sat Mar 28 12:05:48 2009 -0500
    39.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.3 @@ -1,11 +0,0 @@
    39.4 -# Until model subclassing is a possibility, a mixin class is used to add
    39.5 -# the necessary functions that may be contributed for geographic objects.
    39.6 -class GeoMixin:
    39.7 -    """
    39.8 -    The Geographic Mixin class provides routines for geographic objects,
    39.9 -    however, it is no longer necessary, since all of its previous functions 
   39.10 -    may now be accessed via the GeometryProxy.  This mixin is only provided
   39.11 -    for backwards-compatibility purposes, and will be eventually removed
   39.12 -    (unless the need arises again).
   39.13 -    """
   39.14 -    pass
    40.1 --- a/django/contrib/gis/db/models/query.py	Sat Mar 28 12:05:48 2009 -0500
    40.2 +++ b/django/contrib/gis/db/models/query.py	Wed Apr 01 13:05:19 2009 -0500
    40.3 @@ -1,6 +1,6 @@
    40.4  from django.core.exceptions import ImproperlyConfigured
    40.5  from django.db import connection
    40.6 -from django.db.models.query import sql, QuerySet, Q
    40.7 +from django.db.models.query import QuerySet, Q, ValuesQuerySet, ValuesListQuerySet
    40.8  
    40.9  from django.contrib.gis.db.backend import SpatialBackend
   40.10  from django.contrib.gis.db.models import aggregates
   40.11 @@ -9,25 +9,28 @@
   40.12  from django.contrib.gis.measure import Area, Distance
   40.13  from django.contrib.gis.models import get_srid_info
   40.14  
   40.15 -# For backwards-compatibility; Q object should work just fine
   40.16 -# after queryset-refactor.
   40.17 -class GeoQ(Q): pass
   40.18 -
   40.19 -class GeomSQL(object):
   40.20 -    "Simple wrapper object for geometric SQL."
   40.21 -    def __init__(self, geo_sql):
   40.22 -        self.sql = geo_sql
   40.23 -
   40.24 -    def as_sql(self, *args, **kwargs):
   40.25 -        return self.sql
   40.26 -
   40.27  class GeoQuerySet(QuerySet):
   40.28      "The Geographic QuerySet."
   40.29  
   40.30 +    ### Methods overloaded from QuerySet ###
   40.31      def __init__(self, model=None, query=None):
   40.32          super(GeoQuerySet, self).__init__(model=model, query=query)
   40.33          self.query = query or GeoQuery(self.model, connection)
   40.34  
   40.35 +    def values(self, *fields):
   40.36 +        return self._clone(klass=GeoValuesQuerySet, setup=True, _fields=fields)
   40.37 +
   40.38 +    def values_list(self, *fields, **kwargs):
   40.39 +        flat = kwargs.pop('flat', False)
   40.40 +        if kwargs:
   40.41 +            raise TypeError('Unexpected keyword arguments to values_list: %s'
   40.42 +                    % (kwargs.keys(),))
   40.43 +        if flat and len(fields) > 1:
   40.44 +            raise TypeError("'flat' is not valid when values_list is called with more than one field.")
   40.45 +        return self._clone(klass=GeoValuesListQuerySet, setup=True, flat=flat,
   40.46 +                           _fields=fields)
   40.47 +
   40.48 +    ### GeoQuerySet Methods ###
   40.49      def area(self, tolerance=0.05, **kwargs):
   40.50          """
   40.51          Returns the area of the geographic field in an `area` attribute on
   40.52 @@ -198,8 +201,7 @@
   40.53          """
   40.54          if SpatialBackend.spatialite:
   40.55              if z != 0.0:
   40.56 -                raise NotImplementedError, \
   40.57 -                      'SpatiaLite does not support 3D scaling.'
   40.58 +                raise NotImplementedError('SpatiaLite does not support 3D scaling.')
   40.59              s = {'procedure_fmt' : '%(geo_col)s,%(x)s,%(y)s',
   40.60                   'procedure_args' : {'x' : x, 'y' : y},
   40.61                   'select_field' : GeomField(),
   40.62 @@ -237,8 +239,7 @@
   40.63          """
   40.64          if SpatialBackend.spatialite:
   40.65              if z != 0.0:
   40.66 -                raise NotImplementedError, \
   40.67 -                      'SpatiaLite does not support 3D translation.'
   40.68 +                raise NotImplementedError('SpatiaLite does not support 3D translation.')
   40.69              s = {'procedure_fmt' : '%(geo_col)s,%(x)s,%(y)s',
   40.70                   'procedure_args' : {'x' : x, 'y' : y},
   40.71                   'select_field' : GeomField(),
   40.72 @@ -598,3 +599,14 @@
   40.73              return self.query._field_column(geo_field, parent_model._meta.db_table)
   40.74          else:
   40.75              return self.query._field_column(geo_field)
   40.76 +
   40.77 +class GeoValuesQuerySet(ValuesQuerySet):
   40.78 +    def __init__(self, *args, **kwargs):
   40.79 +        super(GeoValuesQuerySet, self).__init__(*args, **kwargs)
   40.80 +        # This flag tells `resolve_columns` to run the values through
   40.81 +        # `convert_values`.  This ensures that Geometry objects instead
   40.82 +        # of string values are returned with `values()` or `values_list()`.
   40.83 +        self.query.geo_values = True
   40.84 +
   40.85 +class GeoValuesListQuerySet(GeoValuesQuerySet, ValuesListQuerySet):
   40.86 +    pass
    41.1 --- a/django/contrib/gis/db/models/sql/query.py	Sat Mar 28 12:05:48 2009 -0500
    41.2 +++ b/django/contrib/gis/db/models/sql/query.py	Wed Apr 01 13:05:19 2009 -0500
    41.3 @@ -14,6 +14,8 @@
    41.4  ALL_TERMS = sql.constants.QUERY_TERMS.copy()
    41.5  ALL_TERMS.update(SpatialBackend.gis_terms)
    41.6  
    41.7 +TABLE_NAME = sql.constants.TABLE_NAME
    41.8 +
    41.9  class GeoQuery(sql.Query):
   41.10      """
   41.11      A single spatial SQL query.
   41.12 @@ -64,10 +66,15 @@
   41.13          else:
   41.14              col_aliases = set()
   41.15          if self.select:
   41.16 +            only_load = self.deferred_to_columns()
   41.17              # This loop customized for GeoQuery.
   41.18              for col, field in izip(self.select, self.select_fields):
   41.19                  if isinstance(col, (list, tuple)):
   41.20 -                    r = self.get_field_select(field, col[0])
   41.21 +                    alias, column = col
   41.22 +                    table = self.alias_map[alias][TABLE_NAME]
   41.23 +                    if table in only_load and col not in only_load[table]:
   41.24 +                        continue
   41.25 +                    r = self.get_field_select(field, alias)
   41.26                      if with_aliases:
   41.27                          if col[1] in col_aliases:
   41.28                              c_alias = 'Col%d' % len(col_aliases)
   41.29 @@ -75,7 +82,7 @@
   41.30                              aliases.add(c_alias)
   41.31                              col_aliases.add(c_alias)
   41.32                          else:
   41.33 -                            result.append('%s AS %s' % (r, col[1]))
   41.34 +                            result.append('%s AS %s' % (r, qn2(col[1])))
   41.35                              aliases.add(r)
   41.36                              col_aliases.add(col[1])
   41.37                      else:
   41.38 @@ -101,7 +108,7 @@
   41.39                      alias is not None and ' AS %s' % alias or ''
   41.40                      )
   41.41                  for alias, aggregate in self.aggregate_select.items()
   41.42 -                ])
   41.43 +        ])
   41.44  
   41.45          # This loop customized for GeoQuery.
   41.46          for (table, col), field in izip(self.related_select_cols, self.related_select_fields):
   41.47 @@ -123,10 +130,14 @@
   41.48                              start_alias=None, opts=None, as_pairs=False):
   41.49          """
   41.50          Computes the default columns for selecting every field in the base
   41.51 -        model.
   41.52 +        model. Will sometimes be called to pull in related models (e.g. via
   41.53 +        select_related), in which case "opts" and "start_alias" will be given
   41.54 +        to provide a starting point for the traversal.
   41.55  
   41.56          Returns a list of strings, quoted appropriately for use in SQL
   41.57 -        directly, as well as a set of aliases used in the select statement.
   41.58 +        directly, as well as a set of aliases used in the select statement (if
   41.59 +        'as_pairs' is True, returns a list of (alias, col_name) pairs instead
   41.60 +        of strings as the first component and None as the second component).
   41.61  
   41.62          This routine is overridden from Query to handle customized selection of
   41.63          geometry columns.
   41.64 @@ -134,22 +145,34 @@
   41.65          result = []
   41.66          if opts is None:
   41.67              opts = self.model._meta
   41.68 +        aliases = set()
   41.69 +        only_load = self.deferred_to_columns()
   41.70 +        proxied_model = opts.proxy and opts.proxy_for_model or 0
   41.71          if start_alias:
   41.72 -            table_alias = start_alias
   41.73 -        else:
   41.74 -            table_alias = self.tables[0]
   41.75 -        root_pk = opts.pk.column
   41.76 -        seen = {None: table_alias}
   41.77 -        aliases = set()
   41.78 +            seen = {None: start_alias}
   41.79          for field, model in opts.get_fields_with_model():
   41.80 -            try:
   41.81 -                alias = seen[model]
   41.82 -            except KeyError:
   41.83 -                alias = self.join((table_alias, model._meta.db_table,
   41.84 -                        root_pk, model._meta.pk.column))
   41.85 -                seen[model] = alias
   41.86 +            if start_alias:
   41.87 +                try:
   41.88 +                    alias = seen[model]
   41.89 +                except KeyError:
   41.90 +                    if model is proxied_model:
   41.91 +                        alias = start_alias
   41.92 +                    else:
   41.93 +                        link_field = opts.get_ancestor_link(model)
   41.94 +                        alias = self.join((start_alias, model._meta.db_table,
   41.95 +                                           link_field.column, model._meta.pk.column))
   41.96 +                    seen[model] = alias
   41.97 +            else:
   41.98 +                # If we're starting from the base model of the queryset, the
   41.99 +                # aliases will have already been set up in pre_sql_setup(), so
  41.100 +                # we can save time here.
  41.101 +                alias = self.included_inherited_models[model]
  41.102 +            table = self.alias_map[alias][TABLE_NAME]
  41.103 +            if table in only_load and field.column not in only_load[table]:
  41.104 +                continue
  41.105              if as_pairs:
  41.106                  result.append((alias, field.column))
  41.107 +                aliases.add(alias)
  41.108                  continue
  41.109              # This part of the function is customized for GeoQuery. We
  41.110              # see if there was any custom selection specified in the
  41.111 @@ -166,8 +189,6 @@
  41.112                  aliases.add(r)
  41.113                  if with_aliases:
  41.114                      col_aliases.add(field.column)
  41.115 -        if as_pairs:
  41.116 -            return result, None
  41.117          return result, aliases
  41.118  
  41.119      def resolve_columns(self, row, fields=()):
  41.120 @@ -191,8 +212,8 @@
  41.121          # distance objects added by GeoQuerySet methods).
  41.122          values = [self.convert_values(v, self.extra_select_fields.get(a, None))
  41.123                    for v, a in izip(row[rn_offset:index_start], aliases)]
  41.124 -        if SpatialBackend.oracle:
  41.125 -            # This is what happens normally in OracleQuery's `resolve_columns`.
  41.126 +        if SpatialBackend.oracle or getattr(self, 'geo_values', False):
  41.127 +            # We resolve the columns 
  41.128              for value, field in izip(row[index_start:], fields):
  41.129                  values.append(self.convert_values(value, field))
  41.130          else:
  41.131 @@ -215,7 +236,7 @@
  41.132              value = Distance(**{field.distance_att : value})
  41.133          elif isinstance(field, AreaField):
  41.134              value = Area(**{field.area_att : value})
  41.135 -        elif isinstance(field, GeomField) and value:
  41.136 +        elif isinstance(field, (GeomField, GeometryField)) and value:
  41.137              value = SpatialBackend.Geometry(value)
  41.138          return value
  41.139  
    42.1 --- a/django/contrib/gis/models.py	Sat Mar 28 12:05:48 2009 -0500
    42.2 +++ b/django/contrib/gis/models.py	Wed Apr 01 13:05:19 2009 -0500
    42.3 @@ -286,6 +286,7 @@
    42.4                  srs_wkt = SpatialReference(fetched[0]).wkt
    42.5              else:
    42.6                  srs_wkt = fetched[0]
    42.7 +            connection.close()
    42.8  
    42.9              # Getting metadata associated with the spatial reference system identifier.
   42.10              # Specifically, getting the unit information and spheroid information
    43.1 --- a/django/contrib/gis/tests/relatedapp/models.py	Sat Mar 28 12:05:48 2009 -0500
    43.2 +++ b/django/contrib/gis/tests/relatedapp/models.py	Wed Apr 01 13:05:19 2009 -0500
    43.3 @@ -2,15 +2,16 @@
    43.4  from django.contrib.localflavor.us.models import USStateField
    43.5  
    43.6  class Location(models.Model):
    43.7 -    name = models.CharField(max_length=50)
    43.8      point = models.PointField()
    43.9      objects = models.GeoManager()
   43.10 +    def __unicode__(self): return self.point.wkt
   43.11  
   43.12  class City(models.Model):
   43.13      name = models.CharField(max_length=50)
   43.14      state = USStateField()
   43.15      location = models.ForeignKey(Location)
   43.16      objects = models.GeoManager()
   43.17 +    def __unicode__(self): return self.name
   43.18  
   43.19  class AugmentedLocation(Location):
   43.20      extra_text = models.TextField(blank=True)
    44.1 --- a/django/contrib/gis/tests/relatedapp/tests.py	Sat Mar 28 12:05:48 2009 -0500
    44.2 +++ b/django/contrib/gis/tests/relatedapp/tests.py	Wed Apr 01 13:05:19 2009 -0500
    44.3 @@ -118,7 +118,7 @@
    44.4          # Regression test for #9752.
    44.5          l = list(DirectoryEntry.objects.all().select_related())
    44.6  
    44.7 -    def test6_f_expressions(self):
    44.8 +    def test06_f_expressions(self):
    44.9          "Testing F() expressions on GeometryFields."
   44.10          # Constructing a dummy parcel border and getting the City instance for
   44.11          # assigning the FK.
   44.12 @@ -166,6 +166,31 @@
   44.13              self.assertEqual(1, len(qs))
   44.14              self.assertEqual('P1', qs[0].name)
   44.15  
   44.16 +    def test07_values(self):
   44.17 +        "Testing values() and values_list() and GeoQuerySets."
   44.18 +        # GeoQuerySet and GeoValuesQuerySet, and GeoValuesListQuerySet respectively.
   44.19 +        gqs = Location.objects.all()
   44.20 +        gvqs = Location.objects.values()
   44.21 +        gvlqs = Location.objects.values_list()
   44.22 +
   44.23 +        # Incrementing through each of the models, dictionaries, and tuples
   44.24 +        # returned by the different types of GeoQuerySets.
   44.25 +        for m, d, t in zip(gqs, gvqs, gvlqs):
   44.26 +            # The values should be Geometry objects and not raw strings returned
   44.27 +            # by the spatial database.
   44.28 +            self.failUnless(isinstance(d['point'], SpatialBackend.Geometry))
   44.29 +            self.failUnless(isinstance(t[1], SpatialBackend.Geometry))
   44.30 +            self.assertEqual(m.point, d['point'])
   44.31 +            self.assertEqual(m.point, t[1])
   44.32 +
   44.33 +    # Test disabled until #10572 is resolved.
   44.34 +    #def test08_defer_only(self):
   44.35 +    #    "Testing defer() and only() on Geographic models."
   44.36 +    #    qs = Location.objects.all()
   44.37 +    #    def_qs = Location.objects.defer('point')
   44.38 +    #    for loc, def_loc in zip(qs, def_qs):
   44.39 +    #        self.assertEqual(loc.point, def_loc.point)
   44.40 +
   44.41      # TODO: Related tests for KML, GML, and distance lookups.
   44.42  
   44.43  def suite():
    45.1 --- a/django/contrib/gis/tests/test_spatialrefsys.py	Sat Mar 28 12:05:48 2009 -0500
    45.2 +++ b/django/contrib/gis/tests/test_spatialrefsys.py	Wed Apr 01 13:05:19 2009 -0500
    45.3 @@ -1,6 +1,6 @@
    45.4  import unittest
    45.5 -from django.contrib.gis.tests.utils import mysql, spatialite, no_mysql, no_spatialite, oracle, postgis
    45.6 -if not mysql and not spatialite:
    45.7 +from django.contrib.gis.tests.utils import mysql, no_mysql, oracle, postgis, spatialite
    45.8 +if not mysql:
    45.9      from django.contrib.gis.models import SpatialRefSys
   45.10  
   45.11  test_srs = ({'srid' : 4326,
   45.12 @@ -9,7 +9,7 @@
   45.13               'srtext' : 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]',
   45.14               'proj4' : '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs ',
   45.15               'spheroid' : 'WGS 84', 'name' : 'WGS 84', 
   45.16 -             'geographic' : True, 'projected' : False,
   45.17 +             'geographic' : True, 'projected' : False, 'spatialite' : True,
   45.18               'ellipsoid' : (6378137.0, 6356752.3, 298.257223563), # From proj's "cs2cs -le" and Wikipedia (semi-minor only)
   45.19               'eprec' : (1, 1, 9),
   45.20               },
   45.21 @@ -19,7 +19,7 @@
   45.22               'srtext' : 'PROJCS["NAD83 / Texas South Central",GEOGCS["NAD83",DATUM["North_American_Datum_1983",SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],AUTHORITY["EPSG","6269"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4269"]],PROJECTION["Lambert_Conformal_Conic_2SP"],PARAMETER["standard_parallel_1",30.28333333333333],PARAMETER["standard_parallel_2",28.38333333333333],PARAMETER["latitude_of_origin",27.83333333333333],PARAMETER["central_meridian",-99],PARAMETER["false_easting",600000],PARAMETER["false_northing",4000000],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AUTHORITY["EPSG","32140"]]',
   45.23               'proj4' : '+proj=lcc +lat_1=30.28333333333333 +lat_2=28.38333333333333 +lat_0=27.83333333333333 +lon_0=-99 +x_0=600000 +y_0=4000000 +ellps=GRS80 +datum=NAD83 +units=m +no_defs ',
   45.24               'spheroid' : 'GRS 1980', 'name' : 'NAD83 / Texas South Central',
   45.25 -             'geographic' : False, 'projected' : True,
   45.26 +             'geographic' : False, 'projected' : True, 'spatialite' : False,
   45.27               'ellipsoid' : (6378137.0, 6356752.31414, 298.257222101), # From proj's "cs2cs -le" and Wikipedia (semi-minor only)
   45.28               'eprec' : (1, 5, 10),
   45.29               },
   45.30 @@ -28,7 +28,6 @@
   45.31  class SpatialRefSysTest(unittest.TestCase):
   45.32  
   45.33      @no_mysql
   45.34 -    @no_spatialite
   45.35      def test01_retrieve(self):
   45.36          "Testing retrieval of SpatialRefSys model objects."
   45.37          for sd in test_srs:
   45.38 @@ -50,7 +49,6 @@
   45.39                  self.assertEqual(sd['proj4'], srs.proj4text)
   45.40  
   45.41      @no_mysql
   45.42 -    @no_spatialite
   45.43      def test02_osr(self):
   45.44          "Testing getting OSR objects from SpatialRefSys model objects."
   45.45          for sd in test_srs:
   45.46 @@ -58,16 +56,21 @@
   45.47              self.assertEqual(True, sr.spheroid.startswith(sd['spheroid']))
   45.48              self.assertEqual(sd['geographic'], sr.geographic)
   45.49              self.assertEqual(sd['projected'], sr.projected)
   45.50 -            self.assertEqual(True, sr.name.startswith(sd['name']))
   45.51 +
   45.52 +            if not (spatialite and not sd['spatialite']):
   45.53 +                # Can't get 'NAD83 / Texas South Central' from PROJ.4 string
   45.54 +                # on SpatiaLite
   45.55 +                self.assertEqual(True, sr.name.startswith(sd['name']))
   45.56  
   45.57              # Testing the SpatialReference object directly.
   45.58 -            if postgis:
   45.59 +            if postgis or spatialite:
   45.60                  srs = sr.srs
   45.61                  self.assertEqual(sd['proj4'], srs.proj4)
   45.62 -                self.assertEqual(sd['srtext'], srs.wkt)
   45.63 +                # No `srtext` field in the `spatial_ref_sys` table in SpatiaLite
   45.64 +                if not spatialite:
   45.65 +                    self.assertEqual(sd['srtext'], srs.wkt)
   45.66  
   45.67      @no_mysql
   45.68 -    @no_spatialite
   45.69      def test03_ellipsoid(self):
   45.70          "Testing the ellipsoid property."
   45.71          for sd in test_srs:
    46.1 --- a/django/contrib/gis/utils/srs.py	Sat Mar 28 12:05:48 2009 -0500
    46.2 +++ b/django/contrib/gis/utils/srs.py	Wed Apr 01 13:05:19 2009 -0500
    46.3 @@ -10,7 +10,7 @@
    46.4      >>> add_postgis_srs(SpatialReference(900913))
    46.5  
    46.6      Keyword Arguments:
    46.7 -     auth_name: This keyword may be customized with the value of the 
    46.8 +     auth_name: This keyword may be customized with the value of the
    46.9                  `auth_name` field.  Defaults to 'EPSG'.
   46.10  
   46.11       auth_srid: This keyword may be customized with the value of the
    47.1 --- a/django/contrib/localflavor/it/it_province.py	Sat Mar 28 12:05:48 2009 -0500
    47.2 +++ b/django/contrib/localflavor/it/it_province.py	Wed Apr 01 13:05:19 2009 -0500
    47.3 @@ -10,7 +10,7 @@
    47.4      ('AT', 'Asti'),
    47.5      ('AV', 'Avellino'),
    47.6      ('BA', 'Bari'),
    47.7 -#    ('BT', 'Barletta-Andria-Trani'), # active starting from 2009
    47.8 +    ('BT', 'Barletta-Andria-Trani'), # active starting from 2009
    47.9      ('BL', 'Belluno'),
   47.10      ('BN', 'Benevento'),
   47.11      ('BG', 'Bergamo'),
   47.12 @@ -33,7 +33,7 @@
   47.13      ('KR', 'Crotone'),
   47.14      ('CN', 'Cuneo'),
   47.15      ('EN', 'Enna'),
   47.16 -#    ('FM', 'Fermo'), # active starting from 2009
   47.17 +    ('FM', 'Fermo'), # active starting from 2009
   47.18      ('FE', 'Ferrara'),
   47.19      ('FI', 'Firenze'),
   47.20      ('FG', 'Foggia'),
   47.21 @@ -60,7 +60,7 @@
   47.22      ('ME', 'Messina'),
   47.23      ('MI', 'Milano'),
   47.24      ('MO', 'Modena'),
   47.25 -#    ('MB', 'Monza e Brianza'), # active starting from 2009
   47.26 +    ('MB', 'Monza e Brianza'), # active starting from 2009
   47.27      ('NA', 'Napoli'),
   47.28      ('NO', 'Novara'),
   47.29      ('NU', 'Nuoro'),
    48.1 --- a/django/core/cache/backends/locmem.py	Sat Mar 28 12:05:48 2009 -0500
    48.2 +++ b/django/core/cache/backends/locmem.py	Wed Apr 01 13:05:19 2009 -0500
    48.3 @@ -58,8 +58,11 @@
    48.4              self._lock.reader_leaves()
    48.5          self._lock.writer_enters()
    48.6          try:
    48.7 -            del self._cache[key]
    48.8 -            del self._expire_info[key]
    48.9 +            try:
   48.10 +                del self._cache[key]
   48.11 +                del self._expire_info[key]
   48.12 +            except KeyError:
   48.13 +                pass
   48.14              return default
   48.15          finally:
   48.16              self._lock.writer_leaves()
    49.1 --- a/django/core/management/base.py	Sat Mar 28 12:05:48 2009 -0500
    49.2 +++ b/django/core/management/base.py	Wed Apr 01 13:05:19 2009 -0500
    49.3 @@ -73,7 +73,7 @@
    49.4         output and, if the command is intended to produce a block of
    49.5         SQL statements, will be wrapped in ``BEGIN`` and ``COMMIT``.
    49.6  
    49.7 -    4. If ``handle()`` raised a ``ComandError``, ``execute()`` will
    49.8 +    4. If ``handle()`` raised a ``CommandError``, ``execute()`` will
    49.9         instead print an error message to ``stderr``.
   49.10  
   49.11      Thus, the ``handle()`` method is typically the starting point for
    50.1 --- a/django/core/urlresolvers.py	Sat Mar 28 12:05:48 2009 -0500
    50.2 +++ b/django/core/urlresolvers.py	Wed Apr 01 13:05:19 2009 -0500
    50.3 @@ -24,7 +24,7 @@
    50.4      from django.utils.itercompat import reversed     # Python 2.3 fallback
    50.5      from sets import Set as set
    50.6  
    50.7 -_resolver_cache = {} # Maps urlconf modules to RegexURLResolver instances.
    50.8 +_resolver_cache = {} # Maps URLconf modules to RegexURLResolver instances.
    50.9  _callable_cache = {} # Maps view and url pattern names to their view functions.
   50.10  
   50.11  # SCRIPT_NAME prefixes for each thread are stored here. If there's no entry for
   50.12 @@ -141,7 +141,7 @@
   50.13  class RegexURLResolver(object):
   50.14      def __init__(self, regex, urlconf_name, default_kwargs=None):
   50.15          # regex is a string representing a regular expression.
   50.16 -        # urlconf_name is a string representing the module containing urlconfs.
   50.17 +        # urlconf_name is a string representing the module containing URLconfs.
   50.18          self.regex = re.compile(regex, re.UNICODE)
   50.19          self.urlconf_name = urlconf_name
   50.20          if not isinstance(urlconf_name, basestring):
    51.1 --- a/django/db/backends/signals.py	Sat Mar 28 12:05:48 2009 -0500
    51.2 +++ b/django/db/backends/signals.py	Wed Apr 01 13:05:19 2009 -0500
    51.3 @@ -1,6 +1,3 @@
    51.4  from django.dispatch import Signal
    51.5  
    51.6  connection_created = Signal()
    51.7 -from django.dispatch import Signal
    51.8 -
    51.9 -connection_created = Signal()
    52.1 --- a/django/db/models/fields/files.py	Sat Mar 28 12:05:48 2009 -0500
    52.2 +++ b/django/db/models/fields/files.py	Wed Apr 01 13:05:19 2009 -0500
    52.3 @@ -222,7 +222,7 @@
    52.4              setattr(instance, self.name, data)
    52.5  
    52.6      def formfield(self, **kwargs):
    52.7 -        defaults = {'form_class': forms.FileField}
    52.8 +        defaults = {'form_class': forms.FileField, 'max_length': self.max_length}
    52.9          # If a file has been provided previously, then the form doesn't require
   52.10          # that a new file is provided this time.
   52.11          # The code to mark the form field as not required is used by
    53.1 --- a/django/db/models/fields/related.py	Sat Mar 28 12:05:48 2009 -0500
    53.2 +++ b/django/db/models/fields/related.py	Wed Apr 01 13:05:19 2009 -0500
    53.3 @@ -210,8 +210,8 @@
    53.4                                  (value, instance._meta.object_name,
    53.5                                   self.related.get_accessor_name(), self.related.opts.object_name))
    53.6  
    53.7 -        # Set the value of the related field
    53.8 -        setattr(value, self.related.field.rel.get_related_field().attname, instance)
    53.9 +        # Set the value of the related field to the value of the related object's related field
   53.10 +        setattr(value, self.related.field.attname, getattr(instance, self.related.field.rel.get_related_field().attname))
   53.11  
   53.12          # Since we already know what the related object is, seed the related
   53.13          # object caches now, too. This avoids another db hit if you get the
   53.14 @@ -332,6 +332,8 @@
   53.15  
   53.16              def add(self, *objs):
   53.17                  for obj in objs:
   53.18 +                    if not isinstance(obj, self.model):
   53.19 +                        raise TypeError, "'%s' instance expected" % self.model._meta.object_name
   53.20                      setattr(obj, rel_field.name, instance)
   53.21                      obj.save()
   53.22              add.alters_data = True
   53.23 @@ -452,11 +454,14 @@
   53.24  
   53.25              # If there aren't any objects, there is nothing to do.
   53.26              if objs:
   53.27 +                from django.db.models.base import Model
   53.28                  # Check that all the objects are of the right type
   53.29                  new_ids = set()
   53.30                  for obj in objs:
   53.31                      if isinstance(obj, self.model):
   53.32                          new_ids.add(obj._get_pk_val())
   53.33 +                    elif isinstance(obj, Model):
   53.34 +                        raise TypeError, "'%s' instance expected" % self.model._meta.object_name
   53.35                      else:
   53.36                          new_ids.add(obj)
   53.37                  # Add the newly created or already existing objects to the join table.
    54.1 --- a/django/db/models/sql/query.py	Sat Mar 28 12:05:48 2009 -0500
    54.2 +++ b/django/db/models/sql/query.py	Wed Apr 01 13:05:19 2009 -0500
    54.3 @@ -784,8 +784,6 @@
    54.4                  aliases.add(r)
    54.5                  if with_aliases:
    54.6                      col_aliases.add(field.column)
    54.7 -        if as_pairs:
    54.8 -            return result, aliases
    54.9          return result, aliases
   54.10  
   54.11      def get_from_clause(self):
    55.1 --- a/django/forms/fields.py	Sat Mar 28 12:05:48 2009 -0500
    55.2 +++ b/django/forms/fields.py	Wed Apr 01 13:05:19 2009 -0500
    55.3 @@ -447,9 +447,11 @@
    55.4          'invalid': _(u"No file was submitted. Check the encoding type on the form."),
    55.5          'missing': _(u"No file was submitted."),
    55.6          'empty': _(u"The submitted file is empty."),
    55.7 +        'max_length': _(u'Ensure this filename has at most %(max)d characters (it has %(length)d).'),
    55.8      }
    55.9  
   55.10      def __init__(self, *args, **kwargs):
   55.11 +        self.max_length = kwargs.pop('max_length', None)
   55.12          super(FileField, self).__init__(*args, **kwargs)
   55.13  
   55.14      def clean(self, data, initial=None):
   55.15 @@ -466,6 +468,9 @@
   55.16          except AttributeError:
   55.17              raise ValidationError(self.error_messages['invalid'])
   55.18  
   55.19 +        if self.max_length is not None and len(file_name) > self.max_length:
   55.20 +            error_values =  {'max': self.max_length, 'length': len(file_name)}
   55.21 +            raise ValidationError(self.error_messages['max_length'] % error_values)
   55.22          if not file_name:
   55.23              raise ValidationError(self.error_messages['invalid'])
   55.24          if not file_size:
    56.1 --- a/django/forms/forms.py	Sat Mar 28 12:05:48 2009 -0500
    56.2 +++ b/django/forms/forms.py	Wed Apr 01 13:05:19 2009 -0500
    56.3 @@ -205,6 +205,15 @@
    56.4          """
    56.5          return self.errors.get(NON_FIELD_ERRORS, self.error_class())
    56.6  
    56.7 +    def _raw_value(self, fieldname):
    56.8 +        """
    56.9 +        Returns the raw_value for a particular field name. This is just a
   56.10 +        convenient wrapper around widget.value_from_datadict.
   56.11 +        """
   56.12 +        field = self.fields[fieldname]
   56.13 +        prefix = self.add_prefix(fieldname)
   56.14 +        return field.widget.value_from_datadict(self.data, self.files, prefix)
   56.15 +
   56.16      def full_clean(self):
   56.17          """
   56.18          Cleans all of self.data and populates self._errors and
    57.1 --- a/django/forms/formsets.py	Sat Mar 28 12:05:48 2009 -0500
    57.2 +++ b/django/forms/formsets.py	Wed Apr 01 13:05:19 2009 -0500
    57.3 @@ -4,7 +4,7 @@
    57.4  from django.utils.translation import ugettext as _
    57.5  from fields import IntegerField, BooleanField
    57.6  from widgets import Media, HiddenInput
    57.7 -from util import ErrorList, ValidationError
    57.8 +from util import ErrorList, ErrorDict, ValidationError
    57.9  
   57.10  __all__ = ('BaseFormSet', 'all_valid')
   57.11  
   57.12 @@ -40,39 +40,51 @@
   57.13          self.error_class = error_class
   57.14          self._errors = None
   57.15          self._non_form_errors = None
   57.16 -        # initialization is different depending on whether we recieved data, initial, or nothing
   57.17 -        if data or files:
   57.18 -            self.management_form = ManagementForm(data, auto_id=self.auto_id, prefix=self.prefix)
   57.19 -            if self.management_form.is_valid():
   57.20 -                self._total_form_count = self.management_form.cleaned_data[TOTAL_FORM_COUNT]
   57.21 -                self._initial_form_count = self.management_form.cleaned_data[INITIAL_FORM_COUNT]
   57.22 -            else:
   57.23 -                raise ValidationError('ManagementForm data is missing or has been tampered with')
   57.24 -        else:
   57.25 -            if initial:
   57.26 -                self._initial_form_count = len(initial)
   57.27 -                if self._initial_form_count > self.max_num and self.max_num > 0:
   57.28 -                    self._initial_form_count = self.max_num
   57.29 -                self._total_form_count = self._initial_form_count + self.extra
   57.30 -            else:
   57.31 -                self._initial_form_count = 0
   57.32 -                self._total_form_count = self.extra
   57.33 -            if self._total_form_count > self.max_num and self.max_num > 0:
   57.34 -                self._total_form_count = self.max_num
   57.35 -            initial = {TOTAL_FORM_COUNT: self._total_form_count,
   57.36 -                       INITIAL_FORM_COUNT: self._initial_form_count}
   57.37 -            self.management_form = ManagementForm(initial=initial, auto_id=self.auto_id, prefix=self.prefix)
   57.38 -
   57.39          # construct the forms in the formset
   57.40          self._construct_forms()
   57.41  
   57.42      def __unicode__(self):
   57.43          return self.as_table()
   57.44  
   57.45 +    def _management_form(self):
   57.46 +        """Returns the ManagementForm instance for this FormSet."""
   57.47 +        if self.data or self.files:
   57.48 +            form = ManagementForm(self.data, auto_id=self.auto_id, prefix=self.prefix)
   57.49 +            if not form.is_valid():
   57.50 +                raise ValidationError('ManagementForm data is missing or has been tampered with')
   57.51 +        else:
   57.52 +            form = ManagementForm(auto_id=self.auto_id, prefix=self.prefix, initial={
   57.53 +                TOTAL_FORM_COUNT: self.total_form_count(),
   57.54 +                INITIAL_FORM_COUNT: self.initial_form_count()
   57.55 +            })
   57.56 +        return form
   57.57 +    management_form = property(_management_form)
   57.58 +
   57.59 +    def total_form_count(self):
   57.60 +        """Returns the total number of forms in this FormSet."""
   57.61 +        if self.data or self.files:
   57.62 +            return self.management_form.cleaned_data[TOTAL_FORM_COUNT]
   57.63 +        else:
   57.64 +            total_forms = self.initial_form_count() + self.extra
   57.65 +            if total_forms > self.max_num > 0:
   57.66 +                total_forms = self.max_num
   57.67 +        return total_forms
   57.68 +
   57.69 +    def initial_form_count(self):
   57.70 +        """Returns the number of forms that are required in this FormSet."""
   57.71 +        if self.data or self.files:
   57.72 +            return self.management_form.cleaned_data[INITIAL_FORM_COUNT]
   57.73 +        else:
   57.74 +            # Use the length of the inital data if it's there, 0 otherwise.
   57.75 +            initial_forms = self.initial and len(self.initial) or 0
   57.76 +            if initial_forms > self.max_num > 0:
   57.77 +                initial_forms = self.max_num
   57.78 +        return initial_forms
   57.79 +
   57.80      def _construct_forms(self):
   57.81          # instantiate all the forms and put them in self.forms
   57.82          self.forms = []
   57.83 -        for i in xrange(self._total_form_count):
   57.84 +        for i in xrange(self.total_form_count()):
   57.85              self.forms.append(self._construct_form(i))
   57.86  
   57.87      def _construct_form(self, i, **kwargs):
   57.88 @@ -89,7 +101,7 @@
   57.89              except IndexError:
   57.90                  pass
   57.91          # Allow extra forms to be empty.
   57.92 -        if i >= self._initial_form_count:
   57.93 +        if i >= self.initial_form_count():
   57.94              defaults['empty_permitted'] = True
   57.95          defaults.update(kwargs)
   57.96          form = self.form(**defaults)
   57.97 @@ -97,13 +109,13 @@
   57.98          return form
   57.99  
  57.100      def _get_initial_forms(self):
  57.101 -        """Return a list of all the intial forms in this formset."""
  57.102 -        return self.forms[:self._initial_form_count]
  57.103 +        """Return a list of all the initial forms in this formset."""
  57.104 +        return self.forms[:self.initial_form_count()]
  57.105      initial_forms = property(_get_initial_forms)
  57.106  
  57.107      def _get_extra_forms(self):
  57.108          """Return a list of all the extra forms in this formset."""
  57.109 -        return self.forms[self._initial_form_count:]
  57.110 +        return self.forms[self.initial_form_count():]
  57.111      extra_forms = property(_get_extra_forms)
  57.112  
  57.113      # Maybe this should just go away?
  57.114 @@ -127,10 +139,10 @@
  57.115          # that have had their deletion widget set to True
  57.116          if not hasattr(self, '_deleted_form_indexes'):
  57.117              self._deleted_form_indexes = []
  57.118 -            for i in range(0, self._total_form_count):
  57.119 +            for i in range(0, self.total_form_count()):
  57.120                  form = self.forms[i]
  57.121                  # if this is an extra form and hasn't changed, don't consider it
  57.122 -                if i >= self._initial_form_count and not form.has_changed():
  57.123 +                if i >= self.initial_form_count() and not form.has_changed():
  57.124                      continue
  57.125                  if form.cleaned_data[DELETION_FIELD_NAME]:
  57.126                      self._deleted_form_indexes.append(i)
  57.127 @@ -140,7 +152,7 @@
  57.128      def _get_ordered_forms(self):
  57.129          """
  57.130          Returns a list of form in the order specified by the incoming data.
  57.131 -        Raises an AttributeError if deletion is not allowed.
  57.132 +        Raises an AttributeError if ordering is not allowed.
  57.133          """
  57.134          if not self.is_valid() or not self.can_order:
  57.135              raise AttributeError("'%s' object has no attribute 'ordered_forms'" % self.__class__.__name__)
  57.136 @@ -150,10 +162,10 @@
  57.137          # by the form data.
  57.138          if not hasattr(self, '_ordering'):
  57.139              self._ordering = []
  57.140 -            for i in range(0, self._total_form_count):
  57.141 +            for i in range(0, self.total_form_count()):
  57.142                  form = self.forms[i]
  57.143                  # if this is an extra form and hasn't changed, don't consider it
  57.144 -                if i >= self._initial_form_count and not form.has_changed():
  57.145 +                if i >= self.initial_form_count() and not form.has_changed():
  57.146                      continue
  57.147                  # don't add data marked for deletion to self.ordered_data
  57.148                  if self.can_delete and form.cleaned_data[DELETION_FIELD_NAME]:
  57.149 @@ -209,8 +221,20 @@
  57.150          # We loop over every form.errors here rather than short circuiting on the
  57.151          # first failure to make sure validation gets triggered for every form.
  57.152          forms_valid = True
  57.153 -        for errors in self.errors:
  57.154 -            if bool(errors):
  57.155 +        for i in range(0, self.total_form_count()):
  57.156 +            form = self.forms[i]
  57.157 +            if self.can_delete:
  57.158 +                # The way we lookup the value of the deletion field here takes
  57.159 +                # more code than we'd like, but the form's cleaned_data will
  57.160 +                # not exist if the form is invalid.
  57.161 +                field = form.fields[DELETION_FIELD_NAME]
  57.162 +                raw_value = form._raw_value(DELETION_FIELD_NAME)
  57.163 +                should_delete = field.clean(raw_value)
  57.164 +                if should_delete:
  57.165 +                    # This form is going to be deleted so any of its errors
  57.166 +                    # should not cause the entire formset to be invalid.
  57.167 +                    continue
  57.168 +            if bool(self.errors[i]):
  57.169                  forms_valid = False
  57.170          return forms_valid and not bool(self.non_form_errors())
  57.171  
  57.172 @@ -221,7 +245,7 @@
  57.173          self._errors = []
  57.174          if not self.is_bound: # Stop further processing.
  57.175              return
  57.176 -        for i in range(0, self._total_form_count):
  57.177 +        for i in range(0, self.total_form_count()):
  57.178              form = self.forms[i]
  57.179              self._errors.append(form.errors)
  57.180          # Give self.clean() a chance to do cross-form validation.
  57.181 @@ -243,7 +267,7 @@
  57.182          """A hook for adding extra fields on to each form instance."""
  57.183          if self.can_order:
  57.184              # Only pre-fill the ordering field for initial forms.
  57.185 -            if index < self._initial_form_count:
  57.186 +            if index < self.initial_form_count():
  57.187                  form.fields[ORDERING_FIELD_NAME] = IntegerField(label=_(u'Order'), initial=index+1, required=False)
  57.188              else:
  57.189                  form.fields[ORDERING_FIELD_NAME] = IntegerField(label=_(u'Order'), required=False)
    58.1 --- a/django/forms/models.py	Sat Mar 28 12:05:48 2009 -0500
    58.2 +++ b/django/forms/models.py	Wed Apr 01 13:05:19 2009 -0500
    58.3 @@ -54,6 +54,10 @@
    58.4          # callable upload_to can use the values from other fields.
    58.5          if isinstance(f, models.FileField):
    58.6              file_field_list.append(f)
    58.7 +        # OneToOneField doesn't allow assignment of None. Guard against that
    58.8 +        # instead of allowing it and throwing an error.
    58.9 +        if isinstance(f, models.OneToOneField) and cleaned_data[f.name] is None:
   58.10 +            pass
   58.11          else:
   58.12              f.save_form_data(instance, cleaned_data[f.name])
   58.13  
   58.14 @@ -266,7 +270,13 @@
   58.15  
   58.16              lookup_kwargs = {}
   58.17              for field_name in unique_check:
   58.18 -                lookup_kwargs[field_name] = self.cleaned_data[field_name]
   58.19 +                lookup_value = self.cleaned_data[field_name]
   58.20 +                # ModelChoiceField will return an object instance rather than
   58.21 +                # a raw primary key value, so convert it to a pk value before
   58.22 +                # using it in a lookup.
   58.23 +                if isinstance(self.fields[field_name], ModelChoiceField):
   58.24 +                    lookup_value =  lookup_value.pk
   58.25 +                lookup_kwargs[field_name] = lookup_value
   58.26  
   58.27              qs = self.instance.__class__._default_manager.filter(**lookup_kwargs)
   58.28  
   58.29 @@ -357,12 +367,17 @@
   58.30                   queryset=None, **kwargs):
   58.31          self.queryset = queryset
   58.32          defaults = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix}
   58.33 -        defaults['initial'] = [model_to_dict(obj) for obj in self.get_queryset()]
   58.34          defaults.update(kwargs)
   58.35          super(BaseModelFormSet, self).__init__(**defaults)
   58.36  
   58.37 +    def initial_form_count(self):
   58.38 +        """Returns the number of forms that are required in this FormSet."""
   58.39 +        if not (self.data or self.files):
   58.40 +            return len(self.get_queryset())
   58.41 +        return super(BaseModelFormSet, self).initial_form_count()
   58.42 +
   58.43      def _construct_form(self, i, **kwargs):
   58.44 -        if i < self._initial_form_count:
   58.45 +        if i < self.initial_form_count():
   58.46              kwargs['instance'] = self.get_queryset()[i]
   58.47          return super(BaseModelFormSet, self)._construct_form(i, **kwargs)
   58.48  
   58.49 @@ -380,11 +395,11 @@
   58.50  
   58.51      def save_new(self, form, commit=True):
   58.52          """Saves and returns a new model instance for the given form."""
   58.53 -        return save_instance(form, self.model(), exclude=[self._pk_field.name], commit=commit)
   58.54 +        return form.save(commit=commit)
   58.55  
   58.56      def save_existing(self, form, instance, commit=True):
   58.57          """Saves and returns an existing model instance for the given form."""
   58.58 -        return save_instance(form, instance, exclude=[self._pk_field.name], commit=commit)
   58.59 +        return form.save(commit=commit)
   58.60  
   58.61      def save(self, commit=True):
   58.62          """Saves model instances for every form, adding and changing instances
   58.63 @@ -410,16 +425,22 @@
   58.64              existing_objects[obj.pk] = obj
   58.65          saved_instances = []
   58.66          for form in self.initial_forms:
   58.67 -            obj = existing_objects[form.cleaned_data[self._pk_field.name]]
   58.68 -            if self.can_delete and form.cleaned_data[DELETION_FIELD_NAME]:
   58.69 -                self.deleted_objects.append(obj)
   58.70 -                obj.delete()
   58.71 -            else:
   58.72 -                if form.changed_data:
   58.73 -                    self.changed_objects.append((obj, form.changed_data))
   58.74 -                    saved_instances.append(self.save_existing(form, obj, commit=commit))
   58.75 -                    if not commit:
   58.76 -                        self.saved_forms.append(form)
   58.77 +            pk_name = self._pk_field.name
   58.78 +            raw_pk_value = form._raw_value(pk_name)
   58.79 +            pk_value = form.fields[pk_name].clean(raw_pk_value).pk
   58.80 +            obj = existing_objects[pk_value]
   58.81 +            if self.can_delete:
   58.82 +                raw_delete_value = form._raw_value(DELETION_FIELD_NAME)
   58.83 +                should_delete = form.fields[DELETION_FIELD_NAME].clean(raw_delete_value)
   58.84 +                if should_delete:
   58.85 +                    self.deleted_objects.append(obj)
   58.86 +                    obj.delete()
   58.87 +                    continue
   58.88 +            if form.changed_data:
   58.89 +                self.changed_objects.append((obj, form.changed_data))
   58.90 +                saved_instances.append(self.save_existing(form, obj, commit=commit))
   58.91 +                if not commit:
   58.92 +                    self.saved_forms.append(form)
   58.93          return saved_instances
   58.94  
   58.95      def save_new_objects(self, commit=True):
   58.96 @@ -429,8 +450,11 @@
   58.97                  continue
   58.98              # If someone has marked an add form for deletion, don't save the
   58.99              # object.
  58.100 -            if self.can_delete and form.cleaned_data[DELETION_FIELD_NAME]:
  58.101 -                continue
  58.102 +            if self.can_delete:
  58.103 +                raw_delete_value = form._raw_value(DELETION_FIELD_NAME)
  58.104 +                should_delete = form.fields[DELETION_FIELD_NAME].clean(raw_delete_value)
  58.105 +                if should_delete:
  58.106 +                    continue
  58.107              self.new_objects.append(self.save_new(form, commit=commit))
  58.108              if not commit:
  58.109                  self.saved_forms.append(form)
  58.110 @@ -438,10 +462,23 @@
  58.111  
  58.112      def add_fields(self, form, index):
  58.113          """Add a hidden field for the object's primary key."""
  58.114 -        from django.db.models import AutoField
  58.115 +        from django.db.models import AutoField, OneToOneField, ForeignKey
  58.116          self._pk_field = pk = self.model._meta.pk
  58.117 -        if pk.auto_created or isinstance(pk, AutoField):
  58.118 -            form.fields[self._pk_field.name] = IntegerField(required=False, widget=HiddenInput)
  58.119 +        # If a pk isn't editable, then it won't be on the form, so we need to
  58.120 +        # add it here so we can tell which object is which when we get the
  58.121 +        # data back. Generally, pk.editable should be false, but for some
  58.122 +        # reason, auto_created pk fields and AutoField's editable attribute is
  58.123 +        # True, so check for that as well.
  58.124 +        if (not pk.editable) or (pk.auto_created or isinstance(pk, AutoField)):
  58.125 +            try:
  58.126 +                pk_value = self.get_queryset()[index].pk
  58.127 +            except IndexError:
  58.128 +                pk_value = None
  58.129 +            if isinstance(pk, OneToOneField) or isinstance(pk, ForeignKey):
  58.130 +                qs = pk.rel.to._default_manager.get_query_set()
  58.131 +            else:
  58.132 +                qs = self.model._default_manager.get_query_set()
  58.133 +            form.fields[self._pk_field.name] = ModelChoiceField(qs, initial=pk_value, required=False, widget=HiddenInput)
  58.134          super(BaseModelFormSet, self).add_fields(form, index)
  58.135  
  58.136  def modelformset_factory(model, form=ModelForm, formfield_callback=lambda f: f.formfield(),
  58.137 @@ -477,11 +514,15 @@
  58.138          super(BaseInlineFormSet, self).__init__(data, files, prefix=prefix,
  58.139                                                  queryset=qs)
  58.140  
  58.141 -    def _construct_forms(self):
  58.142 +    def initial_form_count(self):
  58.143          if self.save_as_new:
  58.144 -            self._total_form_count = self._initial_form_count
  58.145 -            self._initial_form_count = 0
  58.146 -        super(BaseInlineFormSet, self)._construct_forms()
  58.147 +            return 0
  58.148 +        return super(BaseInlineFormSet, self).initial_form_count()
  58.149 +
  58.150 +    def total_form_count(self):
  58.151 +        if self.save_as_new:
  58.152 +            return super(BaseInlineFormSet, self).initial_form_count()
  58.153 +        return super(BaseInlineFormSet, self).total_form_count()
  58.154  
  58.155      def _construct_form(self, i, **kwargs):
  58.156          form = super(BaseInlineFormSet, self)._construct_form(i, **kwargs)
  58.157 @@ -498,21 +539,26 @@
  58.158      get_default_prefix = classmethod(get_default_prefix)
  58.159  
  58.160      def save_new(self, form, commit=True):
  58.161 -        fk_attname = self.fk.get_attname()
  58.162 -        kwargs = {fk_attname: self.instance.pk}
  58.163 -        new_obj = self.model(**kwargs)
  58.164 -        if fk_attname == self._pk_field.attname or self._pk_field.auto_created:
  58.165 -            exclude =  [self._pk_field.name]
  58.166 -        else:
  58.167 -            exclude = []
  58.168 -        return save_instance(form, new_obj, exclude=exclude, commit=commit)
  58.169 +        # Use commit=False so we can assign the parent key afterwards, then
  58.170 +        # save the object.
  58.171 +        obj = form.save(commit=False)
  58.172 +        setattr(obj, self.fk.get_attname(), self.instance.pk)
  58.173 +        obj.save()
  58.174 +        # form.save_m2m() can be called via the formset later on if commit=False
  58.175 +        if commit and hasattr(form, 'save_m2m'):
  58.176 +            form.save_m2m()
  58.177 +        return obj
  58.178  
  58.179      def add_fields(self, form, index):
  58.180          super(BaseInlineFormSet, self).add_fields(form, index)
  58.181          if self._pk_field == self.fk:
  58.182              form.fields[self._pk_field.name] = InlineForeignKeyField(self.instance, pk_field=True)
  58.183          else:
  58.184 -            form.fields[self.fk.name] = InlineForeignKeyField(self.instance, label=form.fields[self.fk.name].label)
  58.185 +            # The foreign key field might not be on the form, so we poke at the
  58.186 +            # Model field to get the label, since we need that for error messages.
  58.187 +            form.fields[self.fk.name] = InlineForeignKeyField(self.instance,
  58.188 +                label=getattr(form.fields.get(self.fk.name), 'label', capfirst(self.fk.verbose_name))
  58.189 +            )
  58.190  
  58.191  def _get_foreign_key(parent_model, model, fk_name=None):
  58.192      """
  58.193 @@ -620,8 +666,6 @@
  58.194          # ensure the we compare the values as equal types.
  58.195          if force_unicode(value) != force_unicode(self.parent_instance.pk):
  58.196              raise ValidationError(self.error_messages['invalid_choice'])
  58.197 -        if self.pk_field:
  58.198 -            return self.parent_instance.pk
  58.199          return self.parent_instance
  58.200  
  58.201  class ModelChoiceIterator(object):
  58.202 @@ -729,6 +773,7 @@
  58.203          'list': _(u'Enter a list of values.'),
  58.204          'invalid_choice': _(u'Select a valid choice. %s is not one of the'
  58.205                              u' available choices.'),
  58.206 +        'invalid_pk_value': _(u'"%s" is not a valid value for a primary key.')
  58.207      }
  58.208  
  58.209      def __init__(self, queryset, cache_choices=False, required=True,
  58.210 @@ -751,6 +796,8 @@
  58.211                  obj = self.queryset.get(pk=val)
  58.212              except self.queryset.model.DoesNotExist:
  58.213                  raise ValidationError(self.error_messages['invalid_choice'] % val)
  58.214 +            except ValueError:
  58.215 +                raise ValidationError(self.error_messages['invalid_pk_value'] % val)
  58.216              else:
  58.217                  final_values.append(obj)
  58.218          return final_values
    59.1 --- a/django/forms/widgets.py	Sat Mar 28 12:05:48 2009 -0500
    59.2 +++ b/django/forms/widgets.py	Wed Apr 01 13:05:19 2009 -0500
    59.3 @@ -422,7 +422,12 @@
    59.4  
    59.5      def value_from_datadict(self, data, files, name):
    59.6          value = data.get(name, None)
    59.7 -        return {u'2': True, u'3': False, True: True, False: False}.get(value, None)
    59.8 +        return {u'2': True, 
    59.9 +                True: True, 
   59.10 +                'True': True, 
   59.11 +                u'3': False, 
   59.12 +                'False': False, 
   59.13 +                False: False}.get(value, None)
   59.14  
   59.15      def _has_changed(self, initial, data):
   59.16          # Sometimes data or initial could be None or u'' which should be the
    60.1 --- a/django/http/__init__.py	Sat Mar 28 12:05:48 2009 -0500
    60.2 +++ b/django/http/__init__.py	Wed Apr 01 13:05:19 2009 -0500
    60.3 @@ -189,7 +189,7 @@
    60.4          for key, value in dict.items(self):
    60.5              dict.__setitem__(result, copy.deepcopy(key, memo), copy.deepcopy(value, memo))
    60.6          return result
    60.7 -
    60.8 +    
    60.9      def setlist(self, key, list_):
   60.10          self._assert_mutable()
   60.11          key = str_to_unicode(key, self.encoding)
    61.1 --- a/django/http/multipartparser.py	Sat Mar 28 12:05:48 2009 -0500
    61.2 +++ b/django/http/multipartparser.py	Wed Apr 01 13:05:19 2009 -0500
    61.3 @@ -34,8 +34,6 @@
    61.4  
    61.5      ``MultiValueDict.parse()`` reads the input stream in ``chunk_size`` chunks
    61.6      and returns a tuple of ``(MultiValueDict(POST), MultiValueDict(FILES))``. If
    61.7 -    ``file_upload_dir`` is defined files will be streamed to temporary files in
    61.8 -    that directory.
    61.9      """
   61.10      def __init__(self, META, input_data, upload_handlers, encoding=None):
   61.11          """
   61.12 @@ -44,7 +42,7 @@
   61.13          :META:
   61.14              The standard ``META`` dictionary in Django request objects.
   61.15          :input_data:
   61.16 -            The raw post data, as a bytestring.
   61.17 +            The raw post data, as a file-like object.
   61.18          :upload_handler:
   61.19              An UploadHandler instance that performs operations on the uploaded
   61.20              data.
    62.1 --- a/django/template/context.py	Sat Mar 28 12:05:48 2009 -0500
    62.2 +++ b/django/template/context.py	Wed Apr 01 13:05:19 2009 -0500
    62.3 @@ -1,4 +1,3 @@
    62.4 -from django.conf import settings
    62.5  from django.core.exceptions import ImproperlyConfigured
    62.6  from django.utils.importlib import import_module
    62.7  
    62.8 @@ -71,6 +70,7 @@
    62.9  # This is a function rather than module-level procedural code because we only
   62.10  # want it to execute if somebody uses RequestContext.
   62.11  def get_standard_processors():
   62.12 +    from django.conf import settings
   62.13      global _standard_context_processors
   62.14      if _standard_context_processors is None:
   62.15          processors = []
    63.1 --- a/django/template/defaultfilters.py	Sat Mar 28 12:05:48 2009 -0500
    63.2 +++ b/django/template/defaultfilters.py	Wed Apr 01 13:05:19 2009 -0500
    63.3 @@ -149,7 +149,9 @@
    63.4      except InvalidOperation:
    63.5          if input_val in special_floats:
    63.6              return input_val
    63.7 -        else:
    63.8 +        try:
    63.9 +            d = Decimal(force_unicode(float(text)))
   63.10 +        except (ValueError, InvalidOperation, TypeError, UnicodeEncodeError):
   63.11              return u''
   63.12      try:
   63.13          p = int(arg)
   63.14 @@ -515,12 +517,18 @@
   63.15  
   63.16  def length(value):
   63.17      """Returns the length of the value - useful for lists."""
   63.18 -    return len(value)
   63.19 +    try:
   63.20 +        return len(value)
   63.21 +    except (ValueError, TypeError):
   63.22 +        return ''
   63.23  length.is_safe = True
   63.24  
   63.25  def length_is(value, arg):
   63.26      """Returns a boolean of whether the value's length is the argument."""
   63.27 -    return len(value) == int(arg)
   63.28 +    try:
   63.29 +        return len(value) == int(arg)
   63.30 +    except (ValueError, TypeError):
   63.31 +        return ''
   63.32  length_is.is_safe = False
   63.33  
   63.34  def random(value):
    64.1 --- a/django/template/loader_tags.py	Sat Mar 28 12:05:48 2009 -0500
    64.2 +++ b/django/template/loader_tags.py	Wed Apr 01 13:05:19 2009 -0500
    64.3 @@ -158,7 +158,7 @@
    64.4      name of the parent template to extend (if it evaluates to a string) or as
    64.5      the parent tempate itelf (if it evaluates to a Template object).
    64.6      """
    64.7 -    bits = token.contents.split()
    64.8 +    bits = token.split_contents()
    64.9      if len(bits) != 2:
   64.10          raise TemplateSyntaxError, "'%s' takes one argument" % bits[0]
   64.11      parent_name, parent_name_expr = None, None
   64.12 @@ -179,7 +179,7 @@
   64.13  
   64.14          {% include "foo/some_include" %}
   64.15      """
   64.16 -    bits = token.contents.split()
   64.17 +    bits = token.split_contents()
   64.18      if len(bits) != 2:
   64.19          raise TemplateSyntaxError, "%r tag takes one argument: the name of the template to be included" % bits[0]
   64.20      path = bits[1]
    65.1 --- a/django/test/client.py	Sat Mar 28 12:05:48 2009 -0500
    65.2 +++ b/django/test/client.py	Wed Apr 01 13:05:19 2009 -0500
    65.3 @@ -431,12 +431,14 @@
    65.4  
    65.5      def logout(self):
    65.6          """
    65.7 -        Removes the authenticated user's cookies.
    65.8 +        Removes the authenticated user's cookies and session object.
    65.9  
   65.10          Causes the authenticated user to be logged out.
   65.11          """
   65.12          session = import_module(settings.SESSION_ENGINE).SessionStore()
   65.13 -        session.delete(session_key=self.cookies[settings.SESSION_COOKIE_NAME].value)
   65.14 +        session_cookie = self.cookies.get(settings.SESSION_COOKIE_NAME)
   65.15 +        if session_cookie:
   65.16 +            session.delete(session_key=session_cookie.value)
   65.17          self.cookies = SimpleCookie()
   65.18  
   65.19      def _handle_redirects(self, response):
    66.1 --- a/django/test/testcases.py	Sat Mar 28 12:05:48 2009 -0500
    66.2 +++ b/django/test/testcases.py	Wed Apr 01 13:05:19 2009 -0500
    66.3 @@ -34,7 +34,7 @@
    66.4  real_savepoint_commit = transaction.savepoint_commit
    66.5  real_savepoint_rollback = transaction.savepoint_rollback
    66.6  
    66.7 -def nop(x=None):
    66.8 +def nop(*args, **kwargs):
    66.9      return
   66.10  
   66.11  def disable_transaction_methods():
    67.1 --- a/django/utils/cache.py	Sat Mar 28 12:05:48 2009 -0500
    67.2 +++ b/django/utils/cache.py	Wed Apr 01 13:05:19 2009 -0500
    67.3 @@ -146,6 +146,11 @@
    67.4      return 'views.decorators.cache.cache_page.%s.%s.%s' % (
    67.5                 key_prefix, iri_to_uri(request.path), ctx.hexdigest())
    67.6  
    67.7 +def _generate_cache_header_key(key_prefix, request):
    67.8 +    """Returns a cache key for the header cache."""
    67.9 +    return 'views.decorators.cache.cache_header.%s.%s' % (
   67.10 +        key_prefix, iri_to_uri(request.path))
   67.11 +
   67.12  def get_cache_key(request, key_prefix=None):
   67.13      """
   67.14      Returns a cache key based on the request path. It can be used in the
   67.15 @@ -158,8 +163,7 @@
   67.16      """
   67.17      if key_prefix is None:
   67.18          key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
   67.19 -    cache_key = 'views.decorators.cache.cache_header.%s.%s' % (
   67.20 -                    key_prefix, iri_to_uri(request.path))
   67.21 +    cache_key = _generate_cache_header_key(key_prefix, request)
   67.22      headerlist = cache.get(cache_key, None)
   67.23      if headerlist is not None:
   67.24          return _generate_cache_key(request, headerlist, key_prefix)
   67.25 @@ -183,8 +187,7 @@
   67.26          key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
   67.27      if cache_timeout is None:
   67.28          cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
   67.29 -    cache_key = 'views.decorators.cache.cache_header.%s.%s' % (
   67.30 -                    key_prefix, iri_to_uri(request.path))
   67.31 +    cache_key = _generate_cache_header_key(key_prefix, request)
   67.32      if response.has_header('Vary'):
   67.33          headerlist = ['HTTP_'+header.upper().replace('-', '_')
   67.34                        for header in cc_delim_re.split(response['Vary'])]
    68.1 --- a/django/utils/datastructures.py	Sat Mar 28 12:05:48 2009 -0500
    68.2 +++ b/django/utils/datastructures.py	Wed Apr 01 13:05:19 2009 -0500
    68.3 @@ -222,7 +222,18 @@
    68.4              dict.__setitem__(result, copy.deepcopy(key, memo),
    68.5                               copy.deepcopy(value, memo))
    68.6          return result
    68.7 -
    68.8 +    
    68.9 +    def __getstate__(self):
   68.10 +        obj_dict = self.__dict__.copy()
   68.11 +        obj_dict['_data'] = dict([(k, self.getlist(k)) for k in self])
   68.12 +        return obj_dict
   68.13 +    
   68.14 +    def __setstate__(self, obj_dict):
   68.15 +        data = obj_dict.pop('_data', {})
   68.16 +        for k, v in data.items():
   68.17 +            self.setlist(k, v)
   68.18 +        self.__dict__.update(obj_dict)
   68.19 +        
   68.20      def get(self, key, default=None):
   68.21          """
   68.22          Returns the last data value for the passed key. If key doesn't exist
   68.23 @@ -283,10 +294,19 @@
   68.24          """Returns a list of (key, list) pairs."""
   68.25          return super(MultiValueDict, self).items()
   68.26  
   68.27 +    def iterlists(self):
   68.28 +        """Yields (key, list) pairs."""
   68.29 +        return super(MultiValueDict, self).iteritems()
   68.30 +
   68.31      def values(self):
   68.32          """Returns a list of the last value on every key list."""
   68.33          return [self[key] for key in self.keys()]
   68.34 -
   68.35 +        
   68.36 +    def itervalues(self):
   68.37 +        """Yield the last value on every key list."""
   68.38 +        for key in self.iterkeys():
   68.39 +            yield self[key]
   68.40 +    
   68.41      def copy(self):
   68.42          """Returns a copy of this object."""
   68.43          return self.__deepcopy__()
    69.1 --- a/django/utils/html.py	Sat Mar 28 12:05:48 2009 -0500
    69.2 +++ b/django/utils/html.py	Wed Apr 01 13:05:19 2009 -0500
    69.3 @@ -46,9 +46,9 @@
    69.4      value = re.sub(r'\r\n|\r|\n', '\n', force_unicode(value)) # normalize newlines
    69.5      paras = re.split('\n{2,}', value)
    69.6      if autoescape:
    69.7 -        paras = [u'<p>%s</p>' % escape(p.strip()).replace('\n', '<br />') for p in paras]
    69.8 +        paras = [u'<p>%s</p>' % escape(p).replace('\n', '<br />') for p in paras]
    69.9      else:
   69.10 -        paras = [u'<p>%s</p>' % p.strip().replace('\n', '<br />') for p in paras]
   69.11 +        paras = [u'<p>%s</p>' % p.replace('\n', '<br />') for p in paras]
   69.12      return u'\n\n'.join(paras)
   69.13  linebreaks = allow_lazy(linebreaks, unicode)
   69.14  
    70.1 --- a/django/utils/text.py	Sat Mar 28 12:05:48 2009 -0500
    70.2 +++ b/django/utils/text.py	Wed Apr 01 13:05:19 2009 -0500
    70.3 @@ -219,27 +219,27 @@
    70.4  smart_split = allow_lazy(smart_split, unicode)
    70.5  
    70.6  def _replace_entity(match):
    70.7 -     text = match.group(1)
    70.8 -     if text[0] == u'#':
    70.9 -         text = text[1:]
   70.10 -         try:
   70.11 -             if text[0] in u'xX':
   70.12 -                 c = int(text[1:], 16)
   70.13 -             else:
   70.14 -                 c = int(text)
   70.15 -             return unichr(c)
   70.16 -         except ValueError:
   70.17 -             return match.group(0)
   70.18 -     else:
   70.19 -         try:
   70.20 -             return unichr(name2codepoint[text])
   70.21 -         except (ValueError, KeyError):
   70.22 -             return match.group(0)
   70.23 +    text = match.group(1)
   70.24 +    if text[0] == u'#':
   70.25 +        text = text[1:]
   70.26 +        try:
   70.27 +            if text[0] in u'xX':
   70.28 +                c = int(text[1:], 16)
   70.29 +            else:
   70.30 +                c = int(text)
   70.31 +            return unichr(c)
   70.32 +        except ValueError:
   70.33 +            return match.group(0)
   70.34 +    else:
   70.35 +        try:
   70.36 +            return unichr(name2codepoint[text])
   70.37 +        except (ValueError, KeyError):
   70.38 +            return match.group(0)
   70.39  
   70.40  _entity_re = re.compile(r"&(#?[xX]?(?:[0-9a-fA-F]+|\w{1,8}));")
   70.41  
   70.42  def unescape_entities(text):
   70.43 -     return _entity_re.sub(_replace_entity, text)
   70.44 +    return _entity_re.sub(_replace_entity, text)
   70.45  unescape_entities = allow_lazy(unescape_entities, unicode)
   70.46  
   70.47  def unescape_string_literal(s):
   70.48 @@ -261,4 +261,3 @@
   70.49      quote = s[0]
   70.50      return s[1:-1].replace(r'\%s' % quote, quote).replace(r'\\', '\\')
   70.51  unescape_string_literal = allow_lazy(unescape_string_literal)
   70.52 -
    71.1 --- a/django/utils/timesince.py	Sat Mar 28 12:05:48 2009 -0500
    71.2 +++ b/django/utils/timesince.py	Wed Apr 01 13:05:19 2009 -0500
    71.3 @@ -25,9 +25,11 @@
    71.4        (60 * 60, lambda n: ungettext('hour', 'hours', n)),
    71.5        (60, lambda n: ungettext('minute', 'minutes', n))
    71.6      )
    71.7 -    # Convert datetime.date to datetime.datetime for comparison
    71.8 -    if d.__class__ is not datetime.datetime:
    71.9 +    # Convert datetime.date to datetime.datetime for comparison.
   71.10 +    if not isinstance(d, datetime.datetime):
   71.11          d = datetime.datetime(d.year, d.month, d.day)
   71.12 +    if now and not isinstance(now, datetime.datetime):
   71.13 +        now = datetime.datetime(now.year, now.month, now.day)
   71.14  
   71.15      if not now:
   71.16          if d.tzinfo:
    72.1 --- a/django/views/debug.py	Sat Mar 28 12:05:48 2009 -0500
    72.2 +++ b/django/views/debug.py	Wed Apr 01 13:05:19 2009 -0500
    72.3 @@ -611,6 +611,28 @@
    72.4    {% else %}
    72.5      <p>No POST data</p>
    72.6    {% endif %}
    72.7 +  <h3 id="files-info">FILES</h3>
    72.8 +  {% if request.FILES %}
    72.9 +    <table class="req">
   72.10 +        <thead>
   72.11 +            <tr>
   72.12 +                <th>Variable</th>
   72.13 +                <th>Value</th>
   72.14 +            </tr>
   72.15 +        </thead>
   72.16 +        <tbody>
   72.17 +            {% for var in request.FILES.items %}
   72.18 +                <tr>
   72.19 +                    <td>{{ var.0 }}</td>
   72.20 +                    <td class="code"><div>{{ var.1|pprint }}</div></td>
   72.21 +                </tr>
   72.22 +            {% endfor %}
   72.23 +        </tbody>
   72.24 +    </table>
   72.25 +  {% else %}
   72.26 +    <p>No FILES data</p>
   72.27 +  {% endif %}
   72.28 +  
   72.29  
   72.30    <h3 id="cookie-info">COOKIES</h3>
   72.31    {% if request.COOKIES %}
    73.1 --- a/docs/conf.py	Sat Mar 28 12:05:48 2009 -0500
    73.2 +++ b/docs/conf.py	Wed Apr 01 13:05:19 2009 -0500
    73.3 @@ -70,6 +70,11 @@
    73.4  # The name of the Pygments (syntax highlighting) style to use.
    73.5  pygments_style = 'trac'
    73.6  
    73.7 +# Sphinx will recurse into subversion configuration folders and try to read  
    73.8 +# any document file within. These should be ignored. 
    73.9 +# Note: exclude_dirnames is new in Sphinx 0.5 
   73.10 +exclude_dirnames = ['.svn']
   73.11 +
   73.12  # Options for HTML output
   73.13  # -----------------------
   73.14  
    74.1 --- a/docs/faq/usage.txt	Sat Mar 28 12:05:48 2009 -0500
    74.2 +++ b/docs/faq/usage.txt	Wed Apr 01 13:05:19 2009 -0500
    74.3 @@ -8,8 +8,8 @@
    74.4  
    74.5  Make sure that:
    74.6  
    74.7 -    * The environment variable DJANGO_SETTINGS_MODULE is set to a fully-qualified
    74.8 -      Python module (i.e. "mysite.settings").
    74.9 +    * The environment variable DJANGO_SETTINGS_MODULE is set to a
   74.10 +      fully-qualified Python module (i.e. "mysite.settings").
   74.11  
   74.12      * Said module is on ``sys.path`` (``import mysite.settings`` should work).
   74.13  
   74.14 @@ -45,24 +45,35 @@
   74.15  How do I use image and file fields?
   74.16  -----------------------------------
   74.17  
   74.18 -Using a :class:`~django.db.models.FileField` or an 
   74.19 +Using a :class:`~django.db.models.FileField` or an
   74.20  :class:`~django.db.models.ImageField` in a model takes a few steps:
   74.21  
   74.22 -    #. In your settings file, you'll need to define :setting:`MEDIA_ROOT` as the
   74.23 -       full path to a directory where you'd like Django to store uploaded files.
   74.24 -       (For performance, these files are not stored in the database.) Define
   74.25 -       :setting:`MEDIA_URL` as the base public URL of that directory. Make sure
   74.26 -       that this directory is writable by the Web server's user account.
   74.27 +    #. In your settings file, you'll need to define :setting:`MEDIA_ROOT` as
   74.28 +       the full path to a directory where you'd like Django to store uploaded
   74.29 +       files. (For performance, these files are not stored in the database.)
   74.30 +       Define :setting:`MEDIA_URL` as the base public URL of that directory.
   74.31 +       Make sure that this directory is writable by the Web server's user
   74.32 +       account.
   74.33  
   74.34 -    #. Add the :class:`~django.db.models.FileField` or 
   74.35 -       :class:`~django.db.models.ImageField` to your model, making sure to 
   74.36 -       define the :attr:`~django.db.models.FileField.upload_to` option to tell 
   74.37 -       Django to which subdirectory of :setting:`MEDIA_ROOT` it should upload 
   74.38 +    #. Add the :class:`~django.db.models.FileField` or
   74.39 +       :class:`~django.db.models.ImageField` to your model, making sure to
   74.40 +       define the :attr:`~django.db.models.FileField.upload_to` option to tell
   74.41 +       Django to which subdirectory of :setting:`MEDIA_ROOT` it should upload
   74.42         files.
   74.43  
   74.44 -    #. All that will be stored in your database is a path to the file 
   74.45 +    #. All that will be stored in your database is a path to the file
   74.46         (relative to :setting:`MEDIA_ROOT`). You'll most likely want to use the
   74.47         convenience :attr:`~django.core.files.File.url` attribute provided by
   74.48         Django. For example, if your :class:`~django.db.models.ImageField` is
   74.49         called ``mug_shot``, you can get the absolute URL to your image in a
   74.50         template with ``{{ object.mug_shot.url }}``.
   74.51 +
   74.52 +How do I make a variable available to all my templates?
   74.53 +-------------------------------------------------------
   74.54 +
   74.55 +Sometimes your templates just all need the same thing. A common example would
   74.56 +be dynamically-generated menus. At first glance, it seems logical to simply
   74.57 +add a common dictionary to the template context.
   74.58 +
   74.59 +The correct solution is to use a ``RequestContext``. Details on how to do this
   74.60 +are here: :ref:`subclassing-context-requestcontext`.
    75.1 --- a/docs/glossary.txt	Sat Mar 28 12:05:48 2009 -0500
    75.2 +++ b/docs/glossary.txt	Wed Apr 01 13:05:19 2009 -0500
    75.3 @@ -13,8 +13,8 @@
    75.4          See :ref:`topics-db-models`.
    75.5  
    75.6      generic view
    75.7 -        A higher-order :term:`view` function that abstracts common idioms and patterns
    75.8 -        found in view development and abstracts them.
    75.9 +        A higher-order :term:`view` function that provides an abstract/generic
   75.10 +        implementation of a common idiom or pattern found in view development.
   75.11          
   75.12          See :ref:`ref-generic-views`.
   75.13  
   75.14 @@ -71,8 +71,9 @@
   75.15          the last bit (``spring``) is the slug.
   75.16  
   75.17      template
   75.18 -        A chunk of text that separates the presentation of a document from its
   75.19 -        data.
   75.20 +        A chunk of text that acts as formatting for representing data. A
   75.21 +        template helps to abstract the presentation of data from the data
   75.22 +        itself.
   75.23          
   75.24          See :ref:`topics-templates`.
   75.25          
    76.1 --- a/docs/howto/custom-model-fields.txt	Sat Mar 28 12:05:48 2009 -0500
    76.2 +++ b/docs/howto/custom-model-fields.txt	Wed Apr 01 13:05:19 2009 -0500
    76.3 @@ -45,7 +45,7 @@
    76.4              self.east = east
    76.5              self.south = south
    76.6              self.west = west
    76.7 -        
    76.8 +
    76.9          # ... (other possibly useful methods omitted) ...
   76.10  
   76.11  .. _Bridge: http://en.wikipedia.org/wiki/Contract_bridge
   76.12 @@ -198,15 +198,13 @@
   76.13      * :attr:`~django.db.models.Field.blank`
   76.14      * :attr:`~django.db.models.Field.null`
   76.15      * :attr:`~django.db.models.Field.db_index`
   76.16 -    * :attr:`~django.db.models.Field.core`
   76.17      * :attr:`~django.db.models.Field.rel`: Used for related fields (like
   76.18        :class:`ForeignKey`). For advanced use only.
   76.19      * :attr:`~django.db.models.Field.default`
   76.20      * :attr:`~django.db.models.Field.editable`
   76.21 -    * :attr:`~django.db.models.Field.serialize`: If ``False``, the field will 
   76.22 +    * :attr:`~django.db.models.Field.serialize`: If ``False``, the field will
   76.23        not be serialized when the model is passed to Django's :ref:`serializers
   76.24        <topics-serialization>`. Defaults to ``True``.
   76.25 -    * :attr:`~django.db.models.Field.prepopulate_from`
   76.26      * :attr:`~django.db.models.Field.unique_for_date`
   76.27      * :attr:`~django.db.models.Field.unique_for_month`
   76.28      * :attr:`~django.db.models.Field.unique_for_year`
   76.29 @@ -216,6 +214,9 @@
   76.30      * :attr:`~django.db.models.Field.db_tablespace`: Currently only used with
   76.31        the Oracle backend and only for index creation. You can usually ignore
   76.32        this option.
   76.33 +    * :attr:`~django.db.models.Field.auto_created`: True if the field was
   76.34 +      automatically created, as for the `OneToOneField` used by model
   76.35 +      inheritance. For advanced use only.
   76.36  
   76.37  All of the options without an explanation in the above list have the same
   76.38  meaning they do for normal Django fields. See the :ref:`field documentation
   76.39 @@ -254,7 +255,7 @@
   76.40  Useful methods
   76.41  --------------
   76.42  
   76.43 -Once you've created your :class:`~django.db.models.Field` subclass and set up up
   76.44 +Once you've created your :class:`~django.db.models.Field` subclass and set up
   76.45  the ``__metaclass__``, you might consider overriding a few standard methods,
   76.46  depending on your field's behavior. The list of methods below is in
   76.47  approximately decreasing order of importance, so start from the top.
   76.48 @@ -419,9 +420,9 @@
   76.49  
   76.50  Same as the above, but called when the Field value must be *saved* to the
   76.51  database. As the default implementation just calls ``get_db_prep_value``, you
   76.52 -shouldn't need to implement this method unless your custom field need a special
   76.53 -conversion when being saved that is not the same as the used for normal query
   76.54 -parameters (which is implemented by ``get_db_prep_value``).
   76.55 +shouldn't need to implement this method unless your custom field needs a
   76.56 +special conversion when being saved that is not the same as the conversion used
   76.57 +for normal query parameters (which is implemented by ``get_db_prep_value``).
   76.58  
   76.59  Preprocessing values before saving
   76.60  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   76.61 @@ -522,7 +523,7 @@
   76.62              defaults.update(kwargs)
   76.63              return super(HandField, self).formfield(**defaults)
   76.64  
   76.65 -This assumes we're imported a ``MyFormField`` field class (which has its own
   76.66 +This assumes we've imported a ``MyFormField`` field class (which has its own
   76.67  default widget). This document doesn't cover the details of writing custom form
   76.68  fields.
   76.69  
    77.1 --- a/docs/howto/deployment/fastcgi.txt	Sat Mar 28 12:05:48 2009 -0500
    77.2 +++ b/docs/howto/deployment/fastcgi.txt	Wed Apr 01 13:05:19 2009 -0500
    77.3 @@ -1,8 +1,8 @@
    77.4  .. _howto-deployment-fastcgi:
    77.5  
    77.6 -===========================================
    77.7 -How to use Django with FastCGI, SCGI or AJP
    77.8 -===========================================
    77.9 +============================================
   77.10 +How to use Django with FastCGI, SCGI, or AJP
   77.11 +============================================
   77.12  
   77.13  .. highlight:: bash
   77.14  
   77.15 @@ -288,6 +288,19 @@
   77.16  specifying multiple entries in the ``fastcgi.server`` directive. Add one
   77.17  FastCGI host for each.
   77.18  
   77.19 +Cherokee setup
   77.20 +==============
   77.21 +
   77.22 +Cherokee is a very fast, flexible and easy to configure Web Server. It
   77.23 +supports the widespread technologies nowadays: FastCGI, SCGI, PHP, CGI, SSI,
   77.24 +TLS and SSL encrypted connections, Virtual hosts, Authentication, on the fly
   77.25 +encoding, Load Balancing, Apache compatible log files, Data Base Balancer,
   77.26 +Reverse HTTP Proxy and much more.
   77.27 +
   77.28 +The Cherokee project provides a documentation to `setting up Django`_ with Cherokee.
   77.29 +
   77.30 +.. _setting up Django: http://www.cherokee-project.com/doc/cookbook_django.html
   77.31 +
   77.32  Running Django on a shared-hosting provider with Apache
   77.33  =======================================================
   77.34  
   77.35 @@ -379,5 +392,3 @@
   77.36  As an example of how to use it, if your Django configuration is serving all of
   77.37  the URLs under ``'/'`` and you wanted to use this setting, you would set
   77.38  ``FORCE_SCRIPT_NAME = ''`` in your settings file.
   77.39 -
   77.40 -
    78.1 --- a/docs/howto/deployment/index.txt	Sat Mar 28 12:05:48 2009 -0500
    78.2 +++ b/docs/howto/deployment/index.txt	Wed Apr 01 13:05:19 2009 -0500
    78.3 @@ -11,23 +11,18 @@
    78.4  .. toctree::
    78.5     :maxdepth: 1
    78.6     
    78.7 +   modwsgi
    78.8     modpython
    78.9 +   modwsgi
   78.10     fastcgi
   78.11     
   78.12 -:ref:`Deploying under mod_python <howto-deployment-modpython>` is the
   78.13 -recommended deployment method; start there if you're not sure which path you'd
   78.14 -like to go down.
   78.15 +If you're new to deploying Django and/or Python, we'd recommend you try
   78.16 +:ref:`mod_wsgi <howto-deployment-modwsgi>` first. In most cases it'll be the easiest,
   78.17 +fastest, and most stable deployment choice.
   78.18  
   78.19  .. seealso::
   78.20  
   78.21      * `Chapter 20 of The Django Book`_ discusses deployment and especially
   78.22        scaling in more detail.
   78.23        
   78.24 -    * `mod_wsgi`_ is a newcomer to the Python deployment world, but it's rapidly
   78.25 -      gaining traction. Currently there's a few hoops you have to jump through to
   78.26 -      `use mod_wsgi with Django`_, but mod_wsgi tends to get rave reviews from
   78.27 -      those who use it.
   78.28 -
   78.29  .. _chapter 20 of the django book: http://djangobook.com/en/1.0/chapter20/
   78.30 -.. _mod_wsgi: http://code.google.com/p/modwsgi/
   78.31 -.. _use mod_wsgi with Django: http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango
   78.32 \ No newline at end of file
    79.1 --- a/docs/howto/deployment/modpython.txt	Sat Mar 28 12:05:48 2009 -0500
    79.2 +++ b/docs/howto/deployment/modpython.txt	Wed Apr 01 13:05:19 2009 -0500
    79.3 @@ -17,8 +17,8 @@
    79.4  Django requires Apache 2.x and mod_python 3.x, and you should use Apache's
    79.5  `prefork MPM`_, as opposed to the `worker MPM`_.
    79.6  
    79.7 -You may also be interested in :ref:`How to use Django with FastCGI, SCGI or AJP
    79.8 -<howto-deployment-fastcgi>` (which also covers SCGI and AJP).
    79.9 +You may also be interested in :ref:`How to use Django with FastCGI, SCGI, or
   79.10 +AJP <howto-deployment-fastcgi>`.
   79.11  
   79.12  .. _Apache: http://httpd.apache.org/
   79.13  .. _mod_python: http://www.modpython.org/
   79.14 @@ -38,7 +38,7 @@
   79.15          SetHandler python-program
   79.16          PythonHandler django.core.handlers.modpython
   79.17          SetEnv DJANGO_SETTINGS_MODULE mysite.settings
   79.18 -        PythonOption django.root /mysite        
   79.19 +        PythonOption django.root /mysite
   79.20          PythonDebug On
   79.21      </Location>
   79.22  
   79.23 @@ -58,12 +58,12 @@
   79.24  django.root ...`` line. The value set on that line (the last item) should
   79.25  match the string given in the ``<Location ...>`` directive. The effect of this
   79.26  is that Django will automatically strip the ``/mysite`` string from the front
   79.27 -of any URLs before matching them against your ``URLConf`` patterns. If you
   79.28 -later move your site to live under ``/mysite2``, you will not have to change
   79.29 -anything except the ``django.root`` option in the config file.
   79.30 +of any URLs before matching them against your URLconf patterns. If you later
   79.31 +move your site to live under ``/mysite2``, you will not have to change anything
   79.32 +except the ``django.root`` option in the config file.
   79.33  
   79.34  When using ``django.root`` you should make sure that what's left, after the
   79.35 -prefix has been removed, begins with a slash. Your URLConf patterns that are
   79.36 +prefix has been removed, begins with a slash. Your URLconf patterns that are
   79.37  expecting an initial slash will then work correctly. In the above example,
   79.38  since we want to send things like ``/mysite/admin/`` to ``/admin/``, we need
   79.39  to remove the string ``/mysite`` from the beginning, so that is the
   79.40 @@ -84,7 +84,7 @@
   79.41          SetHandler python-program
   79.42          PythonHandler django.core.handlers.modpython
   79.43          SetEnv DJANGO_SETTINGS_MODULE mysite.settings
   79.44 -        PythonOption django.root /mysite        
   79.45 +        PythonOption django.root /mysite
   79.46          PythonDebug On
   79.47          **PythonPath "['/path/to/project'] + sys.path"**
   79.48      </Location>
   79.49 @@ -215,8 +215,10 @@
   79.50  Django -- for serving media. Here are some good choices:
   79.51  
   79.52      * lighttpd_
   79.53 +    * Nginx_
   79.54      * TUX_
   79.55      * A stripped-down version of Apache_
   79.56 +    * Cherokee_
   79.57  
   79.58  If, however, you have no option but to serve media files on the same Apache
   79.59  ``VirtualHost`` as Django, here's how you can turn off mod_python for a
   79.60 @@ -249,8 +251,10 @@
   79.61  
   79.62  
   79.63  .. _lighttpd: http://www.lighttpd.net/
   79.64 +.. _Nginx: http://wiki.codemongers.com/Main
   79.65  .. _TUX: http://en.wikipedia.org/wiki/TUX_web_server
   79.66  .. _Apache: http://httpd.apache.org/
   79.67 +.. _Cherokee: http://www.cherokee-project.com/
   79.68  
   79.69  .. _howto-deployment-modpython-serving-the-admin-files:
   79.70  
   79.71 @@ -273,7 +277,7 @@
   79.72         document root. This way, all of your Django-related files -- code **and**
   79.73         templates -- stay in one place, and you'll still be able to ``svn
   79.74         update`` your code to get the latest admin templates, if they change.
   79.75 -       
   79.76 +
   79.77      2. Or, copy the admin media files so that they live within your Apache
   79.78         document root.
   79.79  
   79.80 @@ -337,7 +341,7 @@
   79.81      1. It may be because your Python code is importing the "pyexpat" module,
   79.82         which may conflict with the version embedded in Apache. For full
   79.83         information, see `Expat Causing Apache Crash`_.
   79.84 -       
   79.85 +
   79.86      2. It may be because you're running mod_python and mod_php in the same
   79.87         Apache instance, with MySQL as your database backend. In some cases,
   79.88         this causes a known mod_python issue due to version conflicts in PHP and
   79.89 @@ -361,5 +365,3 @@
   79.90  .. _Expat Causing Apache Crash: http://www.dscpl.com.au/articles/modpython-006.html
   79.91  .. _mod_python FAQ entry: http://modpython.org/FAQ/faqw.py?req=show&file=faq02.013.htp
   79.92  .. _Getting mod_python Working: http://www.dscpl.com.au/articles/modpython-001.html
   79.93 -
   79.94 -
    80.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    80.2 +++ b/docs/howto/deployment/modwsgi.txt	Wed Apr 01 13:05:19 2009 -0500
    80.3 @@ -0,0 +1,68 @@
    80.4 +.. _howto-deployment-modwsgi:
    80.5 +
    80.6 +==========================================
    80.7 +How to use Django with Apache and mod_wsgi
    80.8 +==========================================
    80.9 +
   80.10 +Deploying Django with Apache_ and `mod_wsgi`_ is the recommended way to get
   80.11 +Django into production.
   80.12 +
   80.13 +.. _Apache: http://httpd.apache.org/
   80.14 +.. _mod_wsgi: http://code.google.com/p/modwsgi/
   80.15 +
   80.16 +mod_wsgi is an Apache module which can be used to host any Python application
   80.17 +which supports the `Python WSGI interface`_, including Django. Django will work
   80.18 +with any version of Apache which supports mod_wsgi.
   80.19 +
   80.20 +.. _python wsgi interface: http://www.python.org/dev/peps/pep-0333/
   80.21 +
   80.22 +The `official mod_wsgi documentation`_ is fantastic; it's your source for all
   80.23 +the details about how to use mod_wsgi. You'll probably want to start with the
   80.24 +`installation and configuration documentation`_.
   80.25 +
   80.26 +.. _official mod_wsgi documentation: http://code.google.com/p/modwsgi/
   80.27 +.. _installation and configuration documentation: http://code.google.com/p/modwsgi/wiki/InstallationInstructions
   80.28 +
   80.29 +Basic Configuration
   80.30 +===================
   80.31 +
   80.32 +Once you've got mod_wsgi installed and activated, edit your ``httpd.conf`` file
   80.33 +and add::
   80.34 +
   80.35 +    WSGIScriptAlias / /path/to/mysite/apache/django.wsgi
   80.36 +
   80.37 +The first bit aboveis the url you want to be serving your application at (``/``
   80.38 +indicates the root url), and the second is the location of a "WSGI file" -- see
   80.39 +below -- on your system, usually inside of your project. This tells Apache
   80.40 +to serve any request below the given URL using the WSGI application defined by that file.
   80.41 +
   80.42 +Next we'll need to actually create this WSGI application, so create the file
   80.43 +mentioned in the second part of ``WSGIScriptAlias`` and add::
   80.44 +
   80.45 +    import os
   80.46 +    import sys
   80.47 +
   80.48 +    os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
   80.49 +
   80.50 +    import django.core.handlers.wsgi
   80.51 +    application = django.core.handlers.wsgi.WSGIHandler()
   80.52 +
   80.53 +If your project is not on your ``PYTHONPATH`` by default you can add::
   80.54 +
   80.55 +    sys.path.append('/usr/local/django')
   80.56 +
   80.57 +just above the ``import`` line to place your project on the path. Remember to
   80.58 +replace 'mysite.settings' with your correct settings file.
   80.59 +
   80.60 +See the :ref:`Apache/mod_python documentation<howto-deployment-modpython>` for 
   80.61 +directions on serving static media, and the `mod_wsgi documentation`_ for an 
   80.62 +explanation of other directives and configuration options you can use.
   80.63 +
   80.64 +Details
   80.65 +=======
   80.66 +
   80.67 +For more details, see the `mod_wsgi documentation`_, which explains the above in
   80.68 +more detail, and walks through all the various options you've got when deploying
   80.69 +under mod_wsgi.
   80.70 +
   80.71 +.. _mod_wsgi documentation: http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango
   80.72 \ No newline at end of file
    81.1 --- a/docs/howto/jython.txt	Sat Mar 28 12:05:48 2009 -0500
    81.2 +++ b/docs/howto/jython.txt	Wed Apr 01 13:05:19 2009 -0500
    81.3 @@ -17,18 +17,8 @@
    81.4  Installing Jython
    81.5  =================
    81.6  
    81.7 -Django works with Jython versions 2.5 and higher.
    81.8 -
    81.9 -.. warning::
   81.10 -
   81.11 -    As of the writing of this document, a version of Jython compatible with
   81.12 -    Django has not yet been released. The forthcoming 2.5a2+ release will be be
   81.13 -    the first in which Django will work out of the box.
   81.14 -
   81.15 -    In the meantime, you'll need to use the latest development version of Jython
   81.16 -    obtained from Jython's SVN repository.
   81.17 -
   81.18 -Download Jython at http://www.jython.org/.
   81.19 +Django works with Jython versions 2.5b3 and higher. Download Jython at 
   81.20 +http://www.jython.org/.
   81.21  
   81.22  Creating a servlet container
   81.23  ============================
    82.1 --- a/docs/howto/static-files.txt	Sat Mar 28 12:05:48 2009 -0500
    82.2 +++ b/docs/howto/static-files.txt	Wed Apr 01 13:05:19 2009 -0500
    82.3 @@ -10,7 +10,7 @@
    82.4  Django itself doesn't serve static (media) files, such as images, style sheets,
    82.5  or video. It leaves that job to whichever Web server you choose.
    82.6  
    82.7 -The reasoning here is that standard Web servers, such as Apache_ and lighttpd_,
    82.8 +The reasoning here is that standard Web servers, such as Apache_, lighttpd_ and Cherokee_,
    82.9  are much more fine-tuned at serving static files than a Web application
   82.10  framework.
   82.11  
   82.12 @@ -19,6 +19,7 @@
   82.13  
   82.14  .. _Apache: http://httpd.apache.org/
   82.15  .. _lighttpd: http://www.lighttpd.net/
   82.16 +.. _Cherokee: http://www.cherokee-project.com/
   82.17  
   82.18  The big, fat disclaimer
   82.19  =======================
   82.20 @@ -72,6 +73,9 @@
   82.21      (r'^site_media/(?P<path>.*)$', 'django.views.static.serve',
   82.22              {'document_root': settings.STATIC_DOC_ROOT}),
   82.23  
   82.24 +Be careful not to use the same path as your :setting:`ADMIN_MEDIA_PREFIX` (which defaults
   82.25 +to ``/media/``) as this will overwrite your URLconf entry.
   82.26 +
   82.27  Directory listings
   82.28  ==================
   82.29  
    83.1 --- a/docs/index.txt	Sat Mar 28 12:05:48 2009 -0500
    83.2 +++ b/docs/index.txt	Wed Apr 01 13:05:19 2009 -0500
    83.3 @@ -33,47 +33,121 @@
    83.4  First steps
    83.5  ===========
    83.6  
    83.7 -    * **From scratch:** :ref:`Overview <intro-overview>` | :ref:`Installation <intro-install>`
    83.8 -    * **Tutorial:** :ref:`Part 1 <intro-tutorial01>` | :ref:`Part 2 <intro-tutorial02>` | :ref:`Part 3 <intro-tutorial03>` | :ref:`Part 4 <intro-tutorial04>`
    83.9 +    * **From scratch:** 
   83.10 +      :ref:`Overview <intro-overview>` |
   83.11 +      :ref:`Installation <intro-install>`
   83.12 +      
   83.13 +    * **Tutorial:** 
   83.14 +      :ref:`Part 1 <intro-tutorial01>` | 
   83.15 +      :ref:`Part 2 <intro-tutorial02>` | 
   83.16 +      :ref:`Part 3 <intro-tutorial03>` | 
   83.17 +      :ref:`Part 4 <intro-tutorial04>`
   83.18  
   83.19  The model layer
   83.20  ===============
   83.21  
   83.22 -    * **Models:** :ref:`Model syntax <topics-db-models>` | :ref:`Field types <ref-models-fields>` | :ref:`Meta options <ref-models-options>`
   83.23 -    * **QuerySets:** :ref:`Executing queries <topics-db-queries>` | :ref:`QuerySet method reference <ref-models-querysets>`
   83.24 -    * **Model instances:** :ref:`Instance methods <ref-models-instances>` | :ref:`Accessing related objects <ref-models-relations>`
   83.25 -    * **Advanced:** :ref:`Managers <topics-db-managers>` | :ref:`Raw SQL <topics-db-sql>` | :ref:`Transactions <topics-db-transactions>` | :ref:`Aggregation <topics-db-aggregation>` | :ref:`Custom fields <howto-custom-model-fields>`
   83.26 -    * **Other:** :ref:`Supported databases <ref-databases>` | :ref:`Legacy databases <howto-legacy-databases>` | :ref:`Providing initial data <howto-initial-data>`
   83.27 +    * **Models:** 
   83.28 +      :ref:`Model syntax <topics-db-models>` | 
   83.29 +      :ref:`Field types <ref-models-fields>` | 
   83.30 +      :ref:`Meta options <ref-models-options>`
   83.31 +      
   83.32 +    * **QuerySets:** 
   83.33 +      :ref:`Executing queries <topics-db-queries>` | 
   83.34 +      :ref:`QuerySet method reference <ref-models-querysets>`
   83.35 +      
   83.36 +    * **Model instances:** 
   83.37 +      :ref:`Instance methods <ref-models-instances>` | 
   83.38 +      :ref:`Accessing related objects <ref-models-relations>`
   83.39 +      
   83.40 +    * **Advanced:** 
   83.41 +      :ref:`Managers <topics-db-managers>` | 
   83.42 +      :ref:`Raw SQL <topics-db-sql>` | 
   83.43 +      :ref:`Transactions <topics-db-transactions>` | 
   83.44 +      :ref:`Aggregation <topics-db-aggregation>` | 
   83.45 +      :ref:`Custom fields <howto-custom-model-fields>`
   83.46 +      
   83.47 +    * **Other:** 
   83.48 +      :ref:`Supported databases <ref-databases>` | 
   83.49 +      :ref:`Legacy databases <howto-legacy-databases>` | 
   83.50 +      :ref:`Providing initial data <howto-initial-data>`
   83.51  
   83.52  The template layer
   83.53  ==================
   83.54  
   83.55 -    * **For designers:** :ref:`Syntax overview <topics-templates>` | :ref:`Built-in tags and filters <ref-templates-builtins>`
   83.56 -    * **For programmers:** :ref:`Template API <ref-templates-api>` | :ref:`Custom tags and filters <howto-custom-template-tags>`
   83.57 +    * **For designers:** 
   83.58 +      :ref:`Syntax overview <topics-templates>` | 
   83.59 +      :ref:`Built-in tags and filters <ref-templates-builtins>`
   83.60 +    
   83.61 +    * **For programmers:** 
   83.62 +      :ref:`Template API <ref-templates-api>` | 
   83.63 +      :ref:`Custom tags and filters <howto-custom-template-tags>`
   83.64  
   83.65  The view layer
   83.66  ==============
   83.67  
   83.68 -    * **The basics:** :ref:`URLconfs <topics-http-urls>` | :ref:`View functions <topics-http-views>` | :ref:`Shortcuts <topics-http-shortcuts>`
   83.69 -    * **Reference:** :ref:`Request/response objects <ref-request-response>`
   83.70 -    * **File uploads:** :ref:`Overview <topics-http-file-uploads>` | :ref:`File objects <ref-files-file>` | :ref:`Storage API <ref-files-storage>` | :ref:`Managing files <topics-files>` | :ref:`Custom storage <howto-custom-file-storage>`
   83.71 -    * **Advanced:** :ref:`Generic views <ref-generic-views>` | :ref:`Generating CSV <howto-outputting-csv>` | :ref:`Generating PDF <howto-outputting-pdf>`
   83.72 -    * **Middleware:** :ref:`Overview <topics-http-middleware>` | :ref:`Built-in middleware classes <ref-middleware>`
   83.73 +    * **The basics:** 
   83.74 +      :ref:`URLconfs <topics-http-urls>` | 
   83.75 +      :ref:`View functions <topics-http-views>` | 
   83.76 +      :ref:`Shortcuts <topics-http-shortcuts>`
   83.77 +    
   83.78 +    * **Reference:**  :ref:`Request/response objects <ref-request-response>`
   83.79 +    
   83.80 +    * **File uploads:** 
   83.81 +      :ref:`Overview <topics-http-file-uploads>` | 
   83.82 +      :ref:`File objects <ref-files-file>` | 
   83.83 +      :ref:`Storage API <ref-files-storage>` | 
   83.84 +      :ref:`Managing files <topics-files>` | 
   83.85 +      :ref:`Custom storage <howto-custom-file-storage>`
   83.86 +          
   83.87 +    * **Advanced:** 
   83.88 +      :ref:`Generic views <ref-generic-views>` | 
   83.89 +      :ref:`Generating CSV <howto-outputting-csv>` | 
   83.90 +      :ref:`Generating PDF <howto-outputting-pdf>`
   83.91 +    
   83.92 +    * **Middleware:** 
   83.93 +      :ref:`Overview <topics-http-middleware>` | 
   83.94 +      :ref:`Built-in middleware classes <ref-middleware>`
   83.95  
   83.96  Forms
   83.97  =====
   83.98  
   83.99 -    * **The basics:** :ref:`Overview <topics-forms-index>` | :ref:`Form API <ref-forms-api>` | :ref:`Built-in fields <ref-forms-fields>` | :ref:`Built-in widgets <ref-forms-widgets>`
  83.100 -    * **Advanced:** :ref:`Forms for models <topics-forms-modelforms>` | :ref:`Integrating media <topics-forms-media>` | :ref:`Formsets <topics-forms-formsets>` | :ref:`Customizing validation <ref-forms-validation>`
  83.101 -    * **Extras:** :ref:`Form preview <ref-contrib-formtools-form-preview>` | :ref:`Form wizard <ref-contrib-formtools-form-wizard>`
  83.102 +    * **The basics:** 
  83.103 +      :ref:`Overview <topics-forms-index>` | 
  83.104 +      :ref:`Form API <ref-forms-api>` | 
  83.105 +      :ref:`Built-in fields <ref-forms-fields>` | 
  83.106 +      :ref:`Built-in widgets <ref-forms-widgets>`
  83.107 +    
  83.108 +    * **Advanced:** 
  83.109 +      :ref:`Forms for models <topics-forms-modelforms>` | 
  83.110 +      :ref:`Integrating media <topics-forms-media>` | 
  83.111 +      :ref:`Formsets <topics-forms-formsets>` | 
  83.112 +      :ref:`Customizing validation <ref-forms-validation>`
  83.113 +    
  83.114 +    * **Extras:** 
  83.115 +      :ref:`Form preview <ref-contrib-formtools-form-preview>` | 
  83.116 +      :ref:`Form wizard <ref-contrib-formtools-form-wizard>`
  83.117  
  83.118  The development process
  83.119  =======================
  83.120  
  83.121 -    * **Settings:** :ref:`Overview <topics-settings>` | :ref:`Full list of settings <ref-settings>`
  83.122 -    * **django-admin.py and manage.py:** :ref:`Overview <ref-django-admin>` | :ref:`Adding custom commands <howto-custom-management-commands>`
  83.123 -    * **Testing:** :ref:`Overview <topics-testing>`
  83.124 -    * **Deployment:** :ref:`Overview <howto-deployment-index>` | :ref:`Apache/mod_python <howto-deployment-modpython>` | :ref:`FastCGI/SCGI/AJP <howto-deployment-fastcgi>` | :ref:`Apache authentication <howto-apache-auth>` | :ref:`Serving static files <howto-static-files>` | :ref:`Tracking code errors by e-mail <howto-error-reporting>`
  83.125 +    * **Settings:** 
  83.126 +      :ref:`Overview <topics-settings>` | 
  83.127 +      :ref:`Full list of settings <ref-settings>`
  83.128 +
  83.129 +    * **django-admin.py and manage.py:** 
  83.130 +      :ref:`Overview <ref-django-admin>` | 
  83.131 +      :ref:`Adding custom commands <howto-custom-management-commands>`
  83.132 +    
  83.133 +    * **Testing:**  :ref:`Overview <topics-testing>`
  83.134 +    
  83.135 +    * **Deployment:** 
  83.136 +      :ref:`Overview <howto-deployment-index>` | 
  83.137 +      :ref:`Apache/mod_wsgi <howto-deployment-modwsgi>` |
  83.138 +      :ref:`Apache/mod_python <howto-deployment-modpython>` |
  83.139 +      :ref:`FastCGI/SCGI/AJP <howto-deployment-fastcgi>` | 
  83.140 +      :ref:`Apache authentication <howto-apache-auth>` | 
  83.141 +      :ref:`Serving static files <howto-static-files>` | 
  83.142 +      :ref:`Tracking code errors by e-mail <howto-error-reporting>`
  83.143  
  83.144  Other batteries included
  83.145  ========================
  83.146 @@ -106,10 +180,22 @@
  83.147  The Django open-source project
  83.148  ==============================
  83.149  
  83.150 -    * **Community:** :ref:`How to get involved <internals-contributing>` | :ref:`The release process <internals-release-process>` | :ref:`Team of committers <internals-committers>`
  83.151 -    * **Design philosophies:** :ref:`Overview <misc-design-philosophies>`
  83.152 -    * **Documentation:** :ref:`About this documentation <internals-documentation>`
  83.153 -    * **Third-party distributions:** :ref:`Overview <misc-distributions>`
  83.154 -    * **Django over time:** :ref:`API stability <misc-api-stability>` | :ref:`Archive of release notes <releases-index>` | `Backwards-incompatible changes`_
  83.155 +    * **Community:** 
  83.156 +      :ref:`How to get involved <internals-contributing>` | 
  83.157 +      :ref:`The release process <internals-release-process>` | 
  83.158 +      :ref:`Team of committers <internals-committers>`
  83.159 +    
  83.160 +    * **Design philosophies:** 
  83.161 +      :ref:`Overview <misc-design-philosophies>`
  83.162 +    
  83.163 +    * **Documentation:** 
  83.164 +      :ref:`About this documentation <internals-documentation>`
  83.165 +    
  83.166 +    * **Third-party distributions:** 
  83.167 +      :ref:`Overview <misc-distributions>`
  83.168 +    
  83.169 +    * **Django over time:** 
  83.170 +      :ref:`API stability <misc-api-stability>` | 
  83.171 +      :ref:`Archive of release notes <releases-index>` | `Backwards-incompatible changes`_
  83.172  
  83.173  .. _Backwards-incompatible changes: http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges
    84.1 --- a/docs/internals/release-process.txt	Sat Mar 28 12:05:48 2009 -0500
    84.2 +++ b/docs/internals/release-process.txt	Wed Apr 01 13:05:19 2009 -0500
    84.3 @@ -108,7 +108,7 @@
    84.4        1.3.2, etc.
    84.5        
    84.6      * Security releases will be applied to trunk, a ``1.3.X`` branch and a
    84.7 -      ``1.2.X`` branch. Security fixes will trigger the release of of ``1.3.1``,
    84.8 +      ``1.2.X`` branch. Security fixes will trigger the release of ``1.3.1``,
    84.9        ``1.2.1``, etc.
   84.10  
   84.11  .. _release-process:
    85.1 --- a/docs/intro/tutorial01.txt	Sat Mar 28 12:05:48 2009 -0500
    85.2 +++ b/docs/intro/tutorial01.txt	Wed Apr 01 13:05:19 2009 -0500
    85.3 @@ -618,7 +618,7 @@
    85.4  Note the addition of ``import datetime`` to reference Python's standard
    85.5  ``datetime`` module.
    85.6  
    85.7 -Let's jump back into the Python interactive shell by running
    85.8 +Save these changes and start a new Python interactive shell by running
    85.9  ``python manage.py shell`` again::
   85.10  
   85.11      >>> from mysite.polls.models import Poll, Choice
    86.1 --- a/docs/intro/tutorial02.txt	Sat Mar 28 12:05:48 2009 -0500
    86.2 +++ b/docs/intro/tutorial02.txt	Wed Apr 01 13:05:19 2009 -0500
    86.3 @@ -170,14 +170,14 @@
    86.4  Customize the admin form
    86.5  ========================
    86.6  
    86.7 -Take a few minutes to marvel at all the code you didn't have to write. When you
    86.8 -call ``admin.site.register(Poll)``, Django just lets you edit the object and
    86.9 -"guess" at how to display it within the admin. Often you'll want to control how
   86.10 -the admin looks and works. You'll do this by telling Django about the options
   86.11 +Take a few minutes to marvel at all the code you didn't have to write. By
   86.12 +registering the Poll model with ``admin.site.register(Poll)``, Django was able
   86.13 +to construct a default form representation. Often, you'll want to customize how
   86.14 +the admin form looks and works. You'll do this by telling Django the options
   86.15  you want when you register the object.
   86.16  
   86.17 -Let's see how this works by reordering the fields on the edit form. Replace the
   86.18 -``admin.site.register(Poll)`` line with::
   86.19 +Let's see how this works by re-ordering the fields on the edit form. Replace
   86.20 +the ``admin.site.register(Poll)`` line with::
   86.21  
   86.22      class PollAdmin(admin.ModelAdmin):
   86.23          fields = ['pub_date', 'question']
    87.1 --- a/docs/intro/tutorial03.txt	Sat Mar 28 12:05:48 2009 -0500
    87.2 +++ b/docs/intro/tutorial03.txt	Wed Apr 01 13:05:19 2009 -0500
    87.3 @@ -117,8 +117,8 @@
    87.4  
    87.5  Note that these regular expressions do not search GET and POST parameters, or
    87.6  the domain name. For example, in a request to ``http://www.example.com/myapp/``,
    87.7 -the URLconf will look for ``/myapp/``. In a request to
    87.8 -``http://www.example.com/myapp/?page=3``, the URLconf will look for ``/myapp/``.
    87.9 +the URLconf will look for ``myapp/``. In a request to
   87.10 +``http://www.example.com/myapp/?page=3``, the URLconf will look for ``myapp/``.
   87.11  
   87.12  If you need help with regular expressions, see `Wikipedia's entry`_ and the
   87.13  `Python documentation`_. Also, the O'Reilly book "Mastering Regular Expressions"
    88.1 --- a/docs/intro/tutorial04.txt	Sat Mar 28 12:05:48 2009 -0500
    88.2 +++ b/docs/intro/tutorial04.txt	Wed Apr 01 13:05:19 2009 -0500
    88.3 @@ -47,10 +47,10 @@
    88.4        through its loop
    88.5  
    88.6  Now, let's create a Django view that handles the submitted data and does
    88.7 -something with it. Remember, in :ref:`Tutorial 3 <intro-tutorial03>`, we created
    88.8 -a URLconf for the polls application that includes this line::
    88.9 +something with it. Remember, in :ref:`Tutorial 3 <intro-tutorial03>`, we
   88.10 +created a URLconf for the polls application that includes this line::
   88.11  
   88.12 -    (r'^(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),
   88.13 +    (r'^(?P<poll_id>\d+)/vote/$', 'vote'),
   88.14  
   88.15  So let's create a ``vote()`` function in ``mysite/polls/views.py``::
   88.16  
    89.1 --- a/docs/ref/contrib/admin/index.txt	Sat Mar 28 12:05:48 2009 -0500
    89.2 +++ b/docs/ref/contrib/admin/index.txt	Wed Apr 01 13:05:19 2009 -0500
    89.3 @@ -408,9 +408,6 @@
    89.4          list_display = ('first_name', 'last_name', 'birthday')
    89.5          list_display_links = ('first_name', 'last_name')
    89.6  
    89.7 -Finally, note that in order to use ``list_display_links``, you must define
    89.8 -``list_display``, too.
    89.9 -
   89.10  .. _admin-list-editable:
   89.11  
   89.12  ``list_editable``
   89.13 @@ -428,7 +425,7 @@
   89.14      ``list_editable`` interacts with a couple of other options in particular
   89.15      ways; you should note the following rules:
   89.16  
   89.17 -        * To use ``list_editable`` you must have defined ``ordering`` defined on
   89.18 +        * To use ``list_editable`` you must have defined ``ordering`` on
   89.19            either your model or your ``ModelAdmin``.
   89.20  
   89.21          * Any field in ``list_editable`` must also be in ``list_display``. You
   89.22 @@ -680,7 +677,7 @@
   89.23  A list of actions to make available on the change list page. See
   89.24  :ref:`ref-contrib-admin-actions` for details.
   89.25  
   89.26 -``actions_on_top``, ``actions_on_buttom``
   89.27 +``actions_on_top``, ``actions_on_bottom``
   89.28  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   89.29  
   89.30  Controls where on the page the actions bar appears. By default, the admin
   89.31 @@ -835,8 +832,17 @@
   89.32  ============================
   89.33  
   89.34  The admin interface has the ability to edit models on the same page as a
   89.35 -parent model. These are called inlines. You can add them to a model by
   89.36 -specifying them in a ``ModelAdmin.inlines`` attribute::
   89.37 +parent model. These are called inlines. Suppose you have these two models::
   89.38 +
   89.39 +     class Author(models.Model):
   89.40 +        name = models.CharField(max_length=100)
   89.41 +
   89.42 +     class Book(models.Model):
   89.43 +        author = models.ForeignKey(Author)
   89.44 +        title = models.CharField(max_length=100)
   89.45 +
   89.46 +You can edit the books authored by an author on the author page. You add 
   89.47 +inlines to a model by specifying them in a ``ModelAdmin.inlines``::
   89.48  
   89.49      class BookInline(admin.TabularInline):
   89.50          model = Book
   89.51 @@ -881,7 +887,7 @@
   89.52  ``form``
   89.53  ~~~~~~~~
   89.54  
   89.55 -The value for ``form`` is inherited from ``ModelAdmin``. This is what is
   89.56 +The value for ``form`` defaults to ``BaseModelForm``. This is what is
   89.57  passed through to ``formset_factory`` when creating the formset for this
   89.58  inline.
   89.59  
   89.60 @@ -1124,6 +1130,7 @@
   89.61  Not every template in ``contrib\admin\templates\admin`` may be overridden per
   89.62  app or per model. The following can:
   89.63  
   89.64 +    * ``app_index.html``
   89.65      * ``change_form.html``
   89.66      * ``change_list.html``
   89.67      * ``delete_confirmation.html``
   89.68 @@ -1168,7 +1175,7 @@
   89.69  
   89.70  The last step in setting up the Django admin is to hook your ``AdminSite``
   89.71  instance into your URLconf. Do this by pointing a given URL at the
   89.72 -``AdminSite.root`` method.
   89.73 +``AdminSite.urls`` method.
   89.74  
   89.75  In this example, we register the default ``AdminSite`` instance
   89.76  ``django.contrib.admin.site`` at the URL ``/admin/`` ::
    90.1 --- a/docs/ref/contrib/comments/index.txt	Sat Mar 28 12:05:48 2009 -0500
    90.2 +++ b/docs/ref/contrib/comments/index.txt	Wed Apr 01 13:05:19 2009 -0500
    90.3 @@ -155,9 +155,10 @@
    90.4      {% get_comment_form for event as form %}
    90.5      <form action="{% comment_form_target %}" method="POST">
    90.6        {{ form }}
    90.7 -      <p class="submit">
    90.8 -        <input type="submit" name="preview" class="submit-post" value="Preview">
    90.9 -      </p>
   90.10 +      <tr>
   90.11 +        <td></td>
   90.12 +        <td><input type="submit" name="preview" class="submit-post" value="Preview"></td>
   90.13 +      </tr>
   90.14      </form>
   90.15      
   90.16  Be sure to read the `notes on the comment form`_, below, for some special
    91.1 --- a/docs/ref/contrib/contenttypes.txt	Sat Mar 28 12:05:48 2009 -0500
    91.2 +++ b/docs/ref/contrib/contenttypes.txt	Wed Apr 01 13:05:19 2009 -0500
    91.3 @@ -303,7 +303,20 @@
    91.4      >>> b.tags.all()
    91.5      [<TaggedItem: django>, <TaggedItem: python>]
    91.6  
    91.7 -If you don't add the reverse relationship, you can do the lookup manually::
    91.8 +Just as :class:`django.contrib.contenttypes.generic.GenericForeignKey`
    91.9 +accepts the names of the content-type and object-ID fields as
   91.10 +arguments, so too does ``GenericRelation``; if the model which has the
   91.11 +generic foreign key is using non-default names for those fields, you
   91.12 +must pass the names of the fields when setting up a
   91.13 +``GenericRelation`` to it. For example, if the ``TaggedItem`` model
   91.14 +referred to above used fields named ``content_type_fk`` and
   91.15 +``object_primary_key`` to create its generic foreign key, then a
   91.16 +``GenericRelation`` back to it would need to be defined like so::
   91.17 +
   91.18 +    tags = generic.GenericRelation('content_type_fk', 'object_primary_key')
   91.19 +
   91.20 +Of course, if you don't add the reverse relationship, you can do the
   91.21 +same types of lookups manually::
   91.22  
   91.23      >>> b = Bookmark.objects.get(url='http://www.djangoproject.com/')
   91.24      >>> bookmark_type = ContentType.objects.get_for_model(b)
   91.25 @@ -311,6 +324,14 @@
   91.26      ...                           object_id=b.id)
   91.27      [<TaggedItem: django>, <TaggedItem: python>]
   91.28  
   91.29 +Note that if the model with a :class:`~django.contrib.contenttypes.generic.GenericForeignKey` 
   91.30 +that you're referring to uses a non-default value for ``ct_field`` or ``fk_field`` 
   91.31 +(e.g. the :mod:`django.contrib.comments` app uses ``ct_field="object_pk"``), 
   91.32 +you'll need to pass ``content_type_field`` and ``object_id_field`` to
   91.33 +:class:`~django.contrib.contenttypes.generic.GenericRelation`.::
   91.34 +
   91.35 +	comments = generic.GenericRelation(Comment, content_type_field="content_type", object_id_field="object_pk")
   91.36 +	
   91.37  Note that if you delete an object that has a
   91.38  :class:`~django.contrib.contenttypes.generic.GenericRelation`, any objects
   91.39  which have a :class:`~django.contrib.contenttypes.generic.GenericForeignKey`
    92.1 --- a/docs/ref/contrib/formtools/form-wizard.txt	Sat Mar 28 12:05:48 2009 -0500
    92.2 +++ b/docs/ref/contrib/formtools/form-wizard.txt	Wed Apr 01 13:05:19 2009 -0500
    92.3 @@ -290,7 +290,7 @@
    92.4  .. method:: FormWizard.render_template
    92.5  
    92.6      Renders the template for the given step, returning an
    92.7 -    :class:`~django.http.HttpResponseRedirect` object.
    92.8 +    :class:`~django.http.HttpResponse` object.
    92.9  
   92.10      Override this method if you want to add a custom context, return a different
   92.11      MIME type, etc. If you only need to override the template name, use
    93.1 --- a/docs/ref/databases.txt	Sat Mar 28 12:05:48 2009 -0500
    93.2 +++ b/docs/ref/databases.txt	Wed Apr 01 13:05:19 2009 -0500
    93.3 @@ -26,7 +26,7 @@
    93.4  faulty`_. Users of these releases of PostgreSQL are advised to upgrade to
    93.5  `Release 8.2.5`_ or later. Django will raise a ``NotImplementedError`` if you
    93.6  attempt to use the ``StdDev(sample=False)`` or ``Variance(sample=False)``
    93.7 -aggregate with an database backend falls within the affected release range.
    93.8 +aggregate with a database backend that falls within the affected release range.
    93.9  
   93.10  .. _known to be faulty: http://archives.postgresql.org/pgsql-bugs/2007-07/msg00046.php
   93.11  .. _Release 8.2.5: http://developer.postgresql.org/pgdocs/postgres/release-8-2-5.html
   93.12 @@ -35,7 +35,7 @@
   93.13  ---------------------
   93.14  
   93.15  :ref:`By default <topics-db-transactions>`, Django starts a transaction when a
   93.16 -database connection if first used and commits the result at the end of the
   93.17 +database connection is first used and commits the result at the end of the
   93.18  request/response handling. The PostgreSQL backends normally operate the same
   93.19  as any other Django backend in this respect.
   93.20  
   93.21 @@ -86,10 +86,10 @@
   93.22  MySQL notes
   93.23  ===========
   93.24  
   93.25 -Django expects the database to support transactions, referential integrity,
   93.26 -and Unicode support (UTF-8 encoding). Fortunately, MySQL_ has all these
   93.27 -features as available as far back as 3.23. While it may be possible to use
   93.28 -3.23 or 4.0, you'll probably have less trouble if you use 4.1 or 5.0.
   93.29 +Django expects the database to support transactions, referential integrity, and
   93.30 +Unicode (UTF-8 encoding). Fortunately, MySQL_ has all these features as
   93.31 +available as far back as 3.23. While it may be possible to use 3.23 or 4.0,
   93.32 +you'll probably have less trouble if you use 4.1 or 5.0.
   93.33  
   93.34  MySQL 4.1
   93.35  ---------
   93.36 @@ -351,44 +351,44 @@
   93.37  
   93.38  .. _documented at sqlite.org: http://www.sqlite.org/faq.html#q18
   93.39  
   93.40 -Versions prior to 3.3.6
   93.41 -------------------------
   93.42 +SQLite 3.3.6 or newer strongly recommended
   93.43 +------------------------------------------
   93.44  
   93.45 -Versions of SQLite 3.3.5 and older `contain a bug`_ when handling ``ORDER BY``
   93.46 -parameters. This can cause problems when you use the ``select`` parameter for
   93.47 -the ``extra()`` QuerySet method. The bug can be identified by the error message
   93.48 -``OperationalError: ORDER BY terms must not be non-integer constants``. The
   93.49 -problem can be solved updating SQLite to version 3.3.6 or newer, possibly also
   93.50 -updating the ``pysqlite2`` Python module in the process.
   93.51 +Versions of SQLite 3.3.5 and older contains the following bugs:
   93.52  
   93.53 -.. _contain a bug: http://www.sqlite.org/cvstrac/tktview?tn=1768
   93.54 + * A bug when `handling`_ ``ORDER BY`` parameters. This can cause problems when
   93.55 +   you use the ``select`` parameter for the ``extra()`` QuerySet method. The bug
   93.56 +   can be identified by the error message ``OperationalError: ORDER BY terms
   93.57 +   must not be non-integer constants``.
   93.58  
   93.59 -This has a very low impact because 3.3.6 was released in April 2006, so most
   93.60 -current binary distributions for different platforms include newer version of
   93.61 -SQLite usable from Python through either the ``pysqlite2`` or the ``sqlite3``
   93.62 -modules.
   93.63 + * A bug when handling `aggregation`_ together with DateFields and
   93.64 +   DecimalFields.
   93.65  
   93.66 -However, in the case of Windows, the official binary distribution of the stable
   93.67 -release of Python 2.5 (2.5.2, as of this writing) includes SQLite 3.3.4, so the bug can
   93.68 -make itself evident in that platform. There are (as of Django 1.0) even three
   93.69 -tests in the Django test suite that will fail when run under this setup.  As
   93.70 -described above, this can be solved by downloading and installing a newer
   93.71 -version of ``pysqlite2`` (``pysqlite-2.x.x.win32-py2.5.exe``) that includes and
   93.72 -uses a newer version of SQLite. Python 2.6 ships with a newer version of
   93.73 -SQLite and is not affected by this issue.
   93.74 +.. _handling: http://www.sqlite.org/cvstrac/tktview?tn=1768
   93.75 +.. _aggregation: http://code.djangoproject.com/ticket/10031
   93.76  
   93.77 -If you are in such platform and find yourself in the need to update
   93.78 -``pysqlite``/SQLite, you will also need to manually modify the
   93.79 -``django/db/backends/sqlite3/base.py`` file in the Django source tree so it
   93.80 -attempts to import ``pysqlite2`` before than ``sqlite3`` and so it can take
   93.81 -advantage of the new ``pysqlite2``/SQLite versions.
   93.82 +SQLite 3.3.6 was released in April 2006, so most current binary distributions
   93.83 +for different platforms include newer version of SQLite usable from Python
   93.84 +through either the ``pysqlite2`` or the ``sqlite3`` modules.
   93.85 +
   93.86 +However, some platform/Python version combinations include older versions of
   93.87 +SQLite (e.g. the official binary distribution of Python 2.5 for Windows, 2.5.4
   93.88 +as of this writing, includes SQLite 3.3.4). There are (as of Django 1.1) even
   93.89 +some tests in the Django test suite that will fail when run under this setup.
   93.90 +
   93.91 +As described :ref:`below<using-newer-versions-of-pysqlite>`, this can be solved
   93.92 +by downloading and installing a newer version of ``pysqlite2``
   93.93 +(``pysqlite-2.x.x.win32-py2.5.exe`` in the described case) that includes and
   93.94 +uses a newer version of SQLite. Python 2.6 for Windows ships with a version of
   93.95 +SQLite that is not affected by these issues.
   93.96  
   93.97  Version 3.5.9
   93.98  -------------
   93.99  
  93.100 -The Ubuntu "Intrepid Ibex" SQLite 3.5.9-3 package contains a bug that causes
  93.101 -problems with the evaluation of query expressions. If you are using Ubuntu
  93.102 -"Intrepid Ibex", you will need to find an alternate source for SQLite
  93.103 +The Ubuntu "Intrepid Ibex" (8.10) SQLite 3.5.9-3 package contains a bug that
  93.104 +causes problems with the evaluation of query expressions. If you are using
  93.105 +Ubuntu "Intrepid Ibex", you will need to update the package to version
  93.106 +3.5.9-3ubuntu1 or newer (recommended) or find an alternate source for SQLite
  93.107  packages, or install SQLite from source.
  93.108  
  93.109  At one time, Debian Lenny shipped with the same malfunctioning SQLite 3.5.9-3
  93.110 @@ -411,6 +411,21 @@
  93.111  3.6.3 (released September 22, 2008) or later, or downgrade to an earlier
  93.112  version of SQLite.
  93.113  
  93.114 +.. _using-newer-versions-of-pysqlite:
  93.115 +
  93.116 +Using newer versions of the SQLite DB-API 2.0 driver
  93.117 +----------------------------------------------------
  93.118 +
  93.119 +.. versionadded:: 1.1
  93.120 +
  93.121 +For versions of Python 2.5 or newer that include ``sqlite3`` in the standard
  93.122 +library Django will now use a ``pysqlite2`` interface in preference to
  93.123 +``sqlite3`` if it finds one is available.
  93.124 +
  93.125 +This provides the ability to upgrade both the DB-API 2.0 interface or SQLite 3
  93.126 +itself to versions newer than the ones included with your particular Python
  93.127 +binary distribution, if needed.
  93.128 +
  93.129  .. _oracle-notes:
  93.130  
  93.131  Oracle notes
    94.1 --- a/docs/ref/django-admin.txt	Sat Mar 28 12:05:48 2009 -0500
    94.2 +++ b/docs/ref/django-admin.txt	Wed Apr 01 13:05:19 2009 -0500
    94.3 @@ -341,6 +341,9 @@
    94.4  application,  ``<dirname>/foo/bar/mydata.json`` for each directory in
    94.5  ``FIXTURE_DIRS``, and the literal path ``foo/bar/mydata.json``.
    94.6  
    94.7 +When fixture files are processed, the data is saved to the database as is.
    94.8 +Model defined ``save`` methods and ``pre_save`` signals are not called.
    94.9 +
   94.10  Note that the order in which fixture files are processed is undefined. However,
   94.11  all fixture data is installed as a single transaction, so data in
   94.12  one fixture can reference data in another fixture. If the database backend
    95.1 --- a/docs/ref/forms/fields.txt	Sat Mar 28 12:05:48 2009 -0500
    95.2 +++ b/docs/ref/forms/fields.txt	Wed Apr 01 13:05:19 2009 -0500
    95.3 @@ -174,6 +174,16 @@
    95.4      >>> f.errors
    95.5      {'url': [u'This field is required.'], 'name': [u'This field is required.']}
    95.6  
    95.7 +Instead of a constant, you can also pass any callable::
    95.8 +
    95.9 +    >>> import datetime
   95.10 +    >>> class DateForm(forms.Form):
   95.11 +    ...     day = forms.DateField(initial=datetime.date.today)
   95.12 +    >>> print DateForm()
   95.13 +    <tr><th>Day:</th><td><input type="text" name="day" value="12/23/2008" /><td></tr>
   95.14 +
   95.15 +The callable will be evaluated only when the unbound form is displayed, not when it is defined.
   95.16 +
   95.17  ``widget``
   95.18  ~~~~~~~~~~
   95.19  
    96.1 --- a/docs/ref/models/fields.txt	Sat Mar 28 12:05:48 2009 -0500
    96.2 +++ b/docs/ref/models/fields.txt	Wed Apr 01 13:05:19 2009 -0500
    96.3 @@ -7,6 +7,8 @@
    96.4  .. module:: django.db.models.fields
    96.5     :synopsis: Built-in field types.
    96.6  
    96.7 +.. currentmodule:: django.db.models
    96.8 +
    96.9  This document contains all the gory details about all the `field options`_ and
   96.10  `field types`_ Django's got to offer.
   96.11  
   96.12 @@ -239,7 +241,8 @@
   96.13  field, a :exc:`django.db.IntegrityError` will be raised by the model's
   96.14  :meth:`~django.db.models.Model.save` method.
   96.15  
   96.16 -This option is valid on all field types except :class:`ManyToManyField`.
   96.17 +This option is valid on all field types except :class:`ManyToManyField` and
   96.18 +:class:`FileField`.
   96.19  
   96.20  ``unique_for_date``
   96.21  -------------------
   96.22 @@ -365,13 +368,14 @@
   96.23  
   96.24  .. class:: DateField([auto_now=False, auto_now_add=False, **options])
   96.25  
   96.26 -A date field. Has a few extra optional arguments:
   96.27 +A date, represented in Python by a ``datetime.date`` instance. Has a few extra,
   96.28 +optional arguments:
   96.29  
   96.30  .. attribute:: DateField.auto_now
   96.31  
   96.32      Automatically set the field to now every time the object is saved. Useful
   96.33 -    for "last-modified" timestamps. Note that the current date is *always* used;
   96.34 -    it's not just a default value that you can override.
   96.35 +    for "last-modified" timestamps. Note that the current date is *always*
   96.36 +    used; it's not just a default value that you can override.
   96.37  
   96.38  .. attribute:: DateField.auto_now_add
   96.39  
   96.40 @@ -380,18 +384,19 @@
   96.41      it's not just a default value that you can override.
   96.42  
   96.43  The admin represents this as an ``<input type="text">`` with a JavaScript
   96.44 -calendar, and a shortcut for "Today".  The JavaScript calendar will always start
   96.45 -the week on a Sunday.
   96.46 +calendar, and a shortcut for "Today".  The JavaScript calendar will always
   96.47 +start the week on a Sunday.
   96.48  
   96.49  ``DateTimeField``
   96.50  -----------------
   96.51  
   96.52  .. class:: DateTimeField([auto_now=False, auto_now_add=False, **options])
   96.53  
   96.54 -A date and time field. Takes the same extra options as :class:`DateField`.
   96.55 +A date and time, represented in Python by a ``datetime.datetime`` instance.
   96.56 +Takes the same extra arguments as :class:`DateField`.
   96.57  
   96.58 -The admin represents this as two ``<input type="text">`` fields, with JavaScript
   96.59 -shortcuts.
   96.60 +The admin represents this as two ``<input type="text">`` fields, with
   96.61 +JavaScript shortcuts.
   96.62  
   96.63  ``DecimalField``
   96.64  ----------------
   96.65 @@ -435,7 +440,13 @@
   96.66  
   96.67  .. class:: FileField(upload_to=None, [max_length=100, **options])
   96.68  
   96.69 -A file-upload field. Has one **required** argument:
   96.70 +A file-upload field.
   96.71 +
   96.72 +.. note::
   96.73 +    The ``primary_key`` and ``unique`` arguments are not supported, and will
   96.74 +    raise a ``TypeError`` if used.
   96.75 +
   96.76 +Has one **required** argument:
   96.77  
   96.78  .. attribute:: FileField.upload_to
   96.79  
   96.80 @@ -706,9 +717,11 @@
   96.81  
   96.82  .. class:: TimeField([auto_now=False, auto_now_add=False, **options])
   96.83  
   96.84 -A time. Accepts the same auto-population options as :class:`DateField` and
   96.85 -:class:`DateTimeField`. The admin represents this as an ``<input type="text">``
   96.86 -with some JavaScript shortcuts.
   96.87 +A time, represented in Python by a ``datetime.time`` instance. Accepts the same
   96.88 +auto-population options as :class:`DateField`.
   96.89 +
   96.90 +The admin represents this as an ``<input type="text">`` with some JavaScript
   96.91 +shortcuts.
   96.92  
   96.93  ``URLField``
   96.94  ------------
   96.95 @@ -720,7 +733,10 @@
   96.96  .. attribute:: URLField.verify_exists
   96.97  
   96.98      If ``True`` (the default), the URL given will be checked for existence
   96.99 -    (i.e., the URL actually loads and doesn't give a 404 response).
  96.100 +    (i.e., the URL actually loads and doesn't give a 404 response). It should
  96.101 +    be noted that when using the single-threaded development server, validating
  96.102 +    a url being serverd by the same server will hang.
  96.103 +    This should not be a problem for multithreaded servers.
  96.104  
  96.105  The admin represents this as an ``<input type="text">`` (a single-line input).
  96.106  
    97.1 --- a/docs/ref/models/instances.txt	Sat Mar 28 12:05:48 2009 -0500
    97.2 +++ b/docs/ref/models/instances.txt	Wed Apr 01 13:05:19 2009 -0500
    97.3 @@ -18,12 +18,13 @@
    97.4  Creating objects
    97.5  ================
    97.6  
    97.7 -To create a new instance of a model, just instantiate it like any other Python class:
    97.8 +To create a new instance of a model, just instantiate it like any other Python
    97.9 +class:
   97.10  
   97.11  .. class:: Model(**kwargs)
   97.12  
   97.13 -The keyword arguments to are simply the names of the fields you've defined on
   97.14 -your model. Note that instantiating a model in no way touches your database; for
   97.15 +The keyword arguments are simply the names of the fields you've defined on your
   97.16 +model. Note that instantiating a model in no way touches your database; for
   97.17  that, you need to ``save()``.
   97.18  
   97.19  Saving objects
   97.20 @@ -289,7 +290,7 @@
   97.21  
   97.22  The problem with the way we wrote ``get_absolute_url()`` above is that it
   97.23  slightly violates the DRY principle: the URL for this object is defined both
   97.24 -in the URLConf file and in the model.
   97.25 +in the URLconf file and in the model.
   97.26  
   97.27  You can further decouple your models from the URLconf using the ``permalink``
   97.28  decorator:
    98.1 --- a/docs/ref/models/querysets.txt	Sat Mar 28 12:05:48 2009 -0500
    98.2 +++ b/docs/ref/models/querysets.txt	Wed Apr 01 13:05:19 2009 -0500
    98.3 @@ -154,7 +154,7 @@
    98.4  
    98.5      SELECT ...
    98.6      WHERE NOT pub_date > '2005-1-3'
    98.7 -    AND NOT headline = 'Hello'
    98.8 +    OR NOT headline = 'Hello'
    98.9  
   98.10  Note the second example is more restrictive.
   98.11  
   98.12 @@ -1484,8 +1484,18 @@
   98.13  A boolean full-text search, taking advantage of full-text indexing. This is
   98.14  like ``contains`` but is significantly faster due to full-text indexing.
   98.15  
   98.16 +Example::
   98.17 +    
   98.18 +    Entry.objects.filter(headline__search="+Django -jazz Python")
   98.19 +
   98.20 +SQL equivalent::
   98.21 +
   98.22 +    SELECT ... WHERE MATCH(tablename, headline) AGAINST (+Django -jazz Python IN BOOLEAN MODE);
   98.23 +
   98.24  Note this is only available in MySQL and requires direct manipulation of the
   98.25 -database to add the full-text index.
   98.26 +database to add the full-text index. By default Django uses BOOLEAN MODE for
   98.27 +full text searches. `Please check MySQL documentation for additional details. <http://dev.mysql.com/doc/refman/5.1/en/fulltext-boolean.html>`_
   98.28 +
   98.29  
   98.30  regex
   98.31  ~~~~~
    99.1 --- a/docs/ref/models/relations.txt	Sat Mar 28 12:05:48 2009 -0500
    99.2 +++ b/docs/ref/models/relations.txt	Wed Apr 01 13:05:19 2009 -0500
    99.3 @@ -42,7 +42,7 @@
    99.4          ....     body_text='Hi', 
    99.5          ....     pub_date=datetime.date(2005, 1, 1)
    99.6          .... )
    99.7 -        >>> e.save()
    99.8 +        >>> e.save(force_insert=True)
    99.9  
   99.10      Note that there's no need to specify the keyword argument of the model that
   99.11      defines the relationship. In the above example, we don't pass the parameter
   100.1 --- a/docs/ref/request-response.txt	Sat Mar 28 12:05:48 2009 -0500
   100.2 +++ b/docs/ref/request-response.txt	Wed Apr 01 13:05:19 2009 -0500
   100.3 @@ -14,11 +14,11 @@
   100.4  
   100.5  When a page is requested, Django creates an :class:`HttpRequest` object that
   100.6  contains metadata about the request. Then Django loads the appropriate view,
   100.7 -passing the :class:`HttpRequest` as the first argument to the view function. Each
   100.8 -view is responsible for returning an :class:`HttpResponse` object.
   100.9 +passing the :class:`HttpRequest` as the first argument to the view function.
  100.10 +Each view is responsible for returning an :class:`HttpResponse` object.
  100.11  
  100.12 -This document explains the APIs for :class:`HttpRequest` and :class:`HttpResponse`
  100.13 -objects.
  100.14 +This document explains the APIs for :class:`HttpRequest` and
  100.15 +:class:`HttpResponse` objects.
  100.16  
  100.17  HttpRequest objects
  100.18  ===================
  100.19 @@ -103,7 +103,8 @@
  100.20          * ``read(num_bytes=None)`` -- Read a number of bytes from the file.
  100.21          * ``name`` -- The name of the uploaded file.
  100.22          * ``size`` -- The size, in bytes, of the uploaded file.
  100.23 -        * ``chunks(chunk_size=None)`` -- A generator that yields sequential chunks of data.
  100.24 +        * ``chunks(chunk_size=None)`` -- A generator that yields sequential
  100.25 +          chunks of data.
  100.26  
  100.27      See :ref:`topics-files` for more information.
  100.28  
  100.29 @@ -229,9 +230,10 @@
  100.30  
  100.31     .. versionadded:: 1.0
  100.32  
  100.33 -   Returns ``True`` if the request was made via an ``XMLHttpRequest``, by checking
  100.34 -   the ``HTTP_X_REQUESTED_WITH`` header for the string ``'XMLHttpRequest'``. The
  100.35 -   following major JavaScript libraries all send this header:
  100.36 +   Returns ``True`` if the request was made via an ``XMLHttpRequest``, by
  100.37 +   checking the ``HTTP_X_REQUESTED_WITH`` header for the string
  100.38 +   ``'XMLHttpRequest'``. The following major JavaScript libraries all send this
  100.39 +   header:
  100.40  
  100.41         * jQuery
  100.42         * Dojo
  100.43 @@ -317,6 +319,17 @@
  100.44             >>> q = QueryDict('a=1&a=2&a=3')
  100.45             >>> q.items()
  100.46             [('a', '3')]
  100.47 +           
  100.48 +.. method:: QueryDict.iteritems()
  100.49 +
  100.50 +    Just like the standard dictionary ``iteritems()`` method. Like
  100.51 +    :meth:`QueryDict.items()` this uses the same last-value logic as
  100.52 +    :meth:`QueryDict.__getitem()__`.
  100.53 +
  100.54 +.. method:: QueryDict.iterlists()
  100.55 +
  100.56 +    Like :meth:`QueryDict.iteritems()` except it includes all values, as a list,
  100.57 +    for each member of the dictionary.
  100.58  
  100.59  .. method:: QueryDict.values()
  100.60  
  100.61 @@ -327,6 +340,10 @@
  100.62             >>> q.values()
  100.63             ['3']
  100.64  
  100.65 +.. method:: QueryDict.itervalues()
  100.66 +
  100.67 +    Just like :meth:`QueryDict.values()`, except an iterator.
  100.68 +
  100.69  In addition, ``QueryDict`` has the following methods:
  100.70  
  100.71  .. method:: QueryDict.copy()
   101.1 --- a/docs/ref/signals.txt	Sat Mar 28 12:05:48 2009 -0500
   101.2 +++ b/docs/ref/signals.txt	Wed Apr 01 13:05:19 2009 -0500
   101.3 @@ -30,6 +30,10 @@
   101.4      If you override these methods on your model, you must call the parent class'
   101.5      methods for this signals to be sent.
   101.6  
   101.7 +	Note also that Django stores signal handlers as weak references by default,
   101.8 +	so if your handler is a local function, it may be garbage collected.  To
   101.9 +	prevent this, pass ``weak=False`` when you call the signal's :meth:`~django.dispatch.Signal.connect`.
  101.10 +
  101.11  pre_init
  101.12  --------
  101.13  
   102.1 --- a/docs/ref/templates/builtins.txt	Sat Mar 28 12:05:48 2009 -0500
   102.2 +++ b/docs/ref/templates/builtins.txt	Wed Apr 01 13:05:19 2009 -0500
   102.3 @@ -866,6 +866,13 @@
   102.4  ``datetime.datetime.now()``), the output will be the string
   102.5  ``'Wed 09 Jan 2008'``.
   102.6  
   102.7 +When used without a format string::
   102.8 +
   102.9 +    {{ value|date }}
  102.10 +
  102.11 +...the formatting string defined in the :setting:`DATE_FORMAT` setting will be
  102.12 +used.
  102.13 +
  102.14  .. templatefilter:: default
  102.15  
  102.16  default
  102.17 @@ -1424,6 +1431,13 @@
  102.18  If ``value`` is equivalent to ``datetime.datetime.now()``, the output will be
  102.19  the string ``"01:23"``.
  102.20  
  102.21 +When used without a format string::
  102.22 +
  102.23 +    {{ value|time }}
  102.24 +
  102.25 +...the formatting string defined in the :setting:`TIME_FORMAT` setting will be
  102.26 +used.
  102.27 +
  102.28  .. templatefilter:: timesince
  102.29  
  102.30  timesince
   103.1 --- a/docs/releases/1.1-alpha-1.txt	Sat Mar 28 12:05:48 2009 -0500
   103.2 +++ b/docs/releases/1.1-alpha-1.txt	Wed Apr 01 13:05:19 2009 -0500
   103.3 @@ -82,7 +82,7 @@
   103.4    (sending admin requests to the ``admin.site.root`` view still works, but URLs
   103.5    in the admin will not be "reversible" when configured this way).
   103.6  
   103.7 -* The ``include()`` function in Django URLConf modules can now accept sequences
   103.8 +* The ``include()`` function in Django URLconf modules can now accept sequences
   103.9    of URL patterns (generated by ``patterns()``) in addition to module names.
  103.10  
  103.11  * Instances of Django forms (see `the forms overview <topics-forms-index>`_ now
   104.1 --- a/docs/topics/auth.txt	Sat Mar 28 12:05:48 2009 -0500
   104.2 +++ b/docs/topics/auth.txt	Wed Apr 01 13:05:19 2009 -0500
   104.3 @@ -463,6 +463,12 @@
   104.4  instance of the user profile model associated with that
   104.5  :class:`~django.contrib.auth.models.User`.
   104.6  
   104.7 +The method :class:`~django.contrib.auth.models.User.get_profile()`
   104.8 +does not create the profile, if it does not exist. You need to
   104.9 +register a handler for the signal
  104.10 +:attr:`django.db.models.signals.post_save` on the User model, and, in
  104.11 +the handler, if created=True, create the associated user profile.
  104.12 +
  104.13  For more information, see `Chapter 12 of the Django book`_.
  104.14  
  104.15  .. _Chapter 12 of the Django book: http://www.djangobook.com/en/1.0/chapter12/#cn222
  104.16 @@ -745,7 +751,7 @@
  104.17          <p>Your username and password didn't match. Please try again.</p>
  104.18          {% endif %}
  104.19  
  104.20 -        <form method="post" action=".">
  104.21 +        <form method="post" action="{% url django.contrib.auth.views.login %}">
  104.22          <table>
  104.23          <tr>
  104.24              <td>{{ form.username.label_tag }}</td>
  104.25 @@ -868,6 +874,34 @@
  104.26          * ``login_url``: The URL of the login page to redirect to. This will
  104.27            default to :setting:`settings.LOGIN_URL <LOGIN_URL>` if not supplied.
  104.28  
  104.29 +.. function:: password_reset_confirm(request[,uidb36, token, template_name, token_generator, set_password_form, post_reset_redirect])
  104.30 +
  104.31 +    Presents a form for entering a new password.
  104.32 +
  104.33 +    **Optional arguments:**
  104.34 +
  104.35 +        * ``uidb36``: The user's id encoded in base 36. This will default to
  104.36 +          ``None``.
  104.37 +        * ``token``: Token to check that the password is valid. This will default to ``None``.
  104.38 +        * ``template_name``: The full name of a template to display the confirm
  104.39 +          password view. Default value is :file:`registration/password_reset_confirm.html`.
  104.40 +        * ``token_generator``: Instance of the class to check the password. This
  104.41 +          will default to ``default_token_generator``, it's an instance of
  104.42 +          ``django.contrib.auth.tokens.PasswordResetTokenGenerator``.
  104.43 +        * ``set_password_form``: Form that will use to set the password. This will 
  104.44 +          default to ``SetPasswordForm``.
  104.45 +        * ``post_reset_redirect``: URL to redirect after the password reset
  104.46 +          done. This will default to ``None``.
  104.47 +
  104.48 +.. function:: password_reset_complete(request[,template_name])
  104.49 +
  104.50 +   Presents a view that informs that the password has been changed very well.
  104.51 +
  104.52 +   **Optional arguments:** 
  104.53 +
  104.54 +       * ``template_name``: The full name of a template to display the view.
  104.55 +         This will default to :file:`registration/password_reset_complete.html`.
  104.56 +
  104.57  Built-in forms
  104.58  --------------
  104.59  
  104.60 @@ -1125,10 +1159,10 @@
  104.61  Users
  104.62  -----
  104.63  
  104.64 -The currently logged-in user, either a
  104.65 -:class:`~django.contrib.auth.models.User` instance or an
  104.66 -:class:`~django.contrib.auth.models.AnonymousUser` instance, is stored in the
  104.67 -template variable ``{{ user }}``:
  104.68 +When rendering a template :class:`~django.template.context.RequestContext`, the
  104.69 +currently logged-in user, either a  :class:`~django.contrib.auth.models.User`
  104.70 +instance or an :class:`~django.contrib.auth.models.AnonymousUser` instance, is
  104.71 +stored in the template variable ``{{ user }}``:
  104.72  
  104.73  .. code-block:: html
  104.74  
  104.75 @@ -1138,6 +1172,9 @@
  104.76          <p>Welcome, new user. Please log in.</p>
  104.77      {% endif %}
  104.78  
  104.79 +This template context variable is not available if a ``RequestContext`` is not
  104.80 +being used.
  104.81 +
  104.82  Permissions
  104.83  -----------
  104.84  
   105.1 --- a/docs/topics/db/aggregation.txt	Sat Mar 28 12:05:48 2009 -0500
   105.2 +++ b/docs/topics/db/aggregation.txt	Wed Apr 01 13:05:19 2009 -0500
   105.3 @@ -146,12 +146,11 @@
   105.4  model being queried. However, sometimes the value you want to aggregate
   105.5  will belong to a model that is related to the model you are querying.
   105.6  
   105.7 -When specifying the field to be aggregated in an aggregate functions,
   105.8 -Django will allow you to use the same
   105.9 -:ref:`double underscore notation <field-lookups-intro>` that is used
  105.10 -when referring to related fields in filters. Django will then handle
  105.11 -any table joins that are required to retrieve and aggregate the
  105.12 -related value.
  105.13 +When specifying the field to be aggregated in an aggregate function, Django
  105.14 +will allow you to use the same :ref:`double underscore notation
  105.15 +<field-lookups-intro>` that is used when referring to related fields in
  105.16 +filters. Django will then handle any table joins that are required to retrieve
  105.17 +and aggregate the related value.
  105.18  
  105.19  For example, to find the price range of books offered in each store,
  105.20  you could use the annotation::
   106.1 --- a/docs/topics/db/models.txt	Sat Mar 28 12:05:48 2009 -0500
   106.2 +++ b/docs/topics/db/models.txt	Wed Apr 01 13:05:19 2009 -0500
   106.3 @@ -1,8 +1,8 @@
   106.4  .. _topics-db-models:
   106.5  
   106.6 -==============
   106.7 -Writing models
   106.8 -==============
   106.9 +======
  106.10 +Models
  106.11 +======
  106.12  
  106.13  .. module:: django.db.models
  106.14  
  106.15 @@ -871,7 +871,7 @@
  106.16  name will end up being different. For example::
  106.17  
  106.18      class Base(models.Model):
  106.19 -        m2m = models.ManyToMany(OtherModel, related_name="%(class)s_related")
  106.20 +        m2m = models.ManyToManyField(OtherModel, related_name="%(class)s_related")
  106.21  
  106.22          class Meta:
  106.23              abstract = True
  106.24 @@ -1019,10 +1019,11 @@
  106.25  original.
  106.26  
  106.27  Proxy models are declared like normal models. You tell Django that it's a
  106.28 -proxy model by setting the :attr:`~django.db.models.Options.proxy` attribute to of the ``Meta`` class to ``True``.
  106.29 +proxy model by setting the :attr:`~django.db.models.Options.proxy` attribute of
  106.30 +the ``Meta`` class to ``True``.
  106.31  
  106.32  For example, suppose you want to add a method to the standard ``User`` model
  106.33 -that will make be used in your templates. You can do it like this::
  106.34 +that will be used in your templates. You can do it like this::
  106.35  
  106.36      from django.contrib.auth.models import User
  106.37  
   107.1 --- a/docs/topics/forms/formsets.txt	Sat Mar 28 12:05:48 2009 -0500
   107.2 +++ b/docs/topics/forms/formsets.txt	Wed Apr 01 13:05:19 2009 -0500
   107.3 @@ -133,6 +133,20 @@
   107.4  you are adding new forms via JavaScript, you should increment the count fields
   107.5  in this form as well.
   107.6  
   107.7 +.. versionadded:: 1.1
   107.8 +
   107.9 +``total_form_count`` and ``initial_form_count``
  107.10 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  107.11 +
  107.12 +``BaseModelFormSet`` has a couple of methods that are closely related to the
  107.13 +``ManagementForm``, ``total_form_count`` and ``initial_form_count``.
  107.14 +
  107.15 +``total_form_count`` returns the total number of forms in this formset.
  107.16 +``initial_form_count`` returns the number of forms in the formset that were
  107.17 +pre-filled, and is also used to determine how many forms are required. You
  107.18 +will probably never need to override either of these methods, so please be
  107.19 +sure you understand what they do before doing so.
  107.20 +
  107.21  Custom formset validation
  107.22  ~~~~~~~~~~~~~~~~~~~~~~~~~
  107.23  
   108.1 --- a/docs/topics/forms/index.txt	Sat Mar 28 12:05:48 2009 -0500
   108.2 +++ b/docs/topics/forms/index.txt	Wed Apr 01 13:05:19 2009 -0500
   108.3 @@ -293,7 +293,7 @@
   108.4          message.
   108.5  
   108.6      ``field.is_hidden``
   108.7 -        This attribute is ``True`` is the form field is a hidden field and
   108.8 +        This attribute is ``True`` if the form field is a hidden field and
   108.9          ``False`` otherwise. It's not particularly useful as a template
  108.10          variable, but could be useful in conditional tests such as::
  108.11  
   109.1 --- a/docs/topics/http/shortcuts.txt	Sat Mar 28 12:05:48 2009 -0500
   109.2 +++ b/docs/topics/http/shortcuts.txt	Wed Apr 01 13:05:19 2009 -0500
   109.3 @@ -26,7 +26,7 @@
   109.4  ------------------
   109.5  
   109.6  ``template``
   109.7 -    The full name of a template to use.
   109.8 +    The full name of a template to use or sequence of template names.
   109.9  
  109.10  Optional arguments
  109.11  ------------------
  109.12 @@ -76,7 +76,7 @@
  109.13          # View code here...
  109.14          t = loader.get_template('myapp/template.html')
  109.15          c = Context({'foo': 'bar'})
  109.16 -        r = HttpResponse(t.render(c),
  109.17 +        return HttpResponse(t.render(c),
  109.18              mimetype="application/xhtml+xml")
  109.19  
  109.20  ``redirect``
   110.1 --- a/docs/topics/http/urls.txt	Sat Mar 28 12:05:48 2009 -0500
   110.2 +++ b/docs/topics/http/urls.txt	Wed Apr 01 13:05:19 2009 -0500
   110.3 @@ -623,16 +623,50 @@
   110.4  .. admonition:: Make sure your views are all correct
   110.5  
   110.6      As part of working out which URL names map to which patterns, the
   110.7 -    ``reverse()`` function has to import all of your URLConf files and examine
   110.8 +    ``reverse()`` function has to import all of your URLconf files and examine
   110.9      the name of each view. This involves importing each view function. If
  110.10      there are *any* errors whilst importing any of your view functions, it
  110.11      will cause ``reverse()`` to raise an error, even if that view function is
  110.12      not the one you are trying to reverse.
  110.13  
  110.14 -    Make sure that any views you reference in your URLConf files exist and can
  110.15 +    Make sure that any views you reference in your URLconf files exist and can
  110.16      be imported correctly. Do not include lines that reference views you
  110.17      haven't written yet, because those views will not be importable.
  110.18  
  110.19 +resolve()
  110.20 +---------
  110.21 +
  110.22 +The :func:`django.core.urlresolvers.resolve` function can be used for resolving
  110.23 +URL paths to the corresponding view functions. It has the following signature:
  110.24 +
  110.25 +.. currentmodule:: django.core.urlresolvers
  110.26 +.. function:: resolve(path, urlconf=None)
  110.27 +
  110.28 +``path`` is the URL path you want to resolve. As with ``reverse()`` above, you
  110.29 +don't need to worry about the ``urlconf`` parameter. The function returns the
  110.30 +triple (view function, arguments, keyword arguments).
  110.31 +
  110.32 +For example, it can be used for testing if a view would raise a ``Http404``
  110.33 +error before redirecting to it::
  110.34 +
  110.35 +    from urlparse import urlparse
  110.36 +    from django.core.urlresolvers import resolve
  110.37 +    from django.http import HttpResponseRedirect, Http404
  110.38 +
  110.39 +    def myview(request):
  110.40 +        next = request.META.get('HTTP_REFERER', None) or '/'
  110.41 +        response = HttpResponseRedirect(next)
  110.42 +
  110.43 +        # modify the request and response as required, e.g. change locale
  110.44 +        # and set corresponding locale cookie
  110.45 +
  110.46 +        view, args, kwargs = resolve(urlparse(next)[2])
  110.47 +        kwargs['request'] = request
  110.48 +        try:
  110.49 +            view(*args, **kwargs)
  110.50 +        except Http404:
  110.51 +            return HttpResponseRedirect('/')
  110.52 +        return response
  110.53  
  110.54  permalink()
  110.55  -----------
   111.1 --- a/docs/topics/install.txt	Sat Mar 28 12:05:48 2009 -0500
   111.2 +++ b/docs/topics/install.txt	Wed Apr 01 13:05:19 2009 -0500
   111.3 @@ -80,7 +80,7 @@
   111.4  * If you're using SQLite and either Python 2.3 or Python 2.4, you'll need
   111.5    pysqlite_. Use version 2.0.3 or higher. Python 2.5 ships with an SQLite
   111.6    wrapper in the standard library, so you don't need to install anything extra
   111.7 -  in that case.
   111.8 +  in that case. Please read the SQLite backend :ref:`notes<sqlite-notes>`.
   111.9  
  111.10  * If you're using Oracle, you'll need a copy of cx_Oracle_, but please
  111.11    read the database-specific notes for the
  111.12 @@ -106,7 +106,7 @@
  111.13  .. _compiled Windows version: http://stickpeople.com/projects/python/win-psycopg/
  111.14  .. _MySQLdb: http://sourceforge.net/projects/mysql-python
  111.15  .. _SQLite: http://www.sqlite.org/
  111.16 -.. _pysqlite: http://initd.org/pub/software/pysqlite/
  111.17 +.. _pysqlite: http://pysqlite.org/
  111.18  .. _cx_Oracle: http://cx-oracle.sourceforge.net/
  111.19  .. _Oracle: http://www.oracle.com/
  111.20  
  111.21 @@ -132,14 +132,14 @@
  111.22      The location of the ``site-packages`` directory depends on the operating
  111.23      system, and the location in which Python was installed. To find out your
  111.24      system's ``site-packages`` location, execute the following:
  111.25 -    
  111.26 +
  111.27      .. code-block:: bash
  111.28  
  111.29          python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
  111.30  
  111.31      (Note that this should be run from a shell prompt, not a Python interactive
  111.32      prompt.)
  111.33 -    
  111.34 +
  111.35  .. _install-django-code:
  111.36  
  111.37  Install the Django code
  111.38 @@ -190,7 +190,7 @@
  111.39  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  111.40  
  111.41  .. admonition:: Tracking Django development
  111.42 -    
  111.43 +
  111.44      If you decide to use the latest development version of Django,
  111.45      you'll want to pay close attention to `the development timeline`_,
  111.46      and you'll want to keep an eye on `the list of
  111.47 @@ -219,7 +219,7 @@
  111.48  3. Next, make sure that the Python interpreter can load Django's code. There
  111.49     are various ways of accomplishing this.  One of the most convenient, on
  111.50     Linux, Mac OSX or other Unix-like systems, is to use a symbolic link:
  111.51 -   
  111.52 +
  111.53     .. code-block:: bash
  111.54  
  111.55         ln -s `pwd`/django-trunk/django SITE-PACKAGES-DIR/django
  111.56 @@ -248,7 +248,7 @@
  111.57  4. On Unix-like systems, create a symbolic link to the file
  111.58     ``django-trunk/django/bin/django-admin.py`` in a directory on your system
  111.59     path, such as ``/usr/local/bin``. For example:
  111.60 -   
  111.61 +
  111.62     .. code-block:: bash
  111.63  
  111.64         ln -s `pwd`/django-trunk/django/bin/django-admin.py /usr/local/bin
   112.1 --- a/docs/topics/testing.txt	Sat Mar 28 12:05:48 2009 -0500
   112.2 +++ b/docs/topics/testing.txt	Wed Apr 01 13:05:19 2009 -0500
   112.3 @@ -138,10 +138,11 @@
   112.4  In the case of model tests, note that the test runner takes care of creating
   112.5  its own test database. That is, any test that accesses a database -- by
   112.6  creating and saving model instances, for example -- will not affect your
   112.7 -production database. Each doctest begins with a "blank slate" -- a fresh
   112.8 -database containing an empty table for each model. (See the section on
   112.9 -fixtures, below, for more on this.) Note that to use this feature, the database
  112.10 -user Django is connecting as must have ``CREATE DATABASE`` rights.
  112.11 +production database. However, the database is not refreshed between doctests,
  112.12 +so if your doctest requires a certain state you should consider flushin the 
  112.13 +database or loading a fixture. (See the section on fixtures, below, for more 
  112.14 +on this.) Note that to use this feature, the database user Django is connecting
  112.15 +as must have ``CREATE DATABASE`` rights.
  112.16  
  112.17  For more details about how doctest works, see the `standard library
  112.18  documentation for doctest`_.
   113.1 --- a/tests/modeltests/many_to_many/models.py	Sat Mar 28 12:05:48 2009 -0500
   113.2 +++ b/tests/modeltests/many_to_many/models.py	Wed Apr 01 13:05:19 2009 -0500
   113.3 @@ -61,6 +61,12 @@
   113.4  # Adding a second time is OK
   113.5  >>> a2.publications.add(p3)
   113.6  
   113.7 +# Adding an object of the wrong type raises TypeError
   113.8 +>>> a2.publications.add(a1)
   113.9 +Traceback (most recent call last):
  113.10 +...
  113.11 +TypeError: 'Publication' instance expected
  113.12 +
  113.13  # Add a Publication directly via publications.add by using keyword arguments.
  113.14  >>> new_publication = a2.publications.create(title='Highlights for Children')
  113.15  
   114.1 --- a/tests/modeltests/many_to_one/models.py	Sat Mar 28 12:05:48 2009 -0500
   114.2 +++ b/tests/modeltests/many_to_one/models.py	Wed Apr 01 13:05:19 2009 -0500
   114.3 @@ -72,6 +72,13 @@
   114.4  >>> r2.article_set.add(new_article2)
   114.5  >>> new_article2.reporter.id
   114.6  2
   114.7 +
   114.8 +# Adding an object of the wrong type raises TypeError
   114.9 +>>> r.article_set.add(r2)
  114.10 +Traceback (most recent call last):
  114.11 +...
  114.12 +TypeError: 'Article' instance expected
  114.13 +
  114.14  >>> r.article_set.all()
  114.15  [<Article: John's second story>, <Article: This is a test>]
  114.16  >>> r2.article_set.all()
   115.1 --- a/tests/modeltests/model_forms/models.py	Sat Mar 28 12:05:48 2009 -0500
   115.2 +++ b/tests/modeltests/model_forms/models.py	Wed Apr 01 13:05:19 2009 -0500
   115.3 @@ -93,7 +93,7 @@
   115.4  
   115.5  class TextFile(models.Model):
   115.6      description = models.CharField(max_length=20)
   115.7 -    file = models.FileField(storage=temp_storage, upload_to='tests')
   115.8 +    file = models.FileField(storage=temp_storage, upload_to='tests', max_length=15)
   115.9  
  115.10      def __unicode__(self):
  115.11          return self.description
  115.12 @@ -857,6 +857,10 @@
  115.13  Traceback (most recent call last):
  115.14  ...
  115.15  ValidationError: [u'Enter a list of values.']
  115.16 +>>> f.clean(['fail'])
  115.17 +Traceback (most recent call last):
  115.18 +...
  115.19 +ValidationError: [u'"fail" is not a valid value for a primary key.']
  115.20  
  115.21  # Add a Category object *after* the ModelMultipleChoiceField has already been
  115.22  # instantiated. This proves clean() checks the database during clean() rather
  115.23 @@ -1018,6 +1022,11 @@
  115.24  >>> instance.file
  115.25  <FieldFile: tests/test1.txt>
  115.26  
  115.27 +# Check if the max_length attribute has been inherited from the model.
  115.28 +>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test-maxlength.txt', 'hello world')})
  115.29 +>>> f.is_valid()
  115.30 +False
  115.31 +
  115.32  # Edit an instance that already has the file defined in the model. This will not
  115.33  # save the file again, but leave it exactly as it is.
  115.34  
   116.1 --- a/tests/modeltests/model_formsets/models.py	Sat Mar 28 12:05:48 2009 -0500
   116.2 +++ b/tests/modeltests/model_formsets/models.py	Wed Apr 01 13:05:19 2009 -0500
   116.3 @@ -1,6 +1,4 @@
   116.4 -
   116.5  import datetime
   116.6 -
   116.7  from django import forms
   116.8  from django.db import models
   116.9  
  116.10 @@ -27,7 +25,7 @@
  116.11  
  116.12      def __unicode__(self):
  116.13          return self.title
  116.14 -    
  116.15 +
  116.16  class BookWithCustomPK(models.Model):
  116.17      my_pk = models.DecimalField(max_digits=5, decimal_places=0, primary_key=True)
  116.18      author = models.ForeignKey(Author)
  116.19 @@ -35,13 +33,13 @@
  116.20  
  116.21      def __unicode__(self):
  116.22          return u'%s: %s' % (self.my_pk, self.title)
  116.23 -    
  116.24 +
  116.25  class AlternateBook(Book):
  116.26      notes = models.CharField(max_length=100)
  116.27 -    
  116.28 +
  116.29      def __unicode__(self):
  116.30          return u'%s - %s' % (self.title, self.notes)
  116.31 -    
  116.32 +
  116.33  class AuthorMeeting(models.Model):
  116.34      name = models.CharField(max_length=100)
  116.35      authors = models.ManyToManyField(Author)
  116.36 @@ -68,7 +66,7 @@
  116.37      auto_id = models.AutoField(primary_key=True)
  116.38      name = models.CharField(max_length=100)
  116.39      place = models.ForeignKey(Place)
  116.40 -    
  116.41 +
  116.42      def __unicode__(self):
  116.43          return "%s at %s" % (self.name, self.place)
  116.44  
  116.45 @@ -81,7 +79,7 @@
  116.46  class OwnerProfile(models.Model):
  116.47      owner = models.OneToOneField(Owner, primary_key=True)
  116.48      age = models.PositiveIntegerField()
  116.49 -    
  116.50 +
  116.51      def __unicode__(self):
  116.52          return "%s is %d" % (self.owner.name, self.age)
  116.53  
  116.54 @@ -114,17 +112,17 @@
  116.55  # using inlineformset_factory.
  116.56  class Repository(models.Model):
  116.57      name = models.CharField(max_length=25)
  116.58 -    
  116.59 +
  116.60      def __unicode__(self):
  116.61          return self.name
  116.62  
  116.63  class Revision(models.Model):
  116.64      repository = models.ForeignKey(Repository)
  116.65      revision = models.CharField(max_length=40)
  116.66 -    
  116.67 +
  116.68      class Meta:
  116.69          unique_together = (("repository", "revision"),)
  116.70 -    
  116.71 +
  116.72      def __unicode__(self):
  116.73          return u"%s (%s)" % (self.revision, unicode(self.repository))
  116.74  
  116.75 @@ -146,7 +144,21 @@
  116.76  class Player(models.Model):
  116.77      team = models.ForeignKey(Team, null=True)
  116.78      name = models.CharField(max_length=100)
  116.79 -    
  116.80 +
  116.81 +    def __unicode__(self):
  116.82 +        return self.name
  116.83 +
  116.84 +# Models for testing custom ModelForm save methods in formsets and inline formsets
  116.85 +class Poet(models.Model):
  116.86 +    name = models.CharField(max_length=100)
  116.87 +
  116.88 +    def __unicode__(self):
  116.89 +        return self.name
  116.90 +
  116.91 +class Poem(models.Model):
  116.92 +    poet = models.ForeignKey(Poet)
  116.93 +    name = models.CharField(max_length=100)
  116.94 +
  116.95      def __unicode__(self):
  116.96          return self.name
  116.97  
  116.98 @@ -337,13 +349,44 @@
  116.99  
 116.100  >>> AuthorFormSet = modelformset_factory(Author, max_num=2)
 116.101  >>> formset = AuthorFormSet(queryset=qs)
 116.102 ->>> [sorted(x.items()) for x in formset.initial]
 116.103 -[[('id', 1), ('name', u'Charles Baudelaire')], [('id', 3), ('name', u'Paul Verlaine')]]
 116.104 +>>> [x.name for x in formset.get_queryset()]
 116.105 +[u'Charles Baudelaire', u'Paul Verlaine']
 116.106  
 116.107  >>> AuthorFormSet = modelformset_factory(Author, max_num=3)
 116.108  >>> formset = AuthorFormSet(queryset=qs)
 116.109 ->>> [sorted(x.items()) for x in formset.initial]
 116.110 -[[('id', 1), ('name', u'Charles Baudelaire')], [('id', 3), ('name', u'Paul Verlaine')], [('id', 2), ('name', u'Walt Whitman')]]
 116.111 +>>> [x.name for x in formset.get_queryset()]
 116.112 +[u'Charles Baudelaire', u'Paul Verlaine', u'Walt Whitman']
 116.113 +
 116.114 +
 116.115 +# ModelForm with a custom save method in a formset ###########################
 116.116 +
 116.117 +>>> class PoetForm(forms.ModelForm):
 116.118 +...     def save(self, commit=True):
 116.119 +...         # change the name to "Vladimir Mayakovsky" just to be a jerk.
 116.120 +...         author = super(PoetForm, self).save(commit=False)
 116.121 +...         author.name = u"Vladimir Mayakovsky"
 116.122 +...         if commit:
 116.123 +...             author.save()
 116.124 +...         return author
 116.125 +
 116.126 +>>> PoetFormSet = modelformset_factory(Poet, form=PoetForm)
 116.127 +
 116.128 +>>> data = {
 116.129 +...     'form-TOTAL_FORMS': '3', # the number of forms rendered
 116.130 +...     'form-INITIAL_FORMS': '0', # the number of forms with initial data
 116.131 +...     'form-0-name': 'Walt Whitman',
 116.132 +...     'form-1-name': 'Charles Baudelaire',
 116.133 +...     'form-2-name': '',
 116.134 +... }
 116.135 +
 116.136 +>>> qs = Poet.objects.all()
 116.137 +>>> formset = PoetFormSet(data=data, queryset=qs)
 116.138 +>>> formset.is_valid()
 116.139 +True
 116.140 +
 116.141 +>>> formset.save()
 116.142 +[<Poet: Vladimir Mayakovsky>, <Poet: Vladimir Mayakovsky>]
 116.143 +
 116.144  
 116.145  # Model inheritance in model formsets ########################################
 116.146  
 116.147 @@ -553,6 +596,36 @@
 116.148  [<AlternateBook: Flowers of Evil - English translation of Les Fleurs du Mal>]
 116.149  
 116.150  
 116.151 +# ModelForm with a custom save method in an inline formset ###################
 116.152 +
 116.153 +>>> class PoemForm(forms.ModelForm):
 116.154 +...     def save(self, commit=True):
 116.155 +...         # change the name to "Brooklyn Bridge" just to be a jerk.
 116.156 +...         poem = super(PoemForm, self).save(commit=False)
 116.157 +...         poem.name = u"Brooklyn Bridge"
 116.158 +...         if commit:
 116.159 +...             poem.save()
 116.160 +...         return poem
 116.161 +
 116.162 +>>> PoemFormSet = inlineformset_factory(Poet, Poem, form=PoemForm)
 116.163 +
 116.164 +>>> data = {
 116.165 +...     'poem_set-TOTAL_FORMS': '3', # the number of forms rendered
 116.166 +...     'poem_set-INITIAL_FORMS': '0', # the number of forms with initial data
 116.167 +...     'poem_set-0-name': 'The Cloud in Trousers',
 116.168 +...     'poem_set-1-name': 'I',
 116.169 +...     'poem_set-2-name': '',
 116.170 +... }
 116.171 +
 116.172 +>>> poet = Poet.objects.create(name='Vladimir Mayakovsky')
 116.173 +>>> formset = PoemFormSet(data=data, instance=poet)
 116.174 +>>> formset.is_valid()
 116.175 +True
 116.176 +
 116.177 +>>> formset.save()
 116.178 +[<Poem: Brooklyn Bridge>, <Poem: Brooklyn Bridge>]
 116.179 +
 116.180 +
 116.181  # Test a custom primary key ###################################################
 116.182  
 116.183  We need to ensure that it is displayed
   117.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   117.2 +++ b/tests/modeltests/model_formsets/tests.py	Wed Apr 01 13:05:19 2009 -0500
   117.3 @@ -0,0 +1,70 @@
   117.4 +from django.test import TestCase
   117.5 +from django.forms.models import modelformset_factory
   117.6 +from modeltests.model_formsets.models import Poet, Poem
   117.7 +
   117.8 +class DeletionTests(TestCase):
   117.9 +    def test_deletion(self):
  117.10 +        PoetFormSet = modelformset_factory(Poet, can_delete=True)
  117.11 +        poet = Poet.objects.create(name='test')
  117.12 +        data = {
  117.13 +            'form-TOTAL_FORMS': u'1',
  117.14 +            'form-INITIAL_FORMS': u'1',
  117.15 +            'form-0-id': u'1',
  117.16 +            'form-0-name': u'test',
  117.17 +            'form-0-DELETE': u'on',
  117.18 +        }
  117.19 +        formset = PoetFormSet(data, queryset=Poet.objects.all())
  117.20 +        formset.save()
  117.21 +        self.assertTrue(formset.is_valid())
  117.22 +        self.assertEqual(Poet.objects.count(), 0)
  117.23 +
  117.24 +    def test_add_form_deletion_when_invalid(self):
  117.25 +        """
  117.26 +        Make sure that an add form that is filled out, but marked for deletion
  117.27 +        doesn't cause validation errors.
  117.28 +        """
  117.29 +        PoetFormSet = modelformset_factory(Poet, can_delete=True)
  117.30 +        data = {
  117.31 +            'form-TOTAL_FORMS': u'1',
  117.32 +            'form-INITIAL_FORMS': u'0',
  117.33 +            'form-0-id': u'',
  117.34 +            'form-0-name': u'x' * 1000,
  117.35 +        }
  117.36 +        formset = PoetFormSet(data, queryset=Poet.objects.all())
  117.37 +        # Make sure this form doesn't pass validation.
  117.38 +        self.assertEqual(formset.is_valid(), False)
  117.39 +        self.assertEqual(Poet.objects.count(), 0)
  117.40 +
  117.41 +        # Then make sure that it *does* pass validation and delete the object,
  117.42 +        # even though the data isn't actually valid.
  117.43 +        data['form-0-DELETE'] = 'on'
  117.44 +        formset = PoetFormSet(data, queryset=Poet.objects.all())
  117.45 +        self.assertEqual(formset.is_valid(), True)
  117.46 +        formset.save()
  117.47 +        self.assertEqual(Poet.objects.count(), 0)
  117.48 +
  117.49 +    def test_change_form_deletion_when_invalid(self):
  117.50 +        """
  117.51 +        Make sure that an add form that is filled out, but marked for deletion
  117.52 +        doesn't cause validation errors.
  117.53 +        """
  117.54 +        PoetFormSet = modelformset_factory(Poet, can_delete=True)
  117.55 +        poet = Poet.objects.create(name='test')
  117.56 +        data = {
  117.57 +            'form-TOTAL_FORMS': u'1',
  117.58 +            'form-INITIAL_FORMS': u'1',
  117.59 +            'form-0-id': u'1',
  117.60 +            'form-0-name': u'x' * 1000,
  117.61 +        }
  117.62 +        formset = PoetFormSet(data, queryset=Poet.objects.all())
  117.63 +        # Make sure this form doesn't pass validation.
  117.64 +        self.assertEqual(formset.is_valid(), False)
  117.65 +        self.assertEqual(Poet.objects.count(), 1)
  117.66 +
  117.67 +        # Then make sure that it *does* pass validation and delete the object,
  117.68 +        # even though the data isn't actually valid.
  117.69 +        data['form-0-DELETE'] = 'on'
  117.70 +        formset = PoetFormSet(data, queryset=Poet.objects.all())
  117.71 +        self.assertEqual(formset.is_valid(), True)
  117.72 +        formset.save()
  117.73 +        self.assertEqual(Poet.objects.count(), 0)
   118.1 --- a/tests/modeltests/one_to_one/models.py	Sat Mar 28 12:05:48 2009 -0500
   118.2 +++ b/tests/modeltests/one_to_one/models.py	Wed Apr 01 13:05:19 2009 -0500
   118.3 @@ -79,6 +79,8 @@
   118.4  <Restaurant: Ace Hardware the restaurant>
   118.5  >>> r.place
   118.6  <Place: Ace Hardware the place>
   118.7 +>>> p2.id
   118.8 +2
   118.9  
  118.10  # Set the place back again, using assignment in the reverse direction.
  118.11  >>> p1.restaurant = r
   119.1 --- a/tests/modeltests/test_client/models.py	Sat Mar 28 12:05:48 2009 -0500
   119.2 +++ b/tests/modeltests/test_client/models.py	Wed Apr 01 13:05:19 2009 -0500
   119.3 @@ -423,4 +423,3 @@
   119.4          self.assertEqual(mail.outbox[1].from_email, 'from@example.com')
   119.5          self.assertEqual(mail.outbox[1].to[0], 'second@example.com')
   119.6          self.assertEqual(mail.outbox[1].to[1], 'third@example.com')
   119.7 -
   120.1 --- a/tests/regressiontests/admin_views/customadmin.py	Sat Mar 28 12:05:48 2009 -0500
   120.2 +++ b/tests/regressiontests/admin_views/customadmin.py	Wed Apr 01 13:05:19 2009 -0500
   120.3 @@ -28,3 +28,4 @@
   120.4  site.register(models.Article, models.ArticleAdmin)
   120.5  site.register(models.Section, inlines=[models.ArticleInline])
   120.6  site.register(models.Thing, models.ThingAdmin)
   120.7 +site.register(models.Fabric, models.FabricAdmin)
   121.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   121.2 +++ b/tests/regressiontests/admin_views/fixtures/admin-views-fabrics.xml	Wed Apr 01 13:05:19 2009 -0500
   121.3 @@ -0,0 +1,12 @@
   121.4 +<?xml version="1.0" encoding="utf-8"?>
   121.5 +<django-objects version="1.0">
   121.6 +  <object pk="1" model="admin_views.fabric">
   121.7 +    <field type="CharField" name="surface">x</field>
   121.8 +  </object>
   121.9 +  <object pk="2" model="admin_views.fabric">
  121.10 +    <field type="CharField" name="surface">y</field>
  121.11 +  </object>
  121.12 +  <object pk="3" model="admin_views.fabric">
  121.13 +    <field type="CharField" name="surface">plain</field>
  121.14 +  </object>
  121.15 +</django-objects>
   122.1 --- a/tests/regressiontests/admin_views/models.py	Sat Mar 28 12:05:48 2009 -0500
   122.2 +++ b/tests/regressiontests/admin_views/models.py	Wed Apr 01 13:05:19 2009 -0500
   122.3 @@ -135,6 +135,21 @@
   122.4  class ThingAdmin(admin.ModelAdmin):
   122.5      list_filter = ('color',)
   122.6  
   122.7 +class Fabric(models.Model):
   122.8 +    NG_CHOICES = (
   122.9 +        ('Textured', (
  122.10 +                ('x', 'Horizontal'),
  122.11 +                ('y', 'Vertical'),
  122.12 +            )
  122.13 +        ),
  122.14 +        ('plain', 'Smooth'),
  122.15 +    )
  122.16 +    surface = models.CharField(max_length=20, choices=NG_CHOICES)
  122.17 +
  122.18 +class FabricAdmin(admin.ModelAdmin):
  122.19 +    list_display = ('surface',)
  122.20 +    list_filter = ('surface',)
  122.21 +
  122.22  class Person(models.Model):
  122.23      GENDER_CHOICES = (
  122.24          (1, "Male"),
  122.25 @@ -143,10 +158,10 @@
  122.26      name = models.CharField(max_length=100)
  122.27      gender = models.IntegerField(choices=GENDER_CHOICES)
  122.28      alive = models.BooleanField()
  122.29 -    
  122.30 +
  122.31      def __unicode__(self):
  122.32          return self.name
  122.33 -    
  122.34 +
  122.35      class Meta:
  122.36          ordering = ["id"]
  122.37  
  122.38 @@ -236,6 +251,40 @@
  122.39  class ExternalSubscriberAdmin(admin.ModelAdmin):
  122.40      actions = [external_mail, redirect_to]
  122.41  
  122.42 +class Media(models.Model):
  122.43 +    name = models.CharField(max_length=60)
  122.44 +
  122.45 +class Podcast(Media):
  122.46 +    release_date = models.DateField()
  122.47 +
  122.48 +class PodcastAdmin(admin.ModelAdmin):
  122.49 +    list_display = ('name', 'release_date')
  122.50 +    list_editable = ('release_date',)
  122.51 +
  122.52 +    ordering = ('name',)
  122.53 +
  122.54 +class Parent(models.Model):
  122.55 +    name = models.CharField(max_length=128)
  122.56 +
  122.57 +class Child(models.Model):
  122.58 +    parent = models.ForeignKey(Parent, editable=False)
  122.59 +    name = models.CharField(max_length=30, blank=True)
  122.60 +
  122.61 +class ChildInline(admin.StackedInline):
  122.62 +    model = Child
  122.63 +
  122.64 +class ParentAdmin(admin.ModelAdmin):
  122.65 +    model = Parent
  122.66 +    inlines = [ChildInline]
  122.67 +
  122.68 +class EmptyModel(models.Model):
  122.69 +    def __unicode__(self):
  122.70 +        return "Primary key = %s" % self.id
  122.71 +
  122.72 +class EmptyModelAdmin(admin.ModelAdmin):
  122.73 +    def queryset(self, request):
  122.74 +        return super(EmptyModelAdmin, self).queryset(request).filter(pk__gt=1)
  122.75 +
  122.76  admin.site.register(Article, ArticleAdmin)
  122.77  admin.site.register(CustomArticle, CustomArticleAdmin)
  122.78  admin.site.register(Section, inlines=[ArticleInline])
  122.79 @@ -246,6 +295,10 @@
  122.80  admin.site.register(Persona, PersonaAdmin)
  122.81  admin.site.register(Subscriber, SubscriberAdmin)
  122.82  admin.site.register(ExternalSubscriber, ExternalSubscriberAdmin)
  122.83 +admin.site.register(Podcast, PodcastAdmin)
  122.84 +admin.site.register(Parent, ParentAdmin)
  122.85 +admin.site.register(EmptyModel, EmptyModelAdmin)
  122.86 +admin.site.register(Fabric, FabricAdmin)
  122.87  
  122.88  # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
  122.89  # That way we cover all four cases:
  122.90 @@ -259,5 +312,3 @@
  122.91  admin.site.register(Book, inlines=[ChapterInline])
  122.92  admin.site.register(Promo)
  122.93  admin.site.register(ChapterXtra1)
  122.94 -
  122.95 -
   123.1 --- a/tests/regressiontests/admin_views/tests.py	Sat Mar 28 12:05:48 2009 -0500
   123.2 +++ b/tests/regressiontests/admin_views/tests.py	Wed Apr 01 13:05:19 2009 -0500
   123.3 @@ -1,6 +1,7 @@
   123.4  # coding: utf-8
   123.5  
   123.6  import re
   123.7 +import datetime
   123.8  
   123.9  from django.test import TestCase
  123.10  from django.contrib.auth.models import User, Permission
  123.11 @@ -12,7 +13,7 @@
  123.12  from django.utils.html import escape
  123.13  
  123.14  # local test models
  123.15 -from models import Article, CustomArticle, Section, ModelWithStringPrimaryKey, Person, Persona, FooAccount, BarAccount, Subscriber, ExternalSubscriber
  123.16 +from models import Article, CustomArticle, Section, ModelWithStringPrimaryKey, Person, Persona, FooAccount, BarAccount, Subscriber, ExternalSubscriber, Podcast, EmptyModel
  123.17  
  123.18  try:
  123.19      set
  123.20 @@ -20,7 +21,7 @@
  123.21      from sets import Set as set
  123.22  
  123.23  class AdminViewBasicTest(TestCase):
  123.24 -    fixtures = ['admin-views-users.xml', 'admin-views-colors.xml']
  123.25 +    fixtures = ['admin-views-users.xml', 'admin-views-colors.xml', 'admin-views-fabrics.xml']
  123.26  
  123.27      # Store the bit of the URL where the admin is registered as a class
  123.28      # variable. That way we can test a second AdminSite just by subclassing
  123.29 @@ -181,6 +182,37 @@
  123.30          response = self.client.get('/test_admin/%s/admin_views/thing/' % self.urlbit, {'color__id__exact': 'StringNotInteger!'})
  123.31          self.assertRedirects(response, '/test_admin/%s/admin_views/thing/?e=1' % self.urlbit)
  123.32  
  123.33 +    def testNamedGroupFieldChoicesChangeList(self):
  123.34 +        """
  123.35 +        Ensures the admin changelist shows correct values in the relevant column
  123.36 +        for rows corresponding to instances of a model in which a named group
  123.37 +        has been used in the choices option of a field.
  123.38 +        """
  123.39 +        response = self.client.get('/test_admin/%s/admin_views/fabric/' % self.urlbit)
  123.40 +        self.failUnlessEqual(response.status_code, 200)
  123.41 +        self.failUnless(
  123.42 +            '<a href="1/">Horizontal</a>' in response.content and
  123.43 +            '<a href="2/">Vertical</a>' in response.content,
  123.44 +            "Changelist table isn't showing the right human-readable values set by a model field 'choices' option named group."
  123.45 +        )
  123.46 +
  123.47 +    def testNamedGroupFieldChoicesFilter(self):
  123.48 +        """
  123.49 +        Ensures the filter UI shows correctly when at least one named group has
  123.50 +        been used in the choices option of a model field.
  123.51 +        """
  123.52 +        response = self.client.get('/test_admin/%s/admin_views/fabric/' % self.urlbit)
  123.53 +        self.failUnlessEqual(response.status_code, 200)
  123.54 +        self.failUnless(
  123.55 +            '<div id="changelist-filter">' in response.content,
  123.56 +            "Expected filter not found in changelist view."
  123.57 +        )
  123.58 +        self.failUnless(
  123.59 +            '<a href="?surface__exact=x">Horizontal</a>' in response.content and
  123.60 +            '<a href="?surface__exact=y">Vertical</a>' in response.content,
  123.61 +            "Changelist filter isn't showing options contained inside a model field 'choices' option named group."
  123.62 +        )
  123.63 +
  123.64  class CustomModelAdminTest(AdminViewBasicTest):
  123.65      urlbit = "admin2"
  123.66  
  123.67 @@ -740,6 +772,12 @@
  123.68      def tearDown(self):
  123.69          self.client.logout()
  123.70  
  123.71 +    def test_inheritance(self):
  123.72 +        Podcast.objects.create(name="This Week in Django",
  123.73 +            release_date=datetime.date.today())
  123.74 +        response = self.client.get('/test_admin/admin/admin_views/podcast/')
  123.75 +        self.failUnlessEqual(response.status_code, 200)
  123.76 +
  123.77      def test_changelist_input_html(self):
  123.78          response = self.client.get('/test_admin/admin/admin_views/person/')
  123.79          # 2 inputs per object(the field and the hidden id field) = 6
  123.80 @@ -939,3 +977,44 @@
  123.81          }
  123.82          response = self.client.post('/test_admin/admin/admin_views/externalsubscriber/', action_data)
  123.83          self.failUnlessEqual(response.status_code, 302)
  123.84 +
  123.85 +class TestInlineNotEditable(TestCase):
  123.86 +    fixtures = ['admin-views-users.xml']
  123.87 +
  123.88 +    def setUp(self):
  123.89 +        result = self.client.login(username='super', password='secret')
  123.90 +        self.failUnlessEqual(result, True)
  123.91 +
  123.92 +    def tearDown(self):
  123.93 +        self.client.logout()
  123.94 +
  123.95 +    def test(self):
  123.96 +        """
  123.97 +        InlineModelAdmin broken?
  123.98 +        """
  123.99 +        response = self.client.get('/test_admin/admin/admin_views/parent/add/')
 123.100 +        self.failUnlessEqual(response.status_code, 200)
 123.101 +
 123.102 +
 123.103 +class AdminCustomQuerysetTest(TestCase):
 123.104 +    fixtures = ['admin-views-users.xml']
 123.105 +
 123.106 +    def setUp(self):
 123.107 +        self.client.login(username='super', password='secret')
 123.108 +        self.pks = [EmptyModel.objects.create().id for i in range(3)]
 123.109 +
 123.110 +    def test_changelist_view(self):
 123.111 +        response = self.client.get('/test_admin/admin/admin_views/emptymodel/')
 123.112 +        for i in self.pks:
 123.113 +            if i > 1:
 123.114 +                self.assertContains(response, 'Primary key = %s' % i)
 123.115 +            else:
 123.116 +                self.assertNotContains(response, 'Primary key = %s' % i)
 123.117 +
 123.118 +    def test_change_view(self):
 123.119 +        for i in self.pks:
 123.120 +            response = self.client.get('/test_admin/admin/admin_views/emptymodel/%s/' % i)
 123.121 +            if i > 1:
 123.122 +                self.assertEqual(response.status_code, 200)
 123.123 +            else:
 123.124 +                self.assertEqual(response.status_code, 404)
   124.1 --- a/tests/regressiontests/admin_widgets/tests.py	Sat Mar 28 12:05:48 2009 -0500
   124.2 +++ b/tests/regressiontests/admin_widgets/tests.py	Wed Apr 01 13:05:19 2009 -0500
   124.3 @@ -110,3 +110,16 @@
   124.4          response = self.client.get("/widget_admin/admin_widgets/cartire/add/")
   124.5          self.assert_("BMW M3" not in response.content)
   124.6          self.assert_("Volkswagon Passat" in response.content)
   124.7 +
   124.8 +class AdminForeignKeyWidgetChangeList(DjangoTestCase):
   124.9 +    fixtures = ["admin-widgets-users.xml"]
  124.10 +    
  124.11 +    def setUp(self):
  124.12 +        self.client.login(username="super", password="secret")
  124.13 +    
  124.14 +    def tearDown(self):
  124.15 +        self.client.logout()
  124.16 +    
  124.17 +    def test_changelist_foreignkey(self):
  124.18 +        response = self.client.get('/widget_admin/admin_widgets/car/')
  124.19 +        self.failUnless('/widget_admin/auth/user/add/' in response.content)
   125.1 --- a/tests/regressiontests/admin_widgets/widgetadmin.py	Sat Mar 28 12:05:48 2009 -0500
   125.2 +++ b/tests/regressiontests/admin_widgets/widgetadmin.py	Wed Apr 01 13:05:19 2009 -0500
   125.3 @@ -8,6 +8,9 @@
   125.4  class WidgetAdmin(admin.AdminSite):
   125.5      pass
   125.6  
   125.7 +class CarAdmin(admin.ModelAdmin):
   125.8 +    list_display = ['make', 'model', 'owner']
   125.9 +    list_editable = ['owner']
  125.10  
  125.11  class CarTireAdmin(admin.ModelAdmin):
  125.12      def formfield_for_foreignkey(self, db_field, request, **kwargs):
  125.13 @@ -18,5 +21,6 @@
  125.14  
  125.15  site = WidgetAdmin()
  125.16  
  125.17 -site.register(models.Car)
  125.18 +site.register(models.User)
  125.19 +site.register(models.Car, CarAdmin)
  125.20  site.register(models.CarTire, CarTireAdmin)
   126.1 --- a/tests/regressiontests/backends/tests.py	Sat Mar 28 12:05:48 2009 -0500
   126.2 +++ b/tests/regressiontests/backends/tests.py	Wed Apr 01 13:05:19 2009 -0500
   126.3 @@ -20,15 +20,12 @@
   126.4  >>> cursor = connection.cursor()
   126.5  """
   126.6  # -*- coding: utf-8 -*-
   126.7 -
   126.8 -# Unit tests for specific database backends.
   126.9 -
  126.10 +# Unit and doctests for specific database backends.
  126.11  import unittest
  126.12 -
  126.13  from django.db import connection
  126.14 +from django.db.backends.signals import connection_created
  126.15  from django.conf import settings
  126.16  
  126.17 -
  126.18  class Callproc(unittest.TestCase):
  126.19  
  126.20      def test_dbms_session(self):
  126.21 @@ -42,6 +39,23 @@
  126.22          else:
  126.23              return True
  126.24  
  126.25 +def connection_created_test(sender, **kwargs):
  126.26 +    print 'connection_created signal'
  126.27 +
  126.28 +__test__ = {'API_TESTS': ''}
  126.29 +
  126.30 +# Unfortunately with sqlite3 the in-memory test database cannot be
  126.31 +# closed, and so it cannot be re-opened during testing, and so we
  126.32 +# sadly disable this test for now.
  126.33 +if settings.DATABASE_ENGINE != 'sqlite3':
  126.34 +    __test__['API_TESTS'] += """
  126.35 +>>> connection_created.connect(connection_created_test)
  126.36 +>>> connection.close() # Ensure the connection is closed
  126.37 +>>> cursor = connection.cursor()
  126.38 +connection_created signal
  126.39 +>>> connection_created.disconnect(connection_created_test)
  126.40 +>>> cursor = connection.cursor()
  126.41 +"""
  126.42  
  126.43  if __name__ == '__main__':
  126.44      unittest.main()
   127.1 --- a/tests/regressiontests/datastructures/tests.py	Sat Mar 28 12:05:48 2009 -0500
   127.2 +++ b/tests/regressiontests/datastructures/tests.py	Wed Apr 01 13:05:19 2009 -0500
   127.3 @@ -45,6 +45,8 @@
   127.4  ['Adrian', 'Simon']
   127.5  >>> list(d.iteritems())
   127.6  [('position', 'Developer'), ('name', 'Simon')]
   127.7 +>>> list(d.iterlists())
   127.8 +[('position', ['Developer']), ('name', ['Adrian', 'Simon'])]
   127.9  >>> d['lastname']
  127.10  Traceback (most recent call last):
  127.11  ...
  127.12 @@ -58,6 +60,10 @@
  127.13  >>> d.setlist('lastname', ['Holovaty', 'Willison'])
  127.14  >>> d.getlist('lastname')
  127.15  ['Holovaty', 'Willison']
  127.16 +>>> d.values() 
  127.17 +['Developer', 'Simon', 'Willison']
  127.18 +>>> list(d.itervalues()) 
  127.19 +['Developer', 'Simon', 'Willison']
  127.20  
  127.21  ### SortedDict #################################################################
  127.22  
   128.1 --- a/tests/regressiontests/decorators/tests.py	Sat Mar 28 12:05:48 2009 -0500
   128.2 +++ b/tests/regressiontests/decorators/tests.py	Wed Apr 01 13:05:19 2009 -0500
   128.3 @@ -29,6 +29,7 @@
   128.4  fully_decorated = never_cache(fully_decorated)
   128.5  
   128.6  # django.contrib.auth.decorators
   128.7 +# Apply user_passes_test twice to check #9474
   128.8  fully_decorated = user_passes_test(lambda u:True)(fully_decorated)
   128.9  fully_decorated = login_required(fully_decorated)
  128.10  fully_decorated = permission_required('change_world')(fully_decorated)
  128.11 @@ -54,3 +55,33 @@
  128.12              self.assertEquals(fully_decorated.__name__, 'fully_decorated')
  128.13          self.assertEquals(fully_decorated.__doc__, 'Expected __doc__')
  128.14          self.assertEquals(fully_decorated.__dict__['anything'], 'Expected __dict__')
  128.15 +
  128.16 +    def test_user_passes_test_composition(self):
  128.17 +        """
  128.18 +        Test that the user_passes_test decorator can be applied multiple times
  128.19 +        (#9474).
  128.20 +        """
  128.21 +        def test1(user):
  128.22 +            user.decorators_applied.append('test1')
  128.23 +            return True
  128.24 +            
  128.25 +        def test2(user):
  128.26 +            user.decorators_applied.append('test2')
  128.27 +            return True
  128.28 +            
  128.29 +        def callback(request):
  128.30 +            return request.user.decorators_applied
  128.31 +
  128.32 +        callback = user_passes_test(test1)(callback)
  128.33 +        callback = user_passes_test(test2)(callback)
  128.34 +        
  128.35 +        class DummyUser(object): pass
  128.36 +        class DummyRequest(object): pass
  128.37 +        
  128.38 +        request = DummyRequest()
  128.39 +        request.user = DummyUser()
  128.40 +        request.user.decorators_applied = []
  128.41 +        response = callback(request)
  128.42 +        
  128.43 +        self.assertEqual(response, ['test2', 'test1'])
  128.44 +        
   129.1 --- a/tests/regressiontests/defaultfilters/tests.py	Sat Mar 28 12:05:48 2009 -0500
   129.2 +++ b/tests/regressiontests/defaultfilters/tests.py	Wed Apr 01 13:05:19 2009 -0500
   129.3 @@ -35,8 +35,8 @@
   129.4  u''
   129.5  >>> floatformat(13.1031, u'bar')
   129.6  u'13.1031'
   129.7 ->>> floatformat(18.125, 2) 
   129.8 -u'18.13' 
   129.9 +>>> floatformat(18.125, 2)
  129.10 +u'18.13'
  129.11  >>> floatformat(u'foo', u'bar')
  129.12  u''
  129.13  >>> floatformat(u'¿Cómo esta usted?')
  129.14 @@ -53,6 +53,15 @@
  129.15  >>> floatformat(nan) == unicode(nan)
  129.16  True
  129.17  
  129.18 +>>> class FloatWrapper(object):
  129.19 +...     def __init__(self, value):
  129.20 +...         self.value = value
  129.21 +...     def __float__(self):
  129.22 +...         return self.value
  129.23 +
  129.24 +>>> floatformat(FloatWrapper(11.000001), -2)
  129.25 +u'11.00'
  129.26 +
  129.27  >>> addslashes(u'"double quotes" and \'single quotes\'')
  129.28  u'\\"double quotes\\" and \\\'single quotes\\\''
  129.29  
  129.30 @@ -180,23 +189,23 @@
  129.31  u'<a href="http://31characteruri.com/test/" rel="nofollow">...</a>'
  129.32  
  129.33  # Check normal urlize
  129.34 ->>> urlize('http://google.com') 
  129.35 +>>> urlize('http://google.com')
  129.36  u'<a href="http://google.com" rel="nofollow">http://google.com</a>'
  129.37  
  129.38 ->>> urlize('http://google.com/') 
  129.39 +>>> urlize('http://google.com/')
  129.40  u'<a href="http://google.com/" rel="nofollow">http://google.com/</a>'
  129.41  
  129.42 ->>> urlize('www.google.com') 
  129.43 +>>> urlize('www.google.com')
  129.44  u'<a href="http://www.google.com" rel="nofollow">www.google.com</a>'
  129.45  
  129.46 ->>> urlize('djangoproject.org') 
  129.47 +>>> urlize('djangoproject.org')
  129.48  u'<a href="http://djangoproject.org" rel="nofollow">djangoproject.org</a>'
  129.49  
  129.50 ->>> urlize('info@djangoproject.org') 
  129.51 +>>> urlize('info@djangoproject.org')
  129.52  u'<a href="mailto:info@djangoproject.org">info@djangoproject.org</a>'
  129.53  
  129.54  # Check urlize with https addresses
  129.55 ->>> urlize('https://google.com') 
  129.56 +>>> urlize('https://google.com')
  129.57  u'<a href="https://google.com" rel="nofollow">https://google.com</a>'
  129.58  
  129.59  
   130.1 --- a/tests/regressiontests/forms/fields.py	Sat Mar 28 12:05:48 2009 -0500
   130.2 +++ b/tests/regressiontests/forms/fields.py	Wed Apr 01 13:05:19 2009 -0500
   130.3 @@ -845,6 +845,21 @@
   130.4  >>> type(f.clean(SimpleUploadedFile('name', 'Some File Content'), 'files/test4.pdf'))
   130.5  <class 'django.core.files.uploadedfile.SimpleUploadedFile'>
   130.6  
   130.7 +>>> f = FileField(max_length = 5)
   130.8 +>>> f.clean(SimpleUploadedFile('test_maxlength.txt', 'hello world'))
   130.9 +Traceback (most recent call last):
  130.10 +...
  130.11 +ValidationError: [u'Ensure this filename has at most 5 characters (it has 18).']
  130.12 +
  130.13 +>>> f.clean('', 'files/test1.pdf')
  130.14 +'files/test1.pdf'
  130.15 +
  130.16 +>>> f.clean(None, 'files/test2.pdf')
  130.17 +'files/test2.pdf'
  130.18 +
  130.19 +>>> type(f.clean(SimpleUploadedFile('name', 'Some File Content')))
  130.20 +<class 'django.core.files.uploadedfile.SimpleUploadedFile'>
  130.21 +
  130.22  # URLField ##################################################################
  130.23  
  130.24  >>> f = URLField()
   131.1 --- a/tests/regressiontests/forms/formsets.py	Sat Mar 28 12:05:48 2009 -0500
   131.2 +++ b/tests/regressiontests/forms/formsets.py	Wed Apr 01 13:05:19 2009 -0500
   131.3 @@ -241,7 +241,7 @@
   131.4  
   131.5  # FormSets with deletion ######################################################
   131.6  
   131.7 -We can easily add deletion ability to a FormSet with an agrument to
   131.8 +We can easily add deletion ability to a FormSet with an argument to
   131.9  formset_factory. This will add a boolean field to each form instance. When
  131.10  that boolean field is True, the form will be in formset.deleted_forms
  131.11  
  131.12 @@ -286,6 +286,34 @@
  131.13  >>> [form.cleaned_data for form in formset.deleted_forms]
  131.14  [{'votes': 900, 'DELETE': True, 'choice': u'Fergie'}]
  131.15  
  131.16 +If we fill a form with something and then we check the can_delete checkbox for
  131.17 +that form, that form's errors should not make the entire formset invalid since
  131.18 +it's going to be deleted.
  131.19 +
  131.20 +>>> class CheckForm(Form):
  131.21 +...    field = IntegerField(min_value=100)
  131.22 +
  131.23 +>>> data = {
  131.24 +...     'check-TOTAL_FORMS': '3', # the number of forms rendered
  131.25 +...     'check-INITIAL_FORMS': '2', # the number of forms with initial data
  131.26 +...     'check-0-field': '200',
  131.27 +...     'check-0-DELETE': '',
  131.28 +...     'check-1-field': '50',
  131.29 +...     'check-1-DELETE': 'on',
  131.30 +...     'check-2-field': '',
  131.31 +...     'check-2-DELETE': '',
  131.32 +... }
  131.33 +>>> CheckFormSet = formset_factory(CheckForm, can_delete=True)
  131.34 +>>> formset = CheckFormSet(data, prefix='check')
  131.35 +>>> formset.is_valid()
  131.36 +True
  131.37 +
  131.38 +If we remove the deletion flag now we will have our validation back.
  131.39 +
  131.40 +>>> data['check-1-DELETE'] = ''
  131.41 +>>> formset = CheckFormSet(data, prefix='check')
  131.42 +>>> formset.is_valid()
  131.43 +False
  131.44  
  131.45  # FormSets with ordering ######################################################
  131.46  
   132.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   132.2 +++ b/tests/regressiontests/formwizard/forms.py	Wed Apr 01 13:05:19 2009 -0500
   132.3 @@ -0,0 +1,18 @@
   132.4 +from django import forms
   132.5 +from django.contrib.formtools.wizard import FormWizard
   132.6 +from django.http import HttpResponse
   132.7 +
   132.8 +class Page1(forms.Form):
   132.9 +    name = forms.CharField(max_length=100)
  132.10 +    thirsty = forms.NullBooleanField()
  132.11 +
  132.12 +class Page2(forms.Form):
  132.13 +    address1 = forms.CharField(max_length=100)
  132.14 +    address2 = forms.CharField(max_length=100)
  132.15 +    
  132.16 +class Page3(forms.Form):
  132.17 +    random_crap = forms.CharField(max_length=100)
  132.18 +    
  132.19 +class ContactWizard(FormWizard):
  132.20 +    def done(self, request, form_list):
  132.21 +        return HttpResponse("")
   133.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   133.2 +++ b/tests/regressiontests/formwizard/templates/forms/wizard.html	Wed Apr 01 13:05:19 2009 -0500
   133.3 @@ -0,0 +1,13 @@
   133.4 +<html>
   133.5 +  <body>
   133.6 +    <p>Step {{ step }} of {{ step_count }}</p>
   133.7 +    <form action="." method="post">
   133.8 +    <table>
   133.9 +    {{ form }}
  133.10 +    </table>
  133.11 +    <input type="hidden" name="{{ step_field }}" value="{{ step0 }}" />
  133.12 +    {{ previous_fields|safe }}
  133.13 +    <input type="submit">
  133.14 +    </form>
  133.15 +  </body>
  133.16 +</html>
  133.17 \ No newline at end of file
   134.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   134.2 +++ b/tests/regressiontests/formwizard/tests.py	Wed Apr 01 13:05:19 2009 -0500
   134.3 @@ -0,0 +1,59 @@
   134.4 +import re
   134.5 +from django import forms
   134.6 +from django.test import TestCase
   134.7 +
   134.8 +class FormWizardWithNullBooleanField(TestCase):
   134.9 +    urls = 'regressiontests.formwizard.urls'
  134.10 +
  134.11 +    input_re = re.compile('name="([^"]+)" value="([^"]+)"')
  134.12 +
  134.13 +    wizard_url = '/wiz/'
  134.14 +    wizard_step_data = (
  134.15 +        {
  134.16 +            '0-name': 'Pony',
  134.17 +            '0-thirsty': '2',
  134.18 +        },
  134.19 +        {
  134.20 +            '1-address1': '123 Main St',
  134.21 +            '1-address2': 'Djangoland',
  134.22 +        },
  134.23 +        {
  134.24 +            '2-random_crap': 'blah blah',
  134.25 +        }
  134.26 +    )
  134.27 +
  134.28 +    def grabFieldData(self, response):
  134.29 +        """
  134.30 +        Pull the appropriate field data from the context to pass to the next wizard step
  134.31 +        """
  134.32 +        previous_fields = response.context['previous_fields']
  134.33 +        fields = {'wizard_step': response.context['step0']}
  134.34 +        
  134.35 +        def grab(m):
  134.36 +            fields[m.group(1)] = m.group(2)
  134.37 +            return ''
  134.38 +        
  134.39 +        self.input_re.sub(grab, previous_fields)
  134.40 +        return fields
  134.41 +
  134.42 +    def checkWizardStep(self, response, step_no):
  134.43 +        """
  134.44 +        Helper function to test each step of the wizard
  134.45 +        - Make sure the call succeeded
  134.46 +        - Make sure response is the proper step number
  134.47 +        - return the result from the post for the next step
  134.48 +        """
  134.49 +        step_count = len(self.wizard_step_data)
  134.50 +
  134.51 +        self.assertEqual(response.status_code, 200)
  134.52 +        self.assertContains(response, 'Step %d of %d' % (step_no, step_count))
  134.53 +
  134.54 +        data = self.grabFieldData(response)
  134.55 +        data.update(self.wizard_step_data[step_no - 1])
  134.56 +
  134.57 +        return self.client.post(self.wizard_url, data)
  134.58 +        
  134.59 +    def testWizard(self):
  134.60 +        response = self.client.get(self.wizard_url)
  134.61 +        for step_no in range(1, len(self.wizard_step_data) + 1):
  134.62 +            response = self.checkWizardStep(response, step_no)
   135.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   135.2 +++ b/tests/regressiontests/formwizard/urls.py	Wed Apr 01 13:05:19 2009 -0500
   135.3 @@ -0,0 +1,6 @@
   135.4 +from django.conf.urls.defaults import *
   135.5 +from forms import ContactWizard, Page1, Page2, Page3
   135.6 +
   135.7 +urlpatterns = patterns('',
   135.8 +    url(r'^wiz/$', ContactWizard([Page1, Page2, Page3])),
   135.9 +    )
   136.1 --- a/tests/regressiontests/httpwrappers/tests.py	Sat Mar 28 12:05:48 2009 -0500
   136.2 +++ b/tests/regressiontests/httpwrappers/tests.py	Wed Apr 01 13:05:19 2009 -0500
   136.3 @@ -396,10 +396,18 @@
   136.4  # Pickling a QueryDict #
   136.5  ########################
   136.6  >>> import pickle
   136.7 +>>> q = QueryDict('')
   136.8 +>>> q1 = pickle.loads(pickle.dumps(q, 2))
   136.9 +>>> q == q1
  136.10 +True
  136.11  >>> q = QueryDict('a=b&c=d')
  136.12  >>> q1 = pickle.loads(pickle.dumps(q, 2))
  136.13  >>> q == q1
  136.14  True
  136.15 +>>> q = QueryDict('a=b&c=d&a=1') 
  136.16 +>>> q1 = pickle.loads(pickle.dumps(q, 2))
  136.17 +>>> q == q1 
  136.18 +True
  136.19  
  136.20  ######################################
  136.21  # HttpResponse with Unicode headers  #
   137.1 --- a/tests/regressiontests/inline_formsets/models.py	Sat Mar 28 12:05:48 2009 -0500
   137.2 +++ b/tests/regressiontests/inline_formsets/models.py	Wed Apr 01 13:05:19 2009 -0500
   137.3 @@ -13,6 +13,19 @@
   137.4      school = models.ForeignKey(School)
   137.5      name = models.CharField(max_length=100)
   137.6  
   137.7 +class Poet(models.Model):
   137.8 +    name = models.CharField(max_length=100)
   137.9 +
  137.10 +    def __unicode__(self):
  137.11 +        return self.name
  137.12 +
  137.13 +class Poem(models.Model):
  137.14 +    poet = models.ForeignKey(Poet)
  137.15 +    name = models.CharField(max_length=100)
  137.16 +
  137.17 +    def __unicode__(self):
  137.18 +        return self.name
  137.19 +
  137.20  __test__ = {'API_TESTS': """
  137.21  
  137.22  >>> from django.forms.models import inlineformset_factory
   138.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   138.2 +++ b/tests/regressiontests/inline_formsets/tests.py	Wed Apr 01 13:05:19 2009 -0500
   138.3 @@ -0,0 +1,76 @@
   138.4 +from django.test import TestCase
   138.5 +from django.forms.models import inlineformset_factory
   138.6 +from regressiontests.inline_formsets.models import Poet, Poem
   138.7 +
   138.8 +class DeletionTests(TestCase):
   138.9 +    def test_deletion(self):
  138.10 +        PoemFormSet = inlineformset_factory(Poet, Poem, can_delete=True)
  138.11 +        poet = Poet.objects.create(name='test')
  138.12 +        poet.poem_set.create(name='test poem')
  138.13 +        data = {
  138.14 +            'poem_set-TOTAL_FORMS': u'1',
  138.15 +            'poem_set-INITIAL_FORMS': u'1',
  138.16 +            'poem_set-0-id': u'1',
  138.17 +            'poem_set-0-poem': u'1',
  138.18 +            'poem_set-0-name': u'test',
  138.19 +            'poem_set-0-DELETE': u'on',
  138.20 +        }
  138.21 +        formset = PoemFormSet(data, instance=poet)
  138.22 +        formset.save()
  138.23 +        self.assertTrue(formset.is_valid())
  138.24 +        self.assertEqual(Poem.objects.count(), 0)
  138.25 +
  138.26 +    def test_add_form_deletion_when_invalid(self):
  138.27 +        """
  138.28 +        Make sure that an add form that is filled out, but marked for deletion
  138.29 +        doesn't cause validation errors.
  138.30 +        """
  138.31 +        PoemFormSet = inlineformset_factory(Poet, Poem, can_delete=True)
  138.32 +        poet = Poet.objects.create(name='test')
  138.33 +        data = {
  138.34 +            'poem_set-TOTAL_FORMS': u'1',
  138.35 +            'poem_set-INITIAL_FORMS': u'0',
  138.36 +            'poem_set-0-id': u'',
  138.37 +            'poem_set-0-poem': u'1',
  138.38 +            'poem_set-0-name': u'x' * 1000,
  138.39 +        }
  138.40 +        formset = PoemFormSet(data, instance=poet)
  138.41 +        # Make sure this form doesn't pass validation.
  138.42 +        self.assertEqual(formset.is_valid(), False)
  138.43 +        self.assertEqual(Poem.objects.count(), 0)
  138.44 +
  138.45 +        # Then make sure that it *does* pass validation and delete the object,
  138.46 +        # even though the data isn't actually valid.
  138.47 +        data['poem_set-0-DELETE'] = 'on'
  138.48 +        formset = PoemFormSet(data, instance=poet)
  138.49 +        self.assertEqual(formset.is_valid(), True)
  138.50 +        formset.save()
  138.51 +        self.assertEqual(Poem.objects.count(), 0)
  138.52 +
  138.53 +    def test_change_form_deletion_when_invalid(self):
  138.54 +        """
  138.55 +        Make sure that a change form that is filled out, but marked for deletion
  138.56 +        doesn't cause validation errors.
  138.57 +        """
  138.58 +        PoemFormSet = inlineformset_factory(Poet, Poem, can_delete=True)
  138.59 +        poet = Poet.objects.create(name='test')
  138.60 +        poet.poem_set.create(name='test poem')
  138.61 +        data = {
  138.62 +            'poem_set-TOTAL_FORMS': u'1',
  138.63 +            'poem_set-INITIAL_FORMS': u'1',
  138.64 +            'poem_set-0-id': u'1',
  138.65 +            'poem_set-0-poem': u'1',
  138.66 +            'poem_set-0-name': u'x' * 1000,
  138.67 +        }
  138.68 +        formset = PoemFormSet(data, instance=poet)
  138.69 +        # Make sure this form doesn't pass validation.
  138.70 +        self.assertEqual(formset.is_valid(), False)
  138.71 +        self.assertEqual(Poem.objects.count(), 1)
  138.72 +
  138.73 +        # Then make sure that it *does* pass validation and delete the object,
  138.74 +        # even though the data isn't actually valid.
  138.75 +        data['poem_set-0-DELETE'] = 'on'
  138.76 +        formset = PoemFormSet(data, instance=poet)
  138.77 +        self.assertEqual(formset.is_valid(), True)
  138.78 +        formset.save()
  138.79 +        self.assertEqual(Poem.objects.count(), 0)
   139.1 --- a/tests/regressiontests/templates/filters.py	Sat Mar 28 12:05:48 2009 -0500
   139.2 +++ b/tests/regressiontests/templates/filters.py	Wed Apr 01 13:05:19 2009 -0500
   139.3 @@ -7,7 +7,7 @@
   139.4  consistent.
   139.5  """
   139.6  
   139.7 -from datetime import datetime, timedelta
   139.8 +from datetime import date, datetime, timedelta
   139.9  
  139.10  from django.utils.tzinfo import LocalTimezone, FixedOffset
  139.11  from django.utils.safestring import mark_safe
  139.12 @@ -28,6 +28,8 @@
  139.13      now = datetime.now()
  139.14      now_tz = datetime.now(LocalTimezone(now))
  139.15      now_tz_i = datetime.now(FixedOffset((3 * 60) + 15)) # imaginary time zone
  139.16 +    today = date.today()
  139.17 +
  139.18      return {
  139.19          # Default compare with datetime.now()
  139.20          'filter-timesince01' : ('{{ a|timesince }}', {'a': datetime.now() + timedelta(minutes=-1, seconds = -10)}, '1 minute'),
  139.21 @@ -55,6 +57,10 @@
  139.22          'filter-timesince15' : ('{{ a|timesince:b }}', {'a': now, 'b': now_tz_i}, ''),
  139.23          'filter-timesince16' : ('{{ a|timesince:b }}', {'a': now_tz_i, 'b': now}, ''),
  139.24  
  139.25 +        # Regression for #9065 (two date objects).
  139.26 +        'filter-timesince17' : ('{{ a|timesince:b }}', {'a': today, 'b': today}, '0 minutes'),
  139.27 +        'filter-timesince18' : ('{{ a|timesince:b }}', {'a': today, 'b': today + timedelta(hours=24)}, '1 day'),
  139.28 +
  139.29          # Default compare with datetime.now()
  139.30          'filter-timeuntil01' : ('{{ a|timeuntil }}', {'a':datetime.now() + timedelta(minutes=2, seconds = 10)}, '2 minutes'),
  139.31          'filter-timeuntil02' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(days=1, seconds = 10))}, '1 day'),
  139.32 @@ -74,6 +80,10 @@
  139.33          'filter-timeuntil10' : ('{{ a|timeuntil }}', {'a': now_tz_i}, '0 minutes'),
  139.34          'filter-timeuntil11' : ('{{ a|timeuntil:b }}', {'a': now_tz_i, 'b': now_tz}, '0 minutes'),
  139.35  
  139.36 +        # Regression for #9065 (two date objects).
  139.37 +        'filter-timeuntil12' : ('{{ a|timeuntil:b }}', {'a': today, 'b': today}, '0 minutes'),
  139.38 +        'filter-timeuntil13' : ('{{ a|timeuntil:b }}', {'a': today, 'b': today - timedelta(hours=24)}, '1 day'),
  139.39 +
  139.40          'filter-addslash01': ("{% autoescape off %}{{ a|addslashes }} {{ b|addslashes }}{% endautoescape %}", {"a": "<a>'", "b": mark_safe("<a>'")}, ur"<a>\' <a>\'"),
  139.41          'filter-addslash02': ("{{ a|addslashes }} {{ b|addslashes }}", {"a": "<a>'", "b": mark_safe("<a>'")}, ur"&lt;a&gt;\&#39; <a>\'"),
  139.42  
  139.43 @@ -281,13 +291,33 @@
  139.44          'escapejs01': (r'{{ a|escapejs }}', {'a': 'testing\r\njavascript \'string" <b>escaping</b>'}, 'testing\\x0D\\x0Ajavascript \\x27string\\x22 \\x3Cb\\x3Eescaping\\x3C/b\\x3E'),
  139.45          'escapejs02': (r'{% autoescape off %}{{ a|escapejs }}{% endautoescape %}', {'a': 'testing\r\njavascript \'string" <b>escaping</b>'}, 'testing\\x0D\\x0Ajavascript \\x27string\\x22 \\x3Cb\\x3Eescaping\\x3C/b\\x3E'),
  139.46  
  139.47 +
  139.48 +        # length filter.
  139.49 +        'length01': ('{{ list|length }}', {'list': ['4', None, True, {}]}, '4'),
  139.50 +        'length02': ('{{ list|length }}', {'list': []}, '0'),
  139.51 +        'length03': ('{{ string|length }}', {'string': ''}, '0'),
  139.52 +        'length04': ('{{ string|length }}', {'string': 'django'}, '6'),
  139.53 +        # Invalid uses that should fail silently.
  139.54 +        'length05': ('{{ int|length }}', {'int': 7}, ''),
  139.55 +        'length06': ('{{ None|length }}', {'None': None}, ''),
  139.56 +
  139.57 +        # length_is filter.
  139.58 +        'length_is01': ('{% if some_list|length_is:"4" %}Four{% endif %}', {'some_list': ['4', None, True, {}]}, 'Four'),
  139.59 +        'length_is02': ('{% if some_list|length_is:"4" %}Four{% else %}Not Four{% endif %}', {'some_list': ['4', None, True, {}, 17]}, 'Not Four'),
  139.60 +        'length_is03': ('{% if mystring|length_is:"4" %}Four{% endif %}', {'mystring': 'word'}, 'Four'),
  139.61 +        'length_is04': ('{% if mystring|length_is:"4" %}Four{% else %}Not Four{% endif %}', {'mystring': 'Python'}, 'Not Four'),
  139.62 +        'length_is05': ('{% if mystring|length_is:"4" %}Four{% else %}Not Four{% endif %}', {'mystring': ''}, 'Not Four'),
  139.63 +        'length_is06': ('{% with var|length as my_length %}{{ my_length }}{% endwith %}', {'var': 'django'}, '6'),
  139.64          # Boolean return value from length_is should not be coerced to a string
  139.65 -        'lengthis01': (r'{% if "X"|length_is:0 %}Length is 0{% else %}Length not 0{% endif %}', {}, 'Length not 0'),
  139.66 -        'lengthis02': (r'{% if "X"|length_is:1 %}Length is 1{% else %}Length not 1{% endif %}', {}, 'Length is 1'),
  139.67 +        'length_is07': (r'{% if "X"|length_is:0 %}Length is 0{% else %}Length not 0{% endif %}', {}, 'Length not 0'),
  139.68 +        'length_is08': (r'{% if "X"|length_is:1 %}Length is 1{% else %}Length not 1{% endif %}', {}, 'Length is 1'),
  139.69 +        # Invalid uses that should fail silently.
  139.70 +        'length_is09': ('{{ var|length_is:"fish" }}', {'var': 'django'}, ''),
  139.71 +        'length_is10': ('{{ int|length_is:"1" }}', {'int': 7}, ''),
  139.72 +        'length_is11': ('{{ none|length_is:"1" }}', {'none': None}, ''),
  139.73  
  139.74          'join01': (r'{{ a|join:", " }}', {'a': ['alpha', 'beta & me']}, 'alpha, beta &amp; me'),
  139.75          'join02': (r'{% autoescape off %}{{ a|join:", " }}{% endautoescape %}', {'a': ['alpha', 'beta & me']}, 'alpha, beta & me'),
  139.76          'join03': (r'{{ a|join:" &amp; " }}', {'a': ['alpha', 'beta & me']}, 'alpha &amp; beta &amp; me'),
  139.77          'join04': (r'{% autoescape off %}{{ a|join:" &amp; " }}{% endautoescape %}', {'a': ['alpha', 'beta & me']}, 'alpha &amp; beta & me'),
  139.78      }
  139.79 -
   140.1 --- a/tests/regressiontests/templates/tests.py	Sat Mar 28 12:05:48 2009 -0500
   140.2 +++ b/tests/regressiontests/templates/tests.py	Wed Apr 01 13:05:19 2009 -0500
   140.3 @@ -6,9 +6,11 @@
   140.4      # before importing 'template'.
   140.5      settings.configure()
   140.6  
   140.7 +from datetime import datetime, timedelta
   140.8  import os
   140.9 +import sys
  140.10 +import traceback
  140.11  import unittest
  140.12 -from datetime import datetime, timedelta
  140.13  
  140.14  from django import template
  140.15  from django.core import urlresolvers
  140.16 @@ -207,10 +209,11 @@
  140.17                  try:
  140.18                      test_template = loader.get_template(name)
  140.19                      output = self.render(test_template, vals)
  140.20 -                except Exception, e:
  140.21 -                    if e.__class__ != result:
  140.22 -                        raise
  140.23 -                        failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Got %s, exception: %s" % (invalid_str, name, e.__class__, e))
  140.24 +                except Exception:
  140.25 +                    exc_type, exc_value, exc_tb = sys.exc_info()
  140.26 +                    if exc_type != result:
  140.27 +                        tb = '\n'.join(traceback.format_exception(exc_type, exc_value, exc_tb))
  140.28 +                        failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Got %s, exception: %s\n%s" % (invalid_str, name, exc_type, exc_value, tb))
  140.29                      continue
  140.30                  if output != result:
  140.31                      failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Expected %r, got %r" % (invalid_str, name, result, output))
  140.32 @@ -227,7 +230,8 @@
  140.33          settings.TEMPLATE_DEBUG = old_td
  140.34          settings.TEMPLATE_STRING_IF_INVALID = old_invalid
  140.35  
  140.36 -        self.assertEqual(failures, [], '\n'.join(failures))
  140.37 +        self.assertEqual(failures, [], "Tests failed:\n%s\n%s" %
  140.38 +            ('-'*70, ("\n%s\n" % ('-'*70)).join(failures)))
  140.39  
  140.40      def render(self, test_template, vals):
  140.41          return test_template.render(template.Context(vals[1]))
  140.42 @@ -658,6 +662,8 @@
  140.43              'include02': ('{% include "basic-syntax02" %}', {'headline': 'Included'}, "Included"),
  140.44              'include03': ('{% include template_name %}', {'template_name': 'basic-syntax02', 'headline': 'Included'}, "Included"),
  140.45              'include04': ('a{% include "nonexistent" %}b', {}, "ab"),
  140.46 +            'include 05': ('template with a space', {}, 'template with a space'),
  140.47 +            'include06': ('{% include "include 05"%}', {}, 'template with a space'),
  140.48  
  140.49              ### NAMED ENDBLOCKS #######################################################
  140.50  
  140.51 @@ -757,6 +763,12 @@
  140.52              # Inheritance from a template that doesn't have any blocks
  140.53              'inheritance27': ("{% extends 'inheritance26' %}", {}, 'no tags'),
  140.54  
  140.55 +            # Set up a base template with a space in it.
  140.56 +            'inheritance 28': ("{% block first %}!{% endblock %}", {}, '!'),
  140.57 +
  140.58 +            # Inheritance from a template with a space in its name should work.
  140.59 +            'inheritance29': ("{% extends 'inheritance 28' %}", {}, '!'),
  140.60 +
  140.61              ### I18N ##################################################################
  140.62  
  140.63              # {% spaceless %} tag
   141.1 --- a/tests/regressiontests/test_client_regress/models.py	Sat Mar 28 12:05:48 2009 -0500
   141.2 +++ b/tests/regressiontests/test_client_regress/models.py	Wed Apr 01 13:05:19 2009 -0500
   141.3 @@ -444,7 +444,7 @@
   141.4      urls = 'regressiontests.test_client_regress.urls'
   141.5  
   141.6      def test_urlconf_was_changed(self):
   141.7 -        "TestCase can enforce a custom URLConf on a per-test basis"
   141.8 +        "TestCase can enforce a custom URLconf on a per-test basis"
   141.9          url = reverse('arg_view', args=['somename'])
  141.10          self.assertEquals(url, '/arg_view/somename/')
  141.11  
  141.12 @@ -505,6 +505,14 @@
  141.13          self.assertEqual(response.status_code, 200)
  141.14          self.assertEqual(response.content, 'YES')
  141.15  
  141.16 +    def test_logout(self):
  141.17 +        """Logout should work whether the user is logged in or not (#9978)."""
  141.18 +        self.client.logout()
  141.19 +        login = self.client.login(username='testclient',password='password')
  141.20 +        self.failUnless(login, 'Could not log in')
  141.21 +        self.client.logout()
  141.22 +        self.client.logout()
  141.23 +
  141.24  class RequestMethodTests(TestCase):
  141.25      def test_get(self):
  141.26          "Request a view via request method GET"
   142.1 --- a/tests/regressiontests/views/tests/__init__.py	Sat Mar 28 12:05:48 2009 -0500
   142.2 +++ b/tests/regressiontests/views/tests/__init__.py	Wed Apr 01 13:05:19 2009 -0500
   142.3 @@ -3,3 +3,4 @@
   142.4  from static import *
   142.5  from generic.date_based import *
   142.6  from generic.create_update import *
   142.7 +from debug import *
   143.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   143.2 +++ b/tests/regressiontests/views/tests/debug.py	Wed Apr 01 13:05:19 2009 -0500
   143.3 @@ -0,0 +1,21 @@
   143.4 +from django.conf import settings
   143.5 +from django.core.files.uploadedfile import SimpleUploadedFile
   143.6 +from django.test import TestCase
   143.7 +
   143.8 +class DebugViewTests(TestCase):
   143.9 +    def setUp(self):
  143.10 +        settings.DEBUG = True
  143.11 +
  143.12 +    def tearDown(self):
  143.13 +        settings.DEBUG = False
  143.14 +
  143.15 +    def test_files(self):
  143.16 +        response = self.client.get('/views/raises/')
  143.17 +        self.assertEquals(response.status_code, 500)
  143.18 +
  143.19 +        data = {
  143.20 +            'file_data.txt': SimpleUploadedFile('file_data.txt', 'haha'),
  143.21 +        }
  143.22 +        response = self.client.post('/views/raises/', data)
  143.23 +        self.failUnless('file_data.txt' in response.content)
  143.24 +        self.failIf('haha' in response.content)
   144.1 --- a/tests/regressiontests/views/urls.py	Sat Mar 28 12:05:48 2009 -0500
   144.2 +++ b/tests/regressiontests/views/urls.py	Wed Apr 01 13:05:19 2009 -0500
   144.3 @@ -82,3 +82,8 @@
   144.4      (r'^create_update/no_url/update/article/(?P<slug>[-\w]+)/$',
   144.5          'update_object', dict(slug_field='slug', model=UrlArticle)),
   144.6  )
   144.7 +
   144.8 +# a view that raises an exception for the debug view
   144.9 +urlpatterns += patterns('',
  144.10 +    (r'^raises/$', views.raises)
  144.11 +)
   145.1 --- a/tests/regressiontests/views/views.py	Sat Mar 28 12:05:48 2009 -0500
   145.2 +++ b/tests/regressiontests/views/views.py	Wed Apr 01 13:05:19 2009 -0500
   145.3 @@ -1,5 +1,8 @@
   145.4 +import sys
   145.5 +
   145.6  from django.http import HttpResponse
   145.7  from django import forms
   145.8 +from django.views.debug import technical_500_response
   145.9  from django.views.generic.create_update import create_object
  145.10  
  145.11  from models import Article
  145.12 @@ -27,3 +30,9 @@
  145.13      return create_object(request,
  145.14          post_save_redirect='/views/create_update/view/article/%(slug)s/',
  145.15          form_class=SlugChangingArticleForm)
  145.16 +
  145.17 +def raises(request):
  145.18 +    try:
  145.19 +        raise Exception
  145.20 +    except Exception:
  145.21 +        return technical_500_response(request, *sys.exc_info())