From a873df6f3765075b615e9e9c7f2b178ee90cdbcf Mon Sep 17 00:00:00 2001 From: Chris Cahoon Date: Fri, 17 Jul 2009 11:33:35 +0000 Subject: [PATCH] [soc2009/http-wsgi-improvements] Merged up to r12258 from trunk. git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/http-wsgi-improvements@11260 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- AUTHORS | 1 + django/conf/locale/ca/LC_MESSAGES/django.mo | Bin 64639 -> 67049 bytes django/conf/locale/ca/LC_MESSAGES/django.po | 549 ++++++++++------- django/conf/locale/es/LC_MESSAGES/django.mo | Bin 64913 -> 67328 bytes django/conf/locale/es/LC_MESSAGES/django.po | 556 ++++++++++-------- django/conf/urls/defaults.py | 16 +- django/contrib/admin/options.py | 24 +- django/contrib/admin/sites.py | 70 ++- .../contrib/admin/templates/admin/base.html | 25 +- django/contrib/admin/widgets.py | 15 +- .../admindocs/templates/admin_doc/index.html | 2 +- django/contrib/admindocs/views.py | 11 +- django/contrib/gis/db/models/manager.py | 3 + django/contrib/gis/db/models/query.py | 8 + django/contrib/gis/db/models/sql/query.py | 10 +- .../contrib/gis/gdal/prototypes/generation.py | 9 +- .../contrib/gis/geos/prototypes/topology.py | 2 + django/contrib/gis/tests/relatedapp/tests.py | 42 +- django/core/urlresolvers.py | 107 +++- django/db/backends/oracle/base.py | 13 +- django/db/backends/postgresql/operations.py | 17 +- django/template/context.py | 7 +- django/template/defaulttags.py | 6 +- docs/howto/custom-model-fields.txt | 2 +- docs/howto/deployment/modwsgi.txt | 187 +++--- docs/howto/error-reporting.txt | 10 +- docs/intro/tutorial03.txt | 2 +- .../contrib/admin/_images/article_actions.png | Bin 35643 -> 13367 bytes docs/ref/contrib/admin/index.txt | 110 ++-- docs/ref/contrib/contenttypes.txt | 4 +- docs/ref/forms/fields.txt | 41 +- docs/ref/models/querysets.txt | 2 +- docs/ref/templates/api.txt | 17 +- docs/ref/templates/builtins.txt | 10 + docs/topics/forms/formsets.txt | 49 +- docs/topics/http/urls.txt | 201 ++++++- docs/topics/i18n.txt | 8 +- docs/topics/testing.txt | 8 +- .../admin_views/customadmin.py | 8 +- tests/regressiontests/admin_views/tests.py | 79 +++ .../admin_widgets/widgetadmin.py | 2 +- .../fixtures/m2m_through.json | 34 ++ .../m2m_through_regress/models.py | 10 + .../included_namespace_urls.py | 13 + .../urlpatterns_reverse/namespace_urls.py | 38 ++ .../urlpatterns_reverse/tests.py | 82 ++- 46 files changed, 1665 insertions(+), 745 deletions(-) create mode 100644 tests/regressiontests/m2m_through_regress/fixtures/m2m_through.json create mode 100644 tests/regressiontests/urlpatterns_reverse/included_namespace_urls.py create mode 100644 tests/regressiontests/urlpatterns_reverse/namespace_urls.py diff --git a/AUTHORS b/AUTHORS index 5f36d83770..c965ddee4e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -131,6 +131,7 @@ answer newbie questions, and generally made Django that much better: Andrew Durdin dusk@woofle.net Andy Dustman + J. Clifford Dyer Clint Ecker Nick Efford eibaan@gmail.com diff --git a/django/conf/locale/ca/LC_MESSAGES/django.mo b/django/conf/locale/ca/LC_MESSAGES/django.mo index 38aecaae328e24ca907908ac5c018a8714ac246e..3039bd8fad17608ccf9430ce3013cbefa2f19766 100644 GIT binary patch delta 23221 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 delta 21118 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%0AL8Ozl{PJ`?h0{z zRdT&eN|`@5m7}avF7kWGry^yg<51j$*HXIhF+%-q8>}m3k>tzKM%NO@|NVK5x&Zpl zu=*{g{_2`U-P{1?PaxBog6gD;-x!j zgnr7ur(IggFJK?y+Bl2&q#AQQ(Eh)ounir~q28HBxY7p7m(q-Ha2!Ti1GV95K)WvF zo08g*zlMR-e{KCf#|gCSO{zlu65@fhsY7Z+eh6i{iu(xek*PpMJ^T~4hXsA)na>UQhjX(ooU@>JCzVnpBN^E5^|EmH7^3vDEb-1(RwLuO$6Tn@p&yo%7Z6 z&uZ)Ob)OMlwhILqLaZigo<3E;H)e+LaHik9zo>O0#@iLL#pl+#+-Tjq;%zvCl zRcxSEGy8FG~3dlCDkG zez^<14=mn6eK*o6%A+v5K7VQvoU;aM{{{nJr}EV`in=bgYL(?BKg24V;s0p6kg^fv zGvHga53=^vFp;<-ZN9THI}tA zOUb`Y{c^l)W7MQwJ?eDjw=(6wqRn7ZXVU*juP&d@8uzr4BXmkfnm~Cf%92RAN$ZF| z{?C9vGf24g&1vO-*%;Yuf@tc0qHG&!2l+PEelzh0q*27aCUnk0u#!}a^cV3#(r7Ak zGSD*2iz_J0ME$F42bm6(eM8+q+GHiK>o9R645jQ0`TC?Y#6?xf<+FD6u(ke0AT60c zX;h8$>N-p&nE`Z_r#zhWA??NzHz5@!E=imPyOO@7tUF291L8MH^QqVMndATdT*SC% zi6&7W_Ue1JB^_##Zd#{zX!Hw>YLI@T{FId!3i5|E+YpfSOY;s%Lt3o!S8tgo(7(NP zVz9qz`-Y)OQ@e*GxxqRfSu`H$lQlV%PX6;d&}Pygu3 z{=7ry2PQrA6-v7Ao8q55{9u5;->4fQ{`M0V1^F{g`6=C&d1(TYBIl3rubjU$RZ{aM zgOVOBDU_6B>1X~;OFs_^FI&7!x#-emtCT8Lv{Y$-`<1~#EGZ&s&FcC|Rn}}xs@k%c zzrxz|fk`XY4+-ex&%Yri*x!1~n`!*dcJ0sP|K{ZF;H2-)R`lmQcQr66^Z7ZcSQKm8 zbpCo^($XLI`TJk266k++rAMg0`^`r|S-bV>*(thNVt+3#p;NCu{d;ukP1Myt^7q7W uf7oA90ZHYajrJdT);(lqm4NZH(*^`Y&5j5N$T7QgK)}}Iy8!|J2K_&4h4g*^ diff --git a/django/conf/locale/ca/LC_MESSAGES/django.po b/django/conf/locale/ca/LC_MESSAGES/django.po index 9cfafe3e2a..57f8764938 100644 --- a/django/conf/locale/ca/LC_MESSAGES/django.po +++ b/django/conf/locale/ca/LC_MESSAGES/django.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: Django\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-03-24 13:00+0100\n" +"POT-Creation-Date: 2009-07-07 15:04+0200\n" "PO-Revision-Date: 2009-03-24 13:28+0100\n" "Last-Translator: Django Catalan Group \n" "Language-Team: Catalan \n" @@ -218,6 +218,20 @@ msgstr "xinès simplificat" msgid "Traditional Chinese" msgstr "xinès tradicional" +#: contrib/admin/actions.py:60 +#, python-format +msgid "Successfully deleted %(count)d %(items)s." +msgstr "Eliminat/s %(count)d %(items)s satisfactòriament." + +#: contrib/admin/actions.py:67 contrib/admin/options.py:1025 +msgid "Are you sure?" +msgstr "Esteu segurs?" + +#: contrib/admin/actions.py:85 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "Eliminar els %(verbose_name_plural)s seleccionats" + #: contrib/admin/filterspecs.py:44 #, python-format msgid "" @@ -252,15 +266,15 @@ msgstr "Aquest mes" msgid "This year" msgstr "Aquest any" -#: contrib/admin/filterspecs.py:147 forms/widgets.py:413 +#: contrib/admin/filterspecs.py:147 forms/widgets.py:434 msgid "Yes" msgstr "Si" -#: contrib/admin/filterspecs.py:147 forms/widgets.py:413 +#: contrib/admin/filterspecs.py:147 forms/widgets.py:434 msgid "No" msgstr "No" -#: contrib/admin/filterspecs.py:154 forms/widgets.py:413 +#: contrib/admin/filterspecs.py:154 forms/widgets.py:434 msgid "Unknown" msgstr "Desconegut" @@ -296,74 +310,61 @@ msgstr "entrada del registre" msgid "log entries" msgstr "entrades del registre" -#: contrib/admin/options.py:131 contrib/admin/options.py:145 +#: contrib/admin/options.py:133 contrib/admin/options.py:147 msgid "None" msgstr "cap" -#: contrib/admin/options.py:498 -#, python-format -msgid "Successfully deleted %(count)d %(items)s." -msgstr "Eliminat/s %(count)d %(items)s satisfactòriament." - -#: contrib/admin/options.py:505 contrib/admin/options.py:1012 -msgid "Are you sure?" -msgstr "Esteu segurs?" - -#: contrib/admin/options.py:523 -#, python-format -msgid "Delete selected %(verbose_name_plural)s" -msgstr "Eliminar els %(verbose_name_plural)s seleccionats" - -#: contrib/admin/options.py:531 +#: contrib/admin/options.py:519 #, python-format msgid "Changed %s." msgstr "Modificat %s." -#: contrib/admin/options.py:531 contrib/admin/options.py:541 -#: contrib/comments/templates/comments/preview.html:15 forms/models.py:296 +#: contrib/admin/options.py:519 contrib/admin/options.py:529 +#: contrib/comments/templates/comments/preview.html:16 forms/models.py:388 +#: forms/models.py:600 msgid "and" msgstr "i" -#: contrib/admin/options.py:536 +#: contrib/admin/options.py:524 #, python-format msgid "Added %(name)s \"%(object)s\"." msgstr "Afegit %(name)s \"%(object)s\"" -#: contrib/admin/options.py:540 +#: contrib/admin/options.py:528 #, python-format msgid "Changed %(list)s for %(name)s \"%(object)s\"." msgstr "Modificat %(list)s per a %(name)s \"%(object)s\"." -#: contrib/admin/options.py:545 +#: contrib/admin/options.py:533 #, python-format msgid "Deleted %(name)s \"%(object)s\"." msgstr "Eliminat %(name)s \"%(object)s\"." -#: contrib/admin/options.py:549 +#: contrib/admin/options.py:537 msgid "No fields changed." msgstr "Cap camp canviat." -#: contrib/admin/options.py:610 contrib/auth/admin.py:67 +#: contrib/admin/options.py:598 contrib/auth/admin.py:67 #, python-format msgid "The %(name)s \"%(obj)s\" was added successfully." msgstr "El/la %(name)s \"%(obj)s\".ha estat afegit/da amb èxit." -#: contrib/admin/options.py:614 contrib/admin/options.py:647 +#: contrib/admin/options.py:602 contrib/admin/options.py:635 #: contrib/auth/admin.py:75 msgid "You may edit it again below." msgstr "Podeu editar-lo de nou a baix." -#: contrib/admin/options.py:624 contrib/admin/options.py:657 +#: contrib/admin/options.py:612 contrib/admin/options.py:645 #, python-format msgid "You may add another %s below." msgstr "Podeu afegir un altre %s a baix." -#: contrib/admin/options.py:645 +#: contrib/admin/options.py:633 #, python-format msgid "The %(name)s \"%(obj)s\" was changed successfully." msgstr "S'ha modificat amb èxit el/la %(name)s \"%(obj)s." -#: contrib/admin/options.py:653 +#: contrib/admin/options.py:641 #, python-format msgid "" "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." @@ -371,43 +372,43 @@ msgstr "" "S'ha afegit exitosament el/la %(name)s \"%(obj)s\". Pot editar-lo de nou " "abaix." -#: contrib/admin/options.py:774 +#: contrib/admin/options.py:772 #, python-format msgid "Add %s" msgstr "Afegir %s" -#: contrib/admin/options.py:805 contrib/admin/options.py:990 +#: contrib/admin/options.py:803 contrib/admin/options.py:1003 #, python-format msgid "%(name)s object with primary key %(key)r does not exist." msgstr "No existèix cap objecte %(name)s amb la clau primària %(key)r." -#: contrib/admin/options.py:862 +#: contrib/admin/options.py:860 #, python-format msgid "Change %s" msgstr "Modificar %s" -#: contrib/admin/options.py:894 +#: contrib/admin/options.py:904 msgid "Database error" msgstr "Error de base de dades" -#: contrib/admin/options.py:930 +#: contrib/admin/options.py:940 #, python-format msgid "%(count)s %(name)s was changed successfully." msgid_plural "%(count)s %(name)s were changed successfully." msgstr[0] "%(count)s %(name)s s'ha modificat amb èxit." msgstr[1] "%(count)s %(name)s s'han modificat amb èxit." -#: contrib/admin/options.py:1005 +#: contrib/admin/options.py:1018 #, python-format msgid "The %(name)s \"%(obj)s\" was deleted successfully." msgstr "El/la %(name)s \"%(obj)s\" ha estat eliminat amb èxit." -#: contrib/admin/options.py:1041 +#: contrib/admin/options.py:1054 #, python-format msgid "Change history: %s" msgstr "Modificar històric: %s" -#: contrib/admin/sites.py:15 contrib/admin/views/decorators.py:14 +#: contrib/admin/sites.py:20 contrib/admin/views/decorators.py:14 #: contrib/auth/forms.py:80 msgid "" "Please enter a correct username and password. Note that both fields are case-" @@ -416,11 +417,11 @@ msgstr "" "Si us plau, introduïu un nom d'usuari i contrasenya vàlids. Tingueu en " "compte que tots dos camps son sensibles a majúscules i minúscules." -#: contrib/admin/sites.py:250 contrib/admin/views/decorators.py:40 +#: contrib/admin/sites.py:278 contrib/admin/views/decorators.py:40 msgid "Please log in again, because your session has expired." msgstr "Si us plau, identifiqueu-vos de nou doncs la vostra sessió ha expirat." -#: contrib/admin/sites.py:257 contrib/admin/views/decorators.py:47 +#: contrib/admin/sites.py:285 contrib/admin/views/decorators.py:47 msgid "" "Looks like your browser isn't configured to accept cookies. Please enable " "cookies, reload this page, and try again." @@ -429,29 +430,29 @@ msgstr "" "'cookies' (galetes). Si us plau, habiliteu les 'cookies', recarregueu " "aquesta pàgina i proveu-ho de nou. " -#: contrib/admin/sites.py:273 contrib/admin/sites.py:279 +#: contrib/admin/sites.py:301 contrib/admin/sites.py:307 #: contrib/admin/views/decorators.py:66 msgid "Usernames cannot contain the '@' character." msgstr "Els noms d'usuari no poden contenir el caracter '@'." -#: contrib/admin/sites.py:276 contrib/admin/views/decorators.py:62 +#: contrib/admin/sites.py:304 contrib/admin/views/decorators.py:62 #, python-format msgid "Your e-mail address is not your username. Try '%s' instead." msgstr "" "La vostra adreça de correu no és el vostre nom d'usuari. Provi '%s' en tot " "cas." -#: contrib/admin/sites.py:336 +#: contrib/admin/sites.py:360 msgid "Site administration" msgstr "Lloc administratiu" -#: contrib/admin/sites.py:349 contrib/admin/templates/admin/login.html:26 +#: contrib/admin/sites.py:373 contrib/admin/templates/admin/login.html:26 #: contrib/admin/templates/registration/password_reset_complete.html:14 #: contrib/admin/views/decorators.py:20 msgid "Log in" msgstr "Iniciar sessió" -#: contrib/admin/sites.py:396 +#: contrib/admin/sites.py:417 #, python-format msgid "%s administration" msgstr "Administració de %s" @@ -466,34 +467,27 @@ msgstr "Un o més %(fieldname)s en %(name)s: %(obj)s" msgid "One or more %(fieldname)s in %(name)s:" msgstr "Un o més %(fieldname)s en %(name)s:" -#: contrib/admin/util.py:222 -#, fuzzy -msgid "verbose_name" -msgid_plural "verbose_name_plural" -msgstr[0] "verbose_name" -msgstr[1] "verbose_name_plural" - -#: contrib/admin/widgets.py:70 +#: contrib/admin/widgets.py:71 msgid "Date:" msgstr "Data:" -#: contrib/admin/widgets.py:70 +#: contrib/admin/widgets.py:71 msgid "Time:" msgstr "Hora:" -#: contrib/admin/widgets.py:94 +#: contrib/admin/widgets.py:95 msgid "Currently:" msgstr "Actualment:" -#: contrib/admin/widgets.py:94 +#: contrib/admin/widgets.py:95 msgid "Change:" msgstr "Modificar:" -#: contrib/admin/widgets.py:123 +#: contrib/admin/widgets.py:124 msgid "Lookup" msgstr "Cercar" -#: contrib/admin/widgets.py:230 +#: contrib/admin/widgets.py:236 msgid "Add Another" msgstr "Afegir un altre" @@ -508,9 +502,9 @@ msgstr "Ho sentim, però no s'ha pogut trobar la pàgina sol·licitada" #: contrib/admin/templates/admin/500.html:4 #: contrib/admin/templates/admin/app_index.html:8 -#: contrib/admin/templates/admin/base.html:33 +#: contrib/admin/templates/admin/base.html:31 #: contrib/admin/templates/admin/change_form.html:17 -#: contrib/admin/templates/admin/change_list.html:20 +#: contrib/admin/templates/admin/change_list.html:25 #: contrib/admin/templates/admin/delete_confirmation.html:6 #: contrib/admin/templates/admin/delete_selected_confirmation.html:6 #: contrib/admin/templates/admin/invalid_setup.html:4 @@ -552,7 +546,6 @@ msgid "Run the selected action" msgstr "Executar la acció seleccionada" #: contrib/admin/templates/admin/actions.html:4 -#: contrib/admin/templates/admin/search_form.html:8 msgid "Go" msgstr "Anar" @@ -562,26 +555,26 @@ msgstr "Anar" msgid "%(name)s" msgstr "%(name)s" -#: contrib/admin/templates/admin/base.html:28 +#: contrib/admin/templates/admin/base.html:26 msgid "Welcome," msgstr "Benvingut/da," -#: contrib/admin/templates/admin/base.html:28 +#: contrib/admin/templates/admin/base.html:26 #: contrib/admin/templates/registration/password_change_done.html:3 #: contrib/admin/templates/registration/password_change_form.html:3 #: contrib/admindocs/templates/admin_doc/bookmarklets.html:3 msgid "Documentation" msgstr "Documentació" -#: contrib/admin/templates/admin/base.html:28 -#: contrib/admin/templates/admin/auth/user/change_password.html:13 -#: contrib/admin/templates/admin/auth/user/change_password.html:46 +#: contrib/admin/templates/admin/base.html:26 +#: contrib/admin/templates/admin/auth/user/change_password.html:14 +#: contrib/admin/templates/admin/auth/user/change_password.html:47 #: contrib/admin/templates/registration/password_change_done.html:3 #: contrib/admin/templates/registration/password_change_form.html:3 msgid "Change password" msgstr "Canviar contrasenya" -#: contrib/admin/templates/admin/base.html:28 +#: contrib/admin/templates/admin/base.html:26 #: contrib/admin/templates/registration/password_change_done.html:3 #: contrib/admin/templates/registration/password_change_form.html:3 msgid "Log out" @@ -612,24 +605,24 @@ msgid "View on site" msgstr "Veure al lloc" #: contrib/admin/templates/admin/change_form.html:38 -#: contrib/admin/templates/admin/change_list.html:49 -#: contrib/admin/templates/admin/auth/user/change_password.html:22 +#: contrib/admin/templates/admin/change_list.html:54 +#: contrib/admin/templates/admin/auth/user/change_password.html:23 msgid "Please correct the error below." msgid_plural "Please correct the errors below." msgstr[0] "Si us plau, corregiu l'error mostrat a baix." msgstr[1] "Si us plau, corregiu els errors mostrats a baix." -#: contrib/admin/templates/admin/change_list.html:41 +#: contrib/admin/templates/admin/change_list.html:46 #, python-format msgid "Add %(name)s" msgstr "Afegir %(name)s" -#: contrib/admin/templates/admin/change_list.html:60 +#: contrib/admin/templates/admin/change_list.html:65 msgid "Filter" msgstr "Filtre" #: contrib/admin/templates/admin/delete_confirmation.html:10 -#: contrib/admin/templates/admin/submit_line.html:4 forms/formsets.py:251 +#: contrib/admin/templates/admin/submit_line.html:4 forms/formsets.py:275 msgid "Delete" msgstr "Eliminar" @@ -669,9 +662,9 @@ msgid "" "your account doesn't have permission to delete the following types of " "objects:" msgstr "" -"Eliminar el/la %(object_name)s provocaria l'eliminació " -"d'objectes relacionats, però el vostre compte no te permissos per a esborrar " -"els tipus d'objecte següents:" +"Eliminar el/la %(object_name)s provocaria l'eliminació d'objectes " +"relacionats, però el vostre compte no te permissos per a esborrar els tipus " +"d'objecte següents:" #: contrib/admin/templates/admin/delete_selected_confirmation.html:22 #, python-format @@ -679,8 +672,8 @@ msgid "" "Are you sure you want to delete the selected %(object_name)s objects? All of " "the following objects and it's related items will be deleted:" msgstr "" -"Esteu segurs de voler esborrar els/les %(object_name)s seleccionats?" -"Tots aquests objectes i els seus elements relacionats s'esborraran:" +"Esteu segurs de voler esborrar els/les %(object_name)s seleccionats?Tots " +"aquests objectes i els seus elements relacionats s'esborraran:" #: contrib/admin/templates/admin/filter.html:2 #, python-format @@ -712,6 +705,10 @@ msgstr "Les meves accions" msgid "None available" msgstr "Cap disponible" +#: contrib/admin/templates/admin/index.html:72 +msgid "Unknown content" +msgstr "Contingut desconegut" + #: contrib/admin/templates/admin/invalid_setup.html:7 msgid "" "Something's wrong with your database installation. Make sure the appropriate " @@ -760,6 +757,15 @@ msgstr "" msgid "Show all" msgstr "Mostrar tots" +#: contrib/admin/templates/admin/pagination.html:11 +#: contrib/admin/templates/admin/submit_line.html:3 +msgid "Save" +msgstr "Desar" + +#: contrib/admin/templates/admin/search_form.html:8 +msgid "Search" +msgstr "Cerca" + #: contrib/admin/templates/admin/search_form.html:10 #, python-format msgid "1 result" @@ -772,10 +778,6 @@ msgstr[1] "%(counter)s resultats" msgid "%(full_result_count)s total" msgstr "%(full_result_count)s en total" -#: contrib/admin/templates/admin/submit_line.html:3 -msgid "Save" -msgstr "Desar" - #: contrib/admin/templates/admin/submit_line.html:5 msgid "Save as new" msgstr "Desar com a nou" @@ -802,23 +804,23 @@ msgid "Username" msgstr "Usuari" #: contrib/admin/templates/admin/auth/user/add_form.html:20 -#: contrib/admin/templates/admin/auth/user/change_password.html:33 +#: contrib/admin/templates/admin/auth/user/change_password.html:34 #: contrib/auth/forms.py:17 contrib/auth/forms.py:60 contrib/auth/forms.py:185 msgid "Password" msgstr "Contrasenya" #: contrib/admin/templates/admin/auth/user/add_form.html:26 -#: contrib/admin/templates/admin/auth/user/change_password.html:39 +#: contrib/admin/templates/admin/auth/user/change_password.html:40 #: contrib/auth/forms.py:186 msgid "Password (again)" msgstr "Contrasenya (de nou)" #: contrib/admin/templates/admin/auth/user/add_form.html:27 -#: contrib/admin/templates/admin/auth/user/change_password.html:40 +#: contrib/admin/templates/admin/auth/user/change_password.html:41 msgid "Enter the same password as above, for verification." msgstr "Introduïu la mateixa contrasenya de dalt, per fer-ne la verificació." -#: contrib/admin/templates/admin/auth/user/change_password.html:26 +#: contrib/admin/templates/admin/auth/user/change_password.html:27 #, python-format msgid "Enter a new password for the user %(username)s." msgstr "Introduïu una contrasenya per l'usuari %(username)s" @@ -1035,114 +1037,115 @@ msgstr "El model %(model_name)r no s'ha trobat en l'aplicació %(app_label)r" msgid "the related `%(app_label)s.%(data_type)s` object" msgstr "l'objecte relacionat `%(app_label)s.%(data_type)s`" -#: contrib/admindocs/views.py:206 contrib/admindocs/views.py:228 -#: contrib/admindocs/views.py:242 contrib/admindocs/views.py:247 +#: contrib/admindocs/views.py:206 contrib/admindocs/views.py:225 +#: contrib/admindocs/views.py:230 contrib/admindocs/views.py:244 +#: contrib/admindocs/views.py:258 contrib/admindocs/views.py:263 msgid "model:" msgstr "model:" -#: contrib/admindocs/views.py:237 +#: contrib/admindocs/views.py:221 contrib/admindocs/views.py:253 #, python-format msgid "related `%(app_label)s.%(object_name)s` objects" msgstr "objectes relacionats `%(app_label)s.%(object_name)s`" -#: contrib/admindocs/views.py:242 +#: contrib/admindocs/views.py:225 contrib/admindocs/views.py:258 #, python-format msgid "all %s" msgstr "tots %s" -#: contrib/admindocs/views.py:247 +#: contrib/admindocs/views.py:230 contrib/admindocs/views.py:263 #, python-format msgid "number of %s" msgstr "nombre de %s" -#: contrib/admindocs/views.py:252 +#: contrib/admindocs/views.py:268 #, python-format msgid "Fields on %s objects" msgstr "Camps en objectes %s" -#: contrib/admindocs/views.py:315 contrib/admindocs/views.py:326 -#: contrib/admindocs/views.py:328 contrib/admindocs/views.py:334 -#: contrib/admindocs/views.py:335 contrib/admindocs/views.py:337 +#: contrib/admindocs/views.py:331 contrib/admindocs/views.py:342 +#: contrib/admindocs/views.py:344 contrib/admindocs/views.py:350 +#: contrib/admindocs/views.py:351 contrib/admindocs/views.py:353 msgid "Integer" msgstr "Enter" -#: contrib/admindocs/views.py:316 +#: contrib/admindocs/views.py:332 msgid "Boolean (Either True or False)" msgstr "Booleà (Verdader o Fals)" -#: contrib/admindocs/views.py:317 contrib/admindocs/views.py:336 +#: contrib/admindocs/views.py:333 contrib/admindocs/views.py:352 #, python-format msgid "String (up to %(max_length)s)" msgstr "Cadena (de fins a %(max_length)s)" -#: contrib/admindocs/views.py:318 +#: contrib/admindocs/views.py:334 msgid "Comma-separated integers" msgstr "Enters separats per comes" -#: contrib/admindocs/views.py:319 +#: contrib/admindocs/views.py:335 msgid "Date (without time)" msgstr "Data (sense hora)" -#: contrib/admindocs/views.py:320 +#: contrib/admindocs/views.py:336 msgid "Date (with time)" msgstr "Data (amb hora)" -#: contrib/admindocs/views.py:321 +#: contrib/admindocs/views.py:337 msgid "Decimal number" msgstr "Número decimal" -#: contrib/admindocs/views.py:322 +#: contrib/admindocs/views.py:338 msgid "E-mail address" msgstr "Adreça de correu electrònic" -#: contrib/admindocs/views.py:323 contrib/admindocs/views.py:324 -#: contrib/admindocs/views.py:327 +#: contrib/admindocs/views.py:339 contrib/admindocs/views.py:340 +#: contrib/admindocs/views.py:343 msgid "File path" msgstr "Ruta del fitxer" -#: contrib/admindocs/views.py:325 +#: contrib/admindocs/views.py:341 msgid "Floating point number" msgstr "Número amb punt de coma flotant" -#: contrib/admindocs/views.py:329 contrib/comments/models.py:58 +#: contrib/admindocs/views.py:345 contrib/comments/models.py:60 msgid "IP address" msgstr "Adreça IP" -#: contrib/admindocs/views.py:331 +#: contrib/admindocs/views.py:347 msgid "Boolean (Either True, False or None)" msgstr "Booleà (Verdader, Fals o 'None' (cap))" -#: contrib/admindocs/views.py:332 +#: contrib/admindocs/views.py:348 msgid "Relation to parent model" msgstr "Relació amb el model pare" -#: contrib/admindocs/views.py:333 +#: contrib/admindocs/views.py:349 msgid "Phone number" msgstr "Número de telèfon" -#: contrib/admindocs/views.py:338 +#: contrib/admindocs/views.py:354 msgid "Text" msgstr "Text" -#: contrib/admindocs/views.py:339 +#: contrib/admindocs/views.py:355 msgid "Time" msgstr "Hora" -#: contrib/admindocs/views.py:340 contrib/comments/forms.py:95 +#: contrib/admindocs/views.py:356 contrib/comments/forms.py:95 #: contrib/comments/templates/comments/moderation_queue.html:37 #: contrib/flatpages/admin.py:8 contrib/flatpages/models.py:7 msgid "URL" msgstr "URL" -#: contrib/admindocs/views.py:341 +#: contrib/admindocs/views.py:357 msgid "U.S. state (two uppercase letters)" msgstr "Estat dels E.U.A. (dues lletres majúscules)" -#: contrib/admindocs/views.py:342 +#: contrib/admindocs/views.py:358 msgid "XML text" msgstr "Text XML" -#: contrib/admindocs/views.py:368 +#: contrib/admindocs/views.py:384 #, python-format msgid "%s does not appear to be a urlpattern object" msgstr "%s no sembla ser un objecte 'urlpattern'" @@ -1247,7 +1250,7 @@ msgid "Change password: %s" msgstr "Canviar contrasenya: %s" #: contrib/auth/forms.py:15 contrib/auth/forms.py:48 -#: contrib/auth/models.py:127 +#: contrib/auth/models.py:128 msgid "" "Required. 30 characters or fewer. Alphanumeric characters only (letters, " "digits and underscores)." @@ -1338,31 +1341,31 @@ msgstr "permisos" msgid "group" msgstr "grup" -#: contrib/auth/models.py:91 contrib/auth/models.py:137 +#: contrib/auth/models.py:91 contrib/auth/models.py:138 msgid "groups" msgstr "grups" -#: contrib/auth/models.py:127 +#: contrib/auth/models.py:128 msgid "username" msgstr "nom d'usuari" -#: contrib/auth/models.py:128 +#: contrib/auth/models.py:129 msgid "first name" msgstr "nom propi" -#: contrib/auth/models.py:129 +#: contrib/auth/models.py:130 msgid "last name" msgstr "cognoms" -#: contrib/auth/models.py:130 +#: contrib/auth/models.py:131 msgid "e-mail address" msgstr "adreça de correu electrònic" -#: contrib/auth/models.py:131 +#: contrib/auth/models.py:132 msgid "password" msgstr "contrasenya" -#: contrib/auth/models.py:131 +#: contrib/auth/models.py:132 msgid "" "Use '[algo]$[salt]$[hexdigest]' or use the change " "password form." @@ -1370,19 +1373,19 @@ msgstr "" "Utilitzeu '[algo]$[salt]$[hexdigest]' o el formulari " "de canvi de contrasenya." -#: contrib/auth/models.py:132 +#: contrib/auth/models.py:133 msgid "staff status" msgstr "membre del personal" -#: contrib/auth/models.py:132 +#: contrib/auth/models.py:133 msgid "Designates whether the user can log into this admin site." msgstr "Indica si l'usuari pot entrar en el lloc administratiu." -#: contrib/auth/models.py:133 +#: contrib/auth/models.py:134 msgid "active" msgstr "actiu" -#: contrib/auth/models.py:133 +#: contrib/auth/models.py:134 msgid "" "Designates whether this user should be treated as active. Unselect this " "instead of deleting accounts." @@ -1390,11 +1393,11 @@ msgstr "" "Designa si aquest usuari ha de ser tractat com a actiu. Deseleccioneu-ho " "enlloc d'esborrar comptes d'usuari." -#: contrib/auth/models.py:134 +#: contrib/auth/models.py:135 msgid "superuser status" msgstr "estat de superusuari" -#: contrib/auth/models.py:134 +#: contrib/auth/models.py:135 msgid "" "Designates that this user has all permissions without explicitly assigning " "them." @@ -1402,15 +1405,15 @@ msgstr "" "Designa que aquest usuari té tots els permissos sense assignar-los " "explícitament." -#: contrib/auth/models.py:135 +#: contrib/auth/models.py:136 msgid "last login" msgstr "últim inici de sessió" -#: contrib/auth/models.py:136 +#: contrib/auth/models.py:137 msgid "date joined" msgstr "data de creació" -#: contrib/auth/models.py:138 +#: contrib/auth/models.py:139 msgid "" "In addition to the permissions manually assigned, this user will also get " "all permissions granted to each group he/she is in." @@ -1418,23 +1421,24 @@ msgstr "" "Junt amb els permissos asignats manualment, aquest usuari tindrà, també, els " "permissos dels grups dels que sigui membre." -#: contrib/auth/models.py:139 +#: contrib/auth/models.py:140 msgid "user permissions" msgstr "permissos de l'usuari" -#: contrib/auth/models.py:143 +#: contrib/auth/models.py:144 contrib/comments/models.py:50 +#: contrib/comments/models.py:168 msgid "user" msgstr "usuari" -#: contrib/auth/models.py:144 +#: contrib/auth/models.py:145 msgid "users" msgstr "usuaris" -#: contrib/auth/models.py:300 +#: contrib/auth/models.py:301 msgid "message" msgstr "missatge" -#: contrib/auth/views.py:50 +#: contrib/auth/views.py:56 msgid "Logged out" msgstr "Sessió finalitzada" @@ -1450,6 +1454,16 @@ msgstr "contingut" msgid "Metadata" msgstr "metadades" +#: contrib/comments/feeds.py:13 +#, python-format +msgid "%(site_name)s comments" +msgstr "comentaris de %(site_name)s" + +#: contrib/comments/feeds.py:23 +#, python-format +msgid "Latest comments on %(site_name)s" +msgstr "Últims comentaris a %(site_name)s." + #: contrib/comments/forms.py:93 #: contrib/comments/templates/comments/moderation_queue.html:34 msgid "Name" @@ -1479,46 +1493,51 @@ msgstr "" "Si entreu cualsevol cosa en aquest camp el vostre comentari es tractarà com " "a spam" -#: contrib/comments/models.py:23 +#: contrib/comments/models.py:22 contrib/contenttypes/models.py:74 +msgid "content type" +msgstr "tipus de contingut" + +#: contrib/comments/models.py:24 msgid "object ID" msgstr "ID de l'objecte" -#: contrib/comments/models.py:50 +#: contrib/comments/models.py:52 msgid "user's name" msgstr "nom d'usuari" -#: contrib/comments/models.py:51 +#: contrib/comments/models.py:53 msgid "user's email address" msgstr "adreça de correu electrònic del usuari" -#: contrib/comments/models.py:52 +#: contrib/comments/models.py:54 msgid "user's URL" msgstr "URL del usuari" -#: contrib/comments/models.py:54 +#: contrib/comments/models.py:56 contrib/comments/models.py:76 +#: contrib/comments/models.py:169 msgid "comment" msgstr "comentari" -#: contrib/comments/models.py:57 +#: contrib/comments/models.py:59 msgid "date/time submitted" msgstr "data/hora d'enviament" -#: contrib/comments/models.py:59 +#: contrib/comments/models.py:61 msgid "is public" msgstr "és públic" -#: contrib/comments/models.py:60 +#: contrib/comments/models.py:62 msgid "" "Uncheck this box to make the comment effectively disappear from the site." msgstr "" "Desmarqui aquesta casella per fer desaparèixar aquest comentari del lloc web " "de forma efectiva." -#: contrib/comments/models.py:62 +#: contrib/comments/models.py:64 msgid "is removed" msgstr "està eliminat" -#: contrib/comments/models.py:63 +#: contrib/comments/models.py:65 msgid "" "Check this box if the comment is inappropriate. A \"This comment has been " "removed\" message will be displayed instead." @@ -1526,7 +1545,11 @@ msgstr "" "Marqueu aquesta caixa si el comentari no és apropiat. En lloc seu es " "mostrarà \"Aquest comentari ha estat eliminat\" " -#: contrib/comments/models.py:115 +#: contrib/comments/models.py:77 +msgid "comments" +msgstr "comentaris" + +#: contrib/comments/models.py:119 msgid "" "This comment was posted by an authenticated user and thus the name is read-" "only." @@ -1534,7 +1557,7 @@ msgstr "" "Aquest comentari va ser publicat per un usuari autentificat, per això el seu " "nom no es modificable." -#: contrib/comments/models.py:124 +#: contrib/comments/models.py:128 msgid "" "This comment was posted by an authenticated user and thus the email is read-" "only." @@ -1542,7 +1565,7 @@ msgstr "" "Aquest comentari va ser publicat per un usuari autentificat, per això la " "seva adreça de correu electrònic no es pot modificar." -#: contrib/comments/models.py:149 +#: contrib/comments/models.py:153 #, python-format msgid "" "Posted by %(user)s at %(date)s\n" @@ -1557,9 +1580,26 @@ msgstr "" "\n" "http://%(domain)s%(url)s" +# Context problem... waitting for comments from django-i18n +#: contrib/comments/models.py:170 +msgid "flag" +msgstr "marcar" + +#: contrib/comments/models.py:171 +msgid "date" +msgstr "data" + +#: contrib/comments/models.py:181 +msgid "comment flag" +msgstr "marca del comentari" + +#: contrib/comments/models.py:182 +msgid "comment flags" +msgstr "marques de comentari" + #: contrib/comments/templates/comments/approve.html:4 msgid "Approve a comment" -msgstr "aprovar un comentari" +msgstr "Aprovar un comentari" #: contrib/comments/templates/comments/approve.html:7 msgid "Really make this comment public?" @@ -1616,13 +1656,13 @@ msgstr "Marcar" msgid "Thanks for flagging" msgstr "Gràcies per marcar" -#: contrib/comments/templates/comments/form.html:16 -#: contrib/comments/templates/comments/preview.html:31 +#: contrib/comments/templates/comments/form.html:17 +#: contrib/comments/templates/comments/preview.html:32 msgid "Post" msgstr "Publicar" -#: contrib/comments/templates/comments/form.html:17 -#: contrib/comments/templates/comments/preview.html:32 +#: contrib/comments/templates/comments/form.html:18 +#: contrib/comments/templates/comments/preview.html:33 msgid "Preview" msgstr "Vista prèvia" @@ -1668,33 +1708,29 @@ msgid "Thank you for your comment" msgstr "Gràcies pel seu comentari" #: contrib/comments/templates/comments/preview.html:4 -#: contrib/comments/templates/comments/preview.html:12 +#: contrib/comments/templates/comments/preview.html:13 msgid "Preview your comment" msgstr "Previsualitzar el seu comentari" -#: contrib/comments/templates/comments/preview.html:10 +#: contrib/comments/templates/comments/preview.html:11 msgid "Please correct the error below" msgid_plural "Please correct the errors below" msgstr[0] "Si us plau, corregiu l'error mostrat a baix." msgstr[1] "Si us plau, corregiu els errors mostrats a baix." -#: contrib/comments/templates/comments/preview.html:15 +#: contrib/comments/templates/comments/preview.html:16 msgid "Post your comment" msgstr "Enviar el seu comentari" -#: contrib/comments/templates/comments/preview.html:15 +#: contrib/comments/templates/comments/preview.html:16 msgid "or make changes" msgstr "o faci canvis." -#: contrib/contenttypes/models.py:67 +#: contrib/contenttypes/models.py:70 msgid "python model class name" msgstr "nom de la classe del model en python" -#: contrib/contenttypes/models.py:71 -msgid "content type" -msgstr "tipus de contingut" - -#: contrib/contenttypes/models.py:72 +#: contrib/contenttypes/models.py:75 msgid "content types" msgstr "tipus de continguts" @@ -1765,18 +1801,26 @@ msgstr "" "Ho sentim, pero el seu formulari ha expirat. Per favor, continui omplint el " "formulari en aquesta pàgina." -#: contrib/gis/forms/fields.py:14 +#: contrib/gis/forms/fields.py:17 msgid "No geometry value provided." msgstr "No s'ha indicat cap valor de geometria." -#: contrib/gis/forms/fields.py:15 +#: contrib/gis/forms/fields.py:18 msgid "Invalid geometry value." msgstr "Valor de geometria invàlid." -#: contrib/gis/forms/fields.py:16 +#: contrib/gis/forms/fields.py:19 msgid "Invalid geometry type." msgstr "Tipus de geometria invàlid." +#: contrib/gis/forms/fields.py:20 +msgid "" +"An error occurred when transforming the geometry to the SRID of the geometry " +"form field." +msgstr "" +"Ha ocurregut un error al transformar la geometria al SRID de la geometria " +"del camp de formulari." + #: contrib/humanize/templatetags/humanize.py:19 msgid "th" msgstr "rt" @@ -2112,51 +2156,51 @@ msgstr "Regió Bohèmia Central" #: contrib/localflavor/cz/cz_regions.py:10 msgid "South Bohemian Region" -msgstr "Regió Bohemia Sur" +msgstr "Regió Bohèmia Sur" #: contrib/localflavor/cz/cz_regions.py:11 msgid "Pilsen Region" -msgstr "" +msgstr "Regió Pilsen" #: contrib/localflavor/cz/cz_regions.py:12 msgid "Carlsbad Region" -msgstr "" +msgstr "Regió Carlsbad" #: contrib/localflavor/cz/cz_regions.py:13 msgid "Usti Region" -msgstr "" +msgstr "Regió Usti" #: contrib/localflavor/cz/cz_regions.py:14 msgid "Liberec Region" -msgstr "" +msgstr "Regió Liberec" #: contrib/localflavor/cz/cz_regions.py:15 msgid "Hradec Region" -msgstr "" +msgstr "Regió Hradec" #: contrib/localflavor/cz/cz_regions.py:16 msgid "Pardubice Region" -msgstr "" +msgstr "Regió Pardubice" #: contrib/localflavor/cz/cz_regions.py:17 msgid "Vysocina Region" -msgstr "" +msgstr "Regió Vysocina" #: contrib/localflavor/cz/cz_regions.py:18 msgid "South Moravian Region" -msgstr "" +msgstr "Regió Moràvia Sur" #: contrib/localflavor/cz/cz_regions.py:19 msgid "Olomouc Region" -msgstr "" +msgstr "Regió Olomouc" #: contrib/localflavor/cz/cz_regions.py:20 msgid "Zlin Region" -msgstr "" +msgstr "Regió Zlin" #: contrib/localflavor/cz/cz_regions.py:21 msgid "Moravian-Silesian Region" -msgstr "" +msgstr "Regió Moràvia-Silesiana" #: contrib/localflavor/cz/forms.py:27 contrib/localflavor/sk/forms.py:30 msgid "Enter a postal code in the format XXXXX or XXX XX." @@ -2164,11 +2208,13 @@ msgstr "Introduïu un codi postal en el format XXXXX or XXX XX." #: contrib/localflavor/cz/forms.py:47 msgid "Enter a birth number in the format XXXXXX/XXXX or XXXXXXXXXX." -msgstr "Introduïu un número de naixement en el format XXXXXX/XXXX o XXXXXXXXXX." +msgstr "" +"Introduïu un número de naixement en el format XXXXXX/XXXX o XXXXXXXXXX." #: contrib/localflavor/cz/forms.py:48 msgid "Invalid optional parameter Gender, valid values are 'f' and 'm'" -msgstr "El paràmetre opcional 'Gènere' és invàlid, els valors vàlids son 'f' i 'm'." +msgstr "" +"El paràmetre opcional 'Gènere' és invàlid, els valors vàlids son 'f' i 'm'." #: contrib/localflavor/cz/forms.py:49 msgid "Enter a valid birth number." @@ -3004,16 +3050,16 @@ msgstr "Introduïu un número NIP en el format XXX-XXX-XX-XX o XX-XX-XXX-XXX." msgid "Wrong checksum for the Tax Number (NIP)." msgstr "Validació invàlida del número tributari (NIP)." -#: contrib/localflavor/pl/forms.py:111 -msgid "National Business Register Number (REGON) consists of 7 or 9 digits." +#: contrib/localflavor/pl/forms.py:109 +msgid "National Business Register Number (REGON) consists of 9 or 14 digits." msgstr "" -"El número nacional de registre de negocis (REGON) consisteix en 7 o 9 dígits." +"El número nacional de registre de negocis (REGON) consisteix en 9 o 14 dígits." -#: contrib/localflavor/pl/forms.py:112 +#: contrib/localflavor/pl/forms.py:110 msgid "Wrong checksum for the National Business Register Number (REGON)." msgstr "Validació invàlida del número nacional de registre de negocis." -#: contrib/localflavor/pl/forms.py:155 +#: contrib/localflavor/pl/forms.py:148 msgid "Enter a postal code in the format XX-XXX." msgstr "Introduïu un codi postal en el format XX-XXX." @@ -3851,60 +3897,60 @@ msgstr "nom per mostrar" msgid "sites" msgstr "llocs" -#: db/models/fields/__init__.py:356 db/models/fields/__init__.py:700 +#: db/models/fields/__init__.py:356 db/models/fields/__init__.py:710 msgid "This value must be an integer." msgstr "Aquest valor ha de ser un enter." -#: db/models/fields/__init__.py:387 +#: db/models/fields/__init__.py:388 msgid "This value must be either True or False." msgstr "Aquest valor ha de ser True (Veritat) o False (Fals)" -#: db/models/fields/__init__.py:420 +#: db/models/fields/__init__.py:427 msgid "This field cannot be null." msgstr "Aquest camp no pot ser nul." -#: db/models/fields/__init__.py:436 +#: db/models/fields/__init__.py:443 msgid "Enter only digits separated by commas." msgstr "Introduïu només dígits separats per comes." -#: db/models/fields/__init__.py:467 +#: db/models/fields/__init__.py:474 msgid "Enter a valid date in YYYY-MM-DD format." msgstr "Introduïu una data vàlida en el forma AAAA-MM-DD." -#: db/models/fields/__init__.py:476 +#: db/models/fields/__init__.py:483 #, python-format msgid "Invalid date: %s" msgstr "Data invàlida: %s" -#: db/models/fields/__init__.py:540 db/models/fields/__init__.py:558 +#: db/models/fields/__init__.py:547 db/models/fields/__init__.py:565 msgid "Enter a valid date/time in YYYY-MM-DD HH:MM[:ss[.uuuuuu]] format." msgstr "" "Introduïu un data/hora vàlida en format YYYY-MM-DD HH:MM[:ss[.uuuuuu]]." -#: db/models/fields/__init__.py:594 +#: db/models/fields/__init__.py:601 msgid "This value must be a decimal number." msgstr "Aquest valor ha de ser un número decimal." -#: db/models/fields/__init__.py:676 +#: db/models/fields/__init__.py:686 msgid "This value must be a float." msgstr "Aquest valor ha de ser un número amb punt de coma flotant." -#: db/models/fields/__init__.py:736 +#: db/models/fields/__init__.py:746 msgid "This value must be either None, True or False." msgstr "Aquest valor ha de ser None (Cap), True (Veritat) o False (Fals)" -#: db/models/fields/__init__.py:839 db/models/fields/__init__.py:853 +#: db/models/fields/__init__.py:849 db/models/fields/__init__.py:863 msgid "Enter a valid time in HH:MM[:ss[.uuuuuu]] format." msgstr "Introduïu una hora vàlida en el format HH:MM[:ss[.uuuuuu]]." -#: db/models/fields/related.py:779 +#: db/models/fields/related.py:816 msgid "" "Hold down \"Control\", or \"Command\" on a Mac, to select more than one." msgstr "" "Premeu la tecla \"Control\" -o \"Command\" en un Mac- per seleccionar més " "d'un valor." -#: db/models/fields/related.py:857 +#: db/models/fields/related.py:894 #, python-format msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid." msgid_plural "" @@ -3971,11 +4017,11 @@ msgstr "Assegureu-vos de que no hi ha més de %s decimals." msgid "Ensure that there are no more than %s digits before the decimal point." msgstr "Assegureu-vos de que no hi ha més de %s dígits decimals." -#: forms/fields.py:288 forms/fields.py:850 +#: forms/fields.py:288 forms/fields.py:863 msgid "Enter a valid date." msgstr "Introduïu una data vàlida." -#: forms/fields.py:322 forms/fields.py:851 +#: forms/fields.py:322 forms/fields.py:864 msgid "Enter a valid time." msgstr "Introduïu una hora vàlida." @@ -3996,7 +4042,15 @@ msgstr "No s'ha enviat cap fitxer." msgid "The submitted file is empty." msgstr "El fitxer enviat està buit." -#: forms/fields.py:478 +#: forms/fields.py:450 +#, python-format +msgid "" +"Ensure this filename has at most %(max)d characters (it has %(length)d)." +msgstr "" +"Assegureu-vos de que el valor té com a màxim %(max)d caràcters " +"(en té %(length)d)." + +#: forms/fields.py:483 msgid "" "Upload a valid image. The file you uploaded was either not an image or a " "corrupted image." @@ -4004,106 +4058,139 @@ msgstr "" "Envieu una imatge vàlida. El fitxer que heu enviat no era una imatge o " "estava corrupte." -#: forms/fields.py:539 +#: forms/fields.py:544 msgid "Enter a valid URL." msgstr "Introduïu una URL vàlida." -#: forms/fields.py:540 +#: forms/fields.py:545 msgid "This URL appears to be a broken link." msgstr "Aquesta URL sembla ser un enllaç trencat." -#: forms/fields.py:619 forms/fields.py:697 +#: forms/fields.py:625 forms/fields.py:703 #, python-format msgid "Select a valid choice. %(value)s is not one of the available choices." msgstr "Esculliu una opció vàlida. %(value)s no és una de les opcions vàlides." -#: forms/fields.py:698 forms/fields.py:759 forms/models.py:729 +#: forms/fields.py:704 forms/fields.py:765 forms/models.py:1003 msgid "Enter a list of values." msgstr "Introduïu una llista de valors." -#: forms/fields.py:879 +#: forms/fields.py:892 msgid "Enter a valid IPv4 address." msgstr "Introduïu una adreça IPv4 vàlida." -#: forms/fields.py:889 +#: forms/fields.py:902 msgid "" "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens." msgstr "" "Introduïu un 'slug' vàlid, consistent en lletres, números, guions o guions " "baixos." -#: forms/formsets.py:247 forms/formsets.py:249 +#: forms/formsets.py:271 forms/formsets.py:273 msgid "Order" msgstr "Ordre" -#: forms/models.py:289 forms/models.py:298 +#: forms/models.py:367 +#, python-format +msgid "%(field_name)s must be unique for %(date_field)s %(lookup)s." +msgstr "El camp %(field_name)s ha de ser únic per a %(lookup)s %(date_field)s." + +#: forms/models.py:381 forms/models.py:389 #, python-format msgid "%(model_name)s with this %(field_label)s already exists." msgstr "Ja existeix %(model_name)s amb aquest %(field_label)s." -#: forms/models.py:602 +#: forms/models.py:594 +#, python-format +msgid "Please correct the duplicate data for %(field)s." +msgstr "Si us plau, corregiu la dada duplicada per a %(field)s." + +#: forms/models.py:598 +#, python-format +msgid "Please correct the duplicate data for %(field)s, which must be unique." +msgstr "Si us plau, corregiu la dada duplicada per a %(field)s, la qual ha de ser única." + +#: forms/models.py:604 +#, python-format +msgid "" +"Please correct the duplicate data for %(field_name)s which must be unique " +"for the %(lookup)s in %(date_field)s." +msgstr "" +"Si us plau, corregiu la dada duplicada per a %(field_name)s, " +"la qual ha de ser única per a la cerca %(lookup)s en %(date_field)s." + +#: forms/models.py:612 +msgid "Please correct the duplicate values below." +msgstr "Si us plau, corregiu els valors duplicats a baix." + +#: forms/models.py:867 msgid "The inline foreign key did not match the parent instance primary key." msgstr "" "La clau forànea en línea no coincideix amb la clau primària de la instància " "del pare" -#: forms/models.py:659 +#: forms/models.py:930 msgid "Select a valid choice. That choice is not one of the available choices." msgstr "" "Escolli una opció vàlida; Aquesta opció no és una de les opcions disponibles." -#: forms/models.py:730 +#: forms/models.py:1004 #, python-format msgid "Select a valid choice. %s is not one of the available choices." msgstr "Escolliu una opció vàlida; %s' no és una de les opcions vàlides." -#: template/defaultfilters.py:751 +#: forms/models.py:1006 +#, python-format +msgid "\"%s\" is not a valid value for a primary key." +msgstr "\"%s\" no és un valor vàlid per a una clau primària." + +#: template/defaultfilters.py:767 msgid "yes,no,maybe" msgstr "si,no,potser" -#: template/defaultfilters.py:782 +#: template/defaultfilters.py:798 #, python-format msgid "%(size)d byte" msgid_plural "%(size)d bytes" msgstr[0] "%(size)d byte" msgstr[1] "%(size)d bytes" -#: template/defaultfilters.py:784 +#: template/defaultfilters.py:800 #, python-format msgid "%.1f KB" msgstr "%.1f KB" -#: template/defaultfilters.py:786 +#: template/defaultfilters.py:802 #, python-format msgid "%.1f MB" msgstr "%.1f MB" -#: template/defaultfilters.py:787 +#: template/defaultfilters.py:803 #, python-format msgid "%.1f GB" msgstr "%.1f GB" -#: utils/dateformat.py:41 +#: utils/dateformat.py:42 msgid "p.m." msgstr "p.m." -#: utils/dateformat.py:42 +#: utils/dateformat.py:43 msgid "a.m." msgstr "a.m." -#: utils/dateformat.py:47 +#: utils/dateformat.py:48 msgid "PM" msgstr "PM" -#: utils/dateformat.py:48 +#: utils/dateformat.py:49 msgid "AM" msgstr "AM" -#: utils/dateformat.py:97 +#: utils/dateformat.py:98 msgid "midnight" msgstr "mitja nit" -#: utils/dateformat.py:99 +#: utils/dateformat.py:100 msgid "noon" msgstr "mig dia" @@ -4327,16 +4414,16 @@ msgid_plural "minutes" msgstr[0] "minut" msgstr[1] "minuts" -#: utils/timesince.py:43 +#: utils/timesince.py:45 msgid "minutes" msgstr "minuts" -#: utils/timesince.py:48 +#: utils/timesince.py:50 #, python-format msgid "%(number)d %(type)s" msgstr "%(number)d %(type)s" -#: utils/timesince.py:54 +#: utils/timesince.py:56 #, python-format msgid ", %(number)d %(type)s" msgstr ", %(number)d %(type)s" @@ -4371,3 +4458,9 @@ msgstr "El/la %(verbose_name)s s'ha actualtzat amb èxit." #, python-format msgid "The %(verbose_name)s was deleted." msgstr "El %(verbose_name)s s'ha eliminat." + +#, fuzzy +#~ msgid "verbose_name" +#~ msgid_plural "verbose_name_plural" +#~ msgstr[0] "verbose_name" +#~ msgstr[1] "verbose_name_plural" diff --git a/django/conf/locale/es/LC_MESSAGES/django.mo b/django/conf/locale/es/LC_MESSAGES/django.mo index 831964a5aec4edafa3e857bdfdf374d15f12430d..a8bd5f985de2bd15ff9f9a2a0eb931d5cc4686e2 100644 GIT binary patch delta 23398 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 delta 21233 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 diff --git a/django/conf/locale/es/LC_MESSAGES/django.po b/django/conf/locale/es/LC_MESSAGES/django.po index b02ab9b7ff..fb5eec0c43 100644 --- a/django/conf/locale/es/LC_MESSAGES/django.po +++ b/django/conf/locale/es/LC_MESSAGES/django.po @@ -5,8 +5,8 @@ msgid "" msgstr "" "Project-Id-Version: Django\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-03-24 13:00+0100\n" -"PO-Revision-Date: 2009-03-24 13:26+0100\n" +"POT-Creation-Date: 2009-07-07 15:15+0200\n" +"PO-Revision-Date: 2009-07-07 15:22+0200\n" "Last-Translator: Django Spanish Team Language-" "Team: Django Spanish Team MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -217,6 +217,20 @@ msgstr "chino simplificado" msgid "Traditional Chinese" msgstr "chino tradicional" +#: contrib/admin/actions.py:60 +#, python-format +msgid "Successfully deleted %(count)d %(items)s." +msgstr "Eliminado/s %(count)d %(items)s satisfactoriamente." + +#: contrib/admin/actions.py:67 contrib/admin/options.py:1025 +msgid "Are you sure?" +msgstr "¿Está seguro?" + +#: contrib/admin/actions.py:85 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "Eliminar %(verbose_name_plural)s seleccionado/s" + #: contrib/admin/filterspecs.py:44 #, python-format msgid "" @@ -251,15 +265,15 @@ msgstr "Este mes" msgid "This year" msgstr "Este año" -#: contrib/admin/filterspecs.py:147 forms/widgets.py:413 +#: contrib/admin/filterspecs.py:147 forms/widgets.py:434 msgid "Yes" msgstr "Sí" -#: contrib/admin/filterspecs.py:147 forms/widgets.py:413 +#: contrib/admin/filterspecs.py:147 forms/widgets.py:434 msgid "No" msgstr "No" -#: contrib/admin/filterspecs.py:154 forms/widgets.py:413 +#: contrib/admin/filterspecs.py:154 forms/widgets.py:434 msgid "Unknown" msgstr "Desconocido" @@ -295,117 +309,104 @@ msgstr "entrada de registro" msgid "log entries" msgstr "entradas de registro" -#: contrib/admin/options.py:131 contrib/admin/options.py:145 +#: contrib/admin/options.py:133 contrib/admin/options.py:147 msgid "None" msgstr "Ninguno" -#: contrib/admin/options.py:498 -#, python-format -msgid "Successfully deleted %(count)d %(items)s." -msgstr "Eliminado/s %(count)d %(items)s satisfactoriamente." - -#: contrib/admin/options.py:505 contrib/admin/options.py:1012 -msgid "Are you sure?" -msgstr "¿Está seguro?" - -#: contrib/admin/options.py:523 -#, python-format -msgid "Delete selected %(verbose_name_plural)s" -msgstr "Eliminar %(verbose_name_plural)s seleccionado/s" - -#: contrib/admin/options.py:531 +#: contrib/admin/options.py:519 #, python-format msgid "Changed %s." msgstr "Modificado/a %s." -#: contrib/admin/options.py:531 contrib/admin/options.py:541 -#: contrib/comments/templates/comments/preview.html:15 forms/models.py:296 +#: contrib/admin/options.py:519 contrib/admin/options.py:529 +#: contrib/comments/templates/comments/preview.html:16 forms/models.py:388 +#: forms/models.py:600 msgid "and" msgstr "y" -#: contrib/admin/options.py:536 +#: contrib/admin/options.py:524 #, python-format msgid "Added %(name)s \"%(object)s\"." msgstr "Añadido/a \"%(object)s\" %(name)s." -#: contrib/admin/options.py:540 +#: contrib/admin/options.py:528 #, python-format msgid "Changed %(list)s for %(name)s \"%(object)s\"." msgstr "Modificados %(list)s para \"%(object)s\" %(name)s." -#: contrib/admin/options.py:545 +#: contrib/admin/options.py:533 #, python-format msgid "Deleted %(name)s \"%(object)s\"." msgstr "Eliminado/a \"%(object)s\" %(name)s." -#: contrib/admin/options.py:549 +#: contrib/admin/options.py:537 msgid "No fields changed." msgstr "No ha cambiado ningún campo." -#: contrib/admin/options.py:610 contrib/auth/admin.py:67 +#: contrib/admin/options.py:598 contrib/auth/admin.py:67 #, python-format msgid "The %(name)s \"%(obj)s\" was added successfully." msgstr "Se añadió con éxito el %(name)s \"%(obj)s\"." -#: contrib/admin/options.py:614 contrib/admin/options.py:647 +#: contrib/admin/options.py:602 contrib/admin/options.py:635 #: contrib/auth/admin.py:75 msgid "You may edit it again below." msgstr "Puede editarlo de nuevo abajo." -#: contrib/admin/options.py:624 contrib/admin/options.py:657 +#: contrib/admin/options.py:612 contrib/admin/options.py:645 #, python-format msgid "You may add another %s below." msgstr "Puede añadir otro %s abajo." -#: contrib/admin/options.py:645 +#: contrib/admin/options.py:633 #, python-format msgid "The %(name)s \"%(obj)s\" was changed successfully." msgstr "Se modificó con éxito el %(name)s \"%(obj)s\"." -#: contrib/admin/options.py:653 +#: contrib/admin/options.py:641 #, python-format msgid "" "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." msgstr "" "Se añadió con éxito el %(name)s \"%(obj)s. Puede editarlo de nuevo abajo." -#: contrib/admin/options.py:774 +#: contrib/admin/options.py:772 #, python-format msgid "Add %s" msgstr "Añadir %s" -#: contrib/admin/options.py:805 contrib/admin/options.py:990 +#: contrib/admin/options.py:803 contrib/admin/options.py:1003 #, python-format msgid "%(name)s object with primary key %(key)r does not exist." msgstr "No existe ningún objeto %(name)s con la clave primaria %(key)r." -#: contrib/admin/options.py:862 +#: contrib/admin/options.py:860 #, python-format msgid "Change %s" msgstr "Modificar %s" -#: contrib/admin/options.py:894 +#: contrib/admin/options.py:904 msgid "Database error" msgstr "Error en la base de datos" -#: contrib/admin/options.py:930 +#: contrib/admin/options.py:940 #, python-format msgid "%(count)s %(name)s was changed successfully." msgid_plural "%(count)s %(name)s were changed successfully." msgstr[0] "%(count)s %(name)s fué modificado con éxito." msgstr[1] "%(count)s %(name)s fueron modificados con éxito." -#: contrib/admin/options.py:1005 +#: contrib/admin/options.py:1018 #, python-format msgid "The %(name)s \"%(obj)s\" was deleted successfully." msgstr "Se eliminó con éxito el %(name)s \"%(obj)s\"." -#: contrib/admin/options.py:1041 +#: contrib/admin/options.py:1054 #, python-format msgid "Change history: %s" msgstr "Histórico de modificaciones: %s" -#: contrib/admin/sites.py:15 contrib/admin/views/decorators.py:14 +#: contrib/admin/sites.py:20 contrib/admin/views/decorators.py:14 #: contrib/auth/forms.py:80 msgid "" "Please enter a correct username and password. Note that both fields are case-" @@ -414,11 +415,11 @@ msgstr "" "Por favor, introduzca un nombre de usuario y contraseña correctos. Note que " "ambos campos son sensibles a mayúsculas/minúsculas." -#: contrib/admin/sites.py:250 contrib/admin/views/decorators.py:40 +#: contrib/admin/sites.py:278 contrib/admin/views/decorators.py:40 msgid "Please log in again, because your session has expired." msgstr "Por favor, inicie sesión de nuevo, ya que su sesión ha caducado." -#: contrib/admin/sites.py:257 contrib/admin/views/decorators.py:47 +#: contrib/admin/sites.py:285 contrib/admin/views/decorators.py:47 msgid "" "Looks like your browser isn't configured to accept cookies. Please enable " "cookies, reload this page, and try again." @@ -426,29 +427,29 @@ msgstr "" "Parece que su navegador no está configurado para aceptar cookies. " "Actívelas , recargue esta página, e inténtelo de nuevo." -#: contrib/admin/sites.py:273 contrib/admin/sites.py:279 +#: contrib/admin/sites.py:301 contrib/admin/sites.py:307 #: contrib/admin/views/decorators.py:66 msgid "Usernames cannot contain the '@' character." msgstr "Los nombres de usuario no pueden contener el carácter '@'." -#: contrib/admin/sites.py:276 contrib/admin/views/decorators.py:62 +#: contrib/admin/sites.py:304 contrib/admin/views/decorators.py:62 #, python-format msgid "Your e-mail address is not your username. Try '%s' instead." msgstr "" "Su dirección de correo no es su nombre de usuario. Pruebe con '%s' en su " "lugar." -#: contrib/admin/sites.py:336 +#: contrib/admin/sites.py:360 msgid "Site administration" msgstr "Sitio administrativo" -#: contrib/admin/sites.py:349 contrib/admin/templates/admin/login.html:26 +#: contrib/admin/sites.py:373 contrib/admin/templates/admin/login.html:26 #: contrib/admin/templates/registration/password_reset_complete.html:14 #: contrib/admin/views/decorators.py:20 msgid "Log in" msgstr "Iniciar sesión" -#: contrib/admin/sites.py:396 +#: contrib/admin/sites.py:417 #, python-format msgid "%s administration" msgstr "Administración de %s" @@ -463,33 +464,27 @@ msgstr "Uno o más %(fieldname)s en %(name)s: %(obj)s" msgid "One or more %(fieldname)s in %(name)s:" msgstr "Uno o más %(fieldname)s en %(name)s:" -#: contrib/admin/util.py:222 -msgid "verbose_name" -msgid_plural "verbose_name_plural" -msgstr[0] "verbose_name" -msgstr[1] "verbose_name_plural" - -#: contrib/admin/widgets.py:70 +#: contrib/admin/widgets.py:71 msgid "Date:" msgstr "Fecha:" -#: contrib/admin/widgets.py:70 +#: contrib/admin/widgets.py:71 msgid "Time:" msgstr "Hora:" -#: contrib/admin/widgets.py:94 +#: contrib/admin/widgets.py:95 msgid "Currently:" msgstr "Actualmente:" -#: contrib/admin/widgets.py:94 +#: contrib/admin/widgets.py:95 msgid "Change:" msgstr "Modificar:" -#: contrib/admin/widgets.py:123 +#: contrib/admin/widgets.py:124 msgid "Lookup" msgstr "Buscar" -#: contrib/admin/widgets.py:230 +#: contrib/admin/widgets.py:236 msgid "Add Another" msgstr "Añadir otro" @@ -504,9 +499,9 @@ msgstr "Lo sentimos, pero no se encuentra la página solicitada." #: contrib/admin/templates/admin/500.html:4 #: contrib/admin/templates/admin/app_index.html:8 -#: contrib/admin/templates/admin/base.html:33 +#: contrib/admin/templates/admin/base.html:31 #: contrib/admin/templates/admin/change_form.html:17 -#: contrib/admin/templates/admin/change_list.html:20 +#: contrib/admin/templates/admin/change_list.html:25 #: contrib/admin/templates/admin/delete_confirmation.html:6 #: contrib/admin/templates/admin/delete_selected_confirmation.html:6 #: contrib/admin/templates/admin/invalid_setup.html:4 @@ -549,7 +544,6 @@ msgid "Run the selected action" msgstr "Ejecutar la acción seleccionada" #: contrib/admin/templates/admin/actions.html:4 -#: contrib/admin/templates/admin/search_form.html:8 msgid "Go" msgstr "Ir" @@ -559,26 +553,26 @@ msgstr "Ir" msgid "%(name)s" msgstr "%(name)s" -#: contrib/admin/templates/admin/base.html:28 +#: contrib/admin/templates/admin/base.html:26 msgid "Welcome," msgstr "Bienvenido/a," -#: contrib/admin/templates/admin/base.html:28 +#: contrib/admin/templates/admin/base.html:26 #: contrib/admin/templates/registration/password_change_done.html:3 #: contrib/admin/templates/registration/password_change_form.html:3 #: contrib/admindocs/templates/admin_doc/bookmarklets.html:3 msgid "Documentation" msgstr "Documentación" -#: contrib/admin/templates/admin/base.html:28 -#: contrib/admin/templates/admin/auth/user/change_password.html:13 -#: contrib/admin/templates/admin/auth/user/change_password.html:46 +#: contrib/admin/templates/admin/base.html:26 +#: contrib/admin/templates/admin/auth/user/change_password.html:14 +#: contrib/admin/templates/admin/auth/user/change_password.html:47 #: contrib/admin/templates/registration/password_change_done.html:3 #: contrib/admin/templates/registration/password_change_form.html:3 msgid "Change password" msgstr "Cambiar contraseña" -#: contrib/admin/templates/admin/base.html:28 +#: contrib/admin/templates/admin/base.html:26 #: contrib/admin/templates/registration/password_change_done.html:3 #: contrib/admin/templates/registration/password_change_form.html:3 msgid "Log out" @@ -609,24 +603,24 @@ msgid "View on site" msgstr "Ver en el sitio" #: contrib/admin/templates/admin/change_form.html:38 -#: contrib/admin/templates/admin/change_list.html:49 -#: contrib/admin/templates/admin/auth/user/change_password.html:22 +#: contrib/admin/templates/admin/change_list.html:54 +#: contrib/admin/templates/admin/auth/user/change_password.html:23 msgid "Please correct the error below." msgid_plural "Please correct the errors below." msgstr[0] "Por favor, corrija el siguiente error." msgstr[1] "Por favor, corrija los siguientes errores." -#: contrib/admin/templates/admin/change_list.html:41 +#: contrib/admin/templates/admin/change_list.html:46 #, python-format msgid "Add %(name)s" msgstr "Añadir %(name)s" -#: contrib/admin/templates/admin/change_list.html:60 +#: contrib/admin/templates/admin/change_list.html:65 msgid "Filter" msgstr "Filtro" #: contrib/admin/templates/admin/delete_confirmation.html:10 -#: contrib/admin/templates/admin/submit_line.html:4 forms/formsets.py:251 +#: contrib/admin/templates/admin/submit_line.html:4 forms/formsets.py:275 msgid "Delete" msgstr "Eliminar" @@ -666,9 +660,9 @@ msgid "" "your account doesn't have permission to delete the following types of " "objects:" msgstr "" -"Eliminar el %(object_name)s provocaría la eliminación " -"de objetos relacionados, pero su cuenta no tiene permiso para borrar los " -"siguientes tipos de objetos:" +"Eliminar el %(object_name)s provocaría la eliminación de objetos " +"relacionados, pero su cuenta no tiene permiso para borrar los siguientes " +"tipos de objetos:" #: contrib/admin/templates/admin/delete_selected_confirmation.html:22 #, python-format @@ -676,8 +670,8 @@ msgid "" "Are you sure you want to delete the selected %(object_name)s objects? All of " "the following objects and it's related items will be deleted:" msgstr "" -"¿Está seguro de que quiere borrar los %(object_name)s? " -"Los siguientes objetos y sus elementos relacionados serán eliminados:" +"¿Está seguro de que quiere borrar los %(object_name)s? Los siguientes " +"objetos y sus elementos relacionados serán eliminados:" #: contrib/admin/templates/admin/filter.html:2 #, python-format @@ -709,6 +703,10 @@ msgstr "Mis acciones" msgid "None available" msgstr "Ninguno disponible" +#: contrib/admin/templates/admin/index.html:72 +msgid "Unknown content" +msgstr "Contenido desconocido" + #: contrib/admin/templates/admin/invalid_setup.html:7 msgid "" "Something's wrong with your database installation. Make sure the appropriate " @@ -757,6 +755,15 @@ msgstr "" msgid "Show all" msgstr "Mostrar todo" +#: contrib/admin/templates/admin/pagination.html:11 +#: contrib/admin/templates/admin/submit_line.html:3 +msgid "Save" +msgstr "Grabar" + +#: contrib/admin/templates/admin/search_form.html:8 +msgid "Search" +msgstr "Buscar" + #: contrib/admin/templates/admin/search_form.html:10 #, python-format msgid "1 result" @@ -769,10 +776,6 @@ msgstr[1] "%(counter)s resultados" msgid "%(full_result_count)s total" msgstr "%(full_result_count)s total" -#: contrib/admin/templates/admin/submit_line.html:3 -msgid "Save" -msgstr "Grabar" - #: contrib/admin/templates/admin/submit_line.html:5 msgid "Save as new" msgstr "Grabar como nuevo" @@ -799,23 +802,23 @@ msgid "Username" msgstr "Nombre de usuario" #: contrib/admin/templates/admin/auth/user/add_form.html:20 -#: contrib/admin/templates/admin/auth/user/change_password.html:33 +#: contrib/admin/templates/admin/auth/user/change_password.html:34 #: contrib/auth/forms.py:17 contrib/auth/forms.py:60 contrib/auth/forms.py:185 msgid "Password" msgstr "Contraseña" #: contrib/admin/templates/admin/auth/user/add_form.html:26 -#: contrib/admin/templates/admin/auth/user/change_password.html:39 +#: contrib/admin/templates/admin/auth/user/change_password.html:40 #: contrib/auth/forms.py:186 msgid "Password (again)" msgstr "Contraseña (de nuevo)" #: contrib/admin/templates/admin/auth/user/add_form.html:27 -#: contrib/admin/templates/admin/auth/user/change_password.html:40 +#: contrib/admin/templates/admin/auth/user/change_password.html:41 msgid "Enter the same password as above, for verification." msgstr "Introduzca la misma contraseña que arriba, para verificación." -#: contrib/admin/templates/admin/auth/user/change_password.html:26 +#: contrib/admin/templates/admin/auth/user/change_password.html:27 #, python-format msgid "Enter a new password for the user %(username)s." msgstr "" @@ -1037,114 +1040,115 @@ msgstr "" msgid "the related `%(app_label)s.%(data_type)s` object" msgstr "el objeto relacionado `%(app_label)s.%(data_type)s`" -#: contrib/admindocs/views.py:206 contrib/admindocs/views.py:228 -#: contrib/admindocs/views.py:242 contrib/admindocs/views.py:247 +#: contrib/admindocs/views.py:206 contrib/admindocs/views.py:225 +#: contrib/admindocs/views.py:230 contrib/admindocs/views.py:244 +#: contrib/admindocs/views.py:258 contrib/admindocs/views.py:263 msgid "model:" msgstr "modelo:" -#: contrib/admindocs/views.py:237 +#: contrib/admindocs/views.py:221 contrib/admindocs/views.py:253 #, python-format msgid "related `%(app_label)s.%(object_name)s` objects" msgstr "los objetos relacionados `%(app_label)s.%(object_name)s`" -#: contrib/admindocs/views.py:242 +#: contrib/admindocs/views.py:225 contrib/admindocs/views.py:258 #, python-format msgid "all %s" msgstr "todo %s" -#: contrib/admindocs/views.py:247 +#: contrib/admindocs/views.py:230 contrib/admindocs/views.py:263 #, python-format msgid "number of %s" msgstr "número de %s" -#: contrib/admindocs/views.py:252 +#: contrib/admindocs/views.py:268 #, python-format msgid "Fields on %s objects" msgstr "Campos en %s objetos" -#: contrib/admindocs/views.py:315 contrib/admindocs/views.py:326 -#: contrib/admindocs/views.py:328 contrib/admindocs/views.py:334 -#: contrib/admindocs/views.py:335 contrib/admindocs/views.py:337 +#: contrib/admindocs/views.py:331 contrib/admindocs/views.py:342 +#: contrib/admindocs/views.py:344 contrib/admindocs/views.py:350 +#: contrib/admindocs/views.py:351 contrib/admindocs/views.py:353 msgid "Integer" msgstr "Entero" -#: contrib/admindocs/views.py:316 +#: contrib/admindocs/views.py:332 msgid "Boolean (Either True or False)" msgstr "Booleano (Verdadero o Falso)" -#: contrib/admindocs/views.py:317 contrib/admindocs/views.py:336 +#: contrib/admindocs/views.py:333 contrib/admindocs/views.py:352 #, python-format msgid "String (up to %(max_length)s)" msgstr "Cadena (máximo %(max_length)s)" -#: contrib/admindocs/views.py:318 +#: contrib/admindocs/views.py:334 msgid "Comma-separated integers" msgstr "Enteros separados por comas" -#: contrib/admindocs/views.py:319 +#: contrib/admindocs/views.py:335 msgid "Date (without time)" msgstr "Fecha (sin hora)" -#: contrib/admindocs/views.py:320 +#: contrib/admindocs/views.py:336 msgid "Date (with time)" msgstr "Fecha (con hora)" -#: contrib/admindocs/views.py:321 +#: contrib/admindocs/views.py:337 msgid "Decimal number" msgstr "Número decimal" -#: contrib/admindocs/views.py:322 +#: contrib/admindocs/views.py:338 msgid "E-mail address" msgstr "Dirección de correo electrónico" -#: contrib/admindocs/views.py:323 contrib/admindocs/views.py:324 -#: contrib/admindocs/views.py:327 +#: contrib/admindocs/views.py:339 contrib/admindocs/views.py:340 +#: contrib/admindocs/views.py:343 msgid "File path" msgstr "Ruta de fichero" -#: contrib/admindocs/views.py:325 +#: contrib/admindocs/views.py:341 msgid "Floating point number" msgstr "Número en coma flotante" -#: contrib/admindocs/views.py:329 contrib/comments/models.py:58 +#: contrib/admindocs/views.py:345 contrib/comments/models.py:60 msgid "IP address" msgstr "Dirección IP" -#: contrib/admindocs/views.py:331 +#: contrib/admindocs/views.py:347 msgid "Boolean (Either True, False or None)" msgstr "Booleano (Verdadero, Falso o Nulo)" -#: contrib/admindocs/views.py:332 +#: contrib/admindocs/views.py:348 msgid "Relation to parent model" msgstr "Relación con el modelo padre" -#: contrib/admindocs/views.py:333 +#: contrib/admindocs/views.py:349 msgid "Phone number" msgstr "Número de teléfono" -#: contrib/admindocs/views.py:338 +#: contrib/admindocs/views.py:354 msgid "Text" msgstr "Texto" -#: contrib/admindocs/views.py:339 +#: contrib/admindocs/views.py:355 msgid "Time" msgstr "Hora" -#: contrib/admindocs/views.py:340 contrib/comments/forms.py:95 +#: contrib/admindocs/views.py:356 contrib/comments/forms.py:95 #: contrib/comments/templates/comments/moderation_queue.html:37 #: contrib/flatpages/admin.py:8 contrib/flatpages/models.py:7 msgid "URL" msgstr "URL" -#: contrib/admindocs/views.py:341 +#: contrib/admindocs/views.py:357 msgid "U.S. state (two uppercase letters)" msgstr "Estado de los EEUU (dos letras mayúsculas)" -#: contrib/admindocs/views.py:342 +#: contrib/admindocs/views.py:358 msgid "XML text" msgstr "Texto XML" -#: contrib/admindocs/views.py:368 +#: contrib/admindocs/views.py:384 #, python-format msgid "%s does not appear to be a urlpattern object" msgstr "%s no parece ser un objeto urlpattern" @@ -1248,7 +1252,7 @@ msgid "Change password: %s" msgstr "Cambiar contraseña: %s" #: contrib/auth/forms.py:15 contrib/auth/forms.py:48 -#: contrib/auth/models.py:127 +#: contrib/auth/models.py:128 msgid "" "Required. 30 characters or fewer. Alphanumeric characters only (letters, " "digits and underscores)." @@ -1340,31 +1344,31 @@ msgstr "permisos" msgid "group" msgstr "grupo" -#: contrib/auth/models.py:91 contrib/auth/models.py:137 +#: contrib/auth/models.py:91 contrib/auth/models.py:138 msgid "groups" msgstr "grupos" -#: contrib/auth/models.py:127 +#: contrib/auth/models.py:128 msgid "username" msgstr "nombre de usuario" -#: contrib/auth/models.py:128 +#: contrib/auth/models.py:129 msgid "first name" msgstr "nombre propio" -#: contrib/auth/models.py:129 +#: contrib/auth/models.py:130 msgid "last name" msgstr "apellidos" -#: contrib/auth/models.py:130 +#: contrib/auth/models.py:131 msgid "e-mail address" msgstr "dirección de correo electrónico" -#: contrib/auth/models.py:131 +#: contrib/auth/models.py:132 msgid "password" msgstr "contraseña" -#: contrib/auth/models.py:131 +#: contrib/auth/models.py:132 msgid "" "Use '[algo]$[salt]$[hexdigest]' or use the change " "password form." @@ -1372,19 +1376,19 @@ msgstr "" "Use'[algo]$[sal]$[hash hexadecimal]' o use el " "formulario para cambiar la contraseña." -#: contrib/auth/models.py:132 +#: contrib/auth/models.py:133 msgid "staff status" msgstr "es staff" -#: contrib/auth/models.py:132 +#: contrib/auth/models.py:133 msgid "Designates whether the user can log into this admin site." msgstr "Indica si el usuario puede entrar en este sitio de administración." -#: contrib/auth/models.py:133 +#: contrib/auth/models.py:134 msgid "active" msgstr "activo" -#: contrib/auth/models.py:133 +#: contrib/auth/models.py:134 msgid "" "Designates whether this user should be treated as active. Unselect this " "instead of deleting accounts." @@ -1392,11 +1396,11 @@ msgstr "" "Indica si el usuario puede ser tratado como activo. Desmarque esta opción en " "lugar de borrar la cuenta." -#: contrib/auth/models.py:134 +#: contrib/auth/models.py:135 msgid "superuser status" msgstr "es superusuario" -#: contrib/auth/models.py:134 +#: contrib/auth/models.py:135 msgid "" "Designates that this user has all permissions without explicitly assigning " "them." @@ -1404,15 +1408,15 @@ msgstr "" "Indica que este usuario tiene todos los permisos sin asignárselos " "explícitamente." -#: contrib/auth/models.py:135 +#: contrib/auth/models.py:136 msgid "last login" msgstr "último inicio de sesión" -#: contrib/auth/models.py:136 +#: contrib/auth/models.py:137 msgid "date joined" msgstr "fecha de alta" -#: contrib/auth/models.py:138 +#: contrib/auth/models.py:139 msgid "" "In addition to the permissions manually assigned, this user will also get " "all permissions granted to each group he/she is in." @@ -1420,23 +1424,24 @@ msgstr "" "Además de los permisos asignados manualmente, este usuario también tendrá " "todos los permisos de los grupos en los que esté." -#: contrib/auth/models.py:139 +#: contrib/auth/models.py:140 msgid "user permissions" msgstr "permisos de usuario" -#: contrib/auth/models.py:143 +#: contrib/auth/models.py:144 contrib/comments/models.py:50 +#: contrib/comments/models.py:168 msgid "user" msgstr "usuario" -#: contrib/auth/models.py:144 +#: contrib/auth/models.py:145 msgid "users" msgstr "usuarios" -#: contrib/auth/models.py:300 +#: contrib/auth/models.py:301 msgid "message" msgstr "mensaje" -#: contrib/auth/views.py:50 +#: contrib/auth/views.py:56 msgid "Logged out" msgstr "Sesión terminada" @@ -1452,10 +1457,20 @@ msgstr "contenido" msgid "Metadata" msgstr "metadatos" +#: contrib/comments/feeds.py:13 +#, python-format +msgid "%(site_name)s comments" +msgstr "comentarios de %(site_name)s" + +#: contrib/comments/feeds.py:23 +#, python-format +msgid "Latest comments on %(site_name)s" +msgstr "Últimos comentarios en %(site_name)s" + #: contrib/comments/forms.py:93 #: contrib/comments/templates/comments/moderation_queue.html:34 msgid "Name" -msgstr "nombre" +msgstr "Nombre" #: contrib/comments/forms.py:94 msgid "Email address" @@ -1464,7 +1479,7 @@ msgstr "dirección de correo electrónico" #: contrib/comments/forms.py:96 #: contrib/comments/templates/comments/moderation_queue.html:35 msgid "Comment" -msgstr "comentario" +msgstr "Comentario" #: contrib/comments/forms.py:173 #, python-format @@ -1478,46 +1493,51 @@ msgid "" "If you enter anything in this field your comment will be treated as spam" msgstr "Si introduce algo en este campo su comentario será tratado como spam" -#: contrib/comments/models.py:23 +#: contrib/comments/models.py:22 contrib/contenttypes/models.py:74 +msgid "content type" +msgstr "tipo de contenido" + +#: contrib/comments/models.py:24 msgid "object ID" msgstr "ID de objeto" -#: contrib/comments/models.py:50 +#: contrib/comments/models.py:52 msgid "user's name" msgstr "nombre del usuario" -#: contrib/comments/models.py:51 +#: contrib/comments/models.py:53 msgid "user's email address" msgstr "dirección de correo electrónico del usuario" -#: contrib/comments/models.py:52 +#: contrib/comments/models.py:54 msgid "user's URL" msgstr "URL del usuario" -#: contrib/comments/models.py:54 +#: contrib/comments/models.py:56 contrib/comments/models.py:76 +#: contrib/comments/models.py:169 msgid "comment" msgstr "comentario" -#: contrib/comments/models.py:57 +#: contrib/comments/models.py:59 msgid "date/time submitted" msgstr "fecha/hora de envío" -#: contrib/comments/models.py:59 +#: contrib/comments/models.py:61 msgid "is public" msgstr "es público" -#: contrib/comments/models.py:60 +#: contrib/comments/models.py:62 msgid "" "Uncheck this box to make the comment effectively disappear from the site." msgstr "" "Desmarque esta casilla para hacer desaparecer el comentario del sitio web de " "forma efectiva." -#: contrib/comments/models.py:62 +#: contrib/comments/models.py:64 msgid "is removed" msgstr "está eliminado" -#: contrib/comments/models.py:63 +#: contrib/comments/models.py:65 msgid "" "Check this box if the comment is inappropriate. A \"This comment has been " "removed\" message will be displayed instead." @@ -1525,7 +1545,11 @@ msgstr "" "Marque esta opción si el comentario es inapropiado. En su lugar se mostrará " "el mensaje \"Este comentario ha sido eliminado\"." -#: contrib/comments/models.py:115 +#: contrib/comments/models.py:77 +msgid "comments" +msgstr "comentarios" + +#: contrib/comments/models.py:119 msgid "" "This comment was posted by an authenticated user and thus the name is read-" "only." @@ -1533,7 +1557,7 @@ msgstr "" "Este comentario ha sido enviado por un usuario autentificado: de modo que su " "nombre no es modificable." -#: contrib/comments/models.py:124 +#: contrib/comments/models.py:128 msgid "" "This comment was posted by an authenticated user and thus the email is read-" "only." @@ -1541,7 +1565,7 @@ msgstr "" "Este comentario ha sido colocado por un usuario autentificado: de modo que " "su dirección de correo electrónico no es modificable." -#: contrib/comments/models.py:149 +#: contrib/comments/models.py:153 #, python-format msgid "" "Posted by %(user)s at %(date)s\n" @@ -1556,6 +1580,22 @@ msgstr "" "\n" "http://%(domain)s%(url)s" +#: contrib/comments/models.py:170 +msgid "flag" +msgstr "marcar" + +#: contrib/comments/models.py:171 +msgid "date" +msgstr "fecha" + +#: contrib/comments/models.py:181 +msgid "comment flag" +msgstr "marca de comentario" + +#: contrib/comments/models.py:182 +msgid "comment flags" +msgstr "marcas de comentario" + #: contrib/comments/templates/comments/approve.html:4 msgid "Approve a comment" msgstr "Aprovar un comentario" @@ -1615,13 +1655,13 @@ msgstr "Marcar" msgid "Thanks for flagging" msgstr "Graciar por marcar" -#: contrib/comments/templates/comments/form.html:16 -#: contrib/comments/templates/comments/preview.html:31 +#: contrib/comments/templates/comments/form.html:17 +#: contrib/comments/templates/comments/preview.html:32 msgid "Post" msgstr "Enviar" -#: contrib/comments/templates/comments/form.html:17 -#: contrib/comments/templates/comments/preview.html:32 +#: contrib/comments/templates/comments/form.html:18 +#: contrib/comments/templates/comments/preview.html:33 msgid "Preview" msgstr "Previsualizar" @@ -1667,33 +1707,29 @@ msgid "Thank you for your comment" msgstr "Gracias por su comentario" #: contrib/comments/templates/comments/preview.html:4 -#: contrib/comments/templates/comments/preview.html:12 +#: contrib/comments/templates/comments/preview.html:13 msgid "Preview your comment" msgstr "Previsualizar su comentario" -#: contrib/comments/templates/comments/preview.html:10 +#: contrib/comments/templates/comments/preview.html:11 msgid "Please correct the error below" msgid_plural "Please correct the errors below" msgstr[0] "Por favor, corrija el siguiente error." msgstr[1] "Por favor, corrija los siguientes errores." -#: contrib/comments/templates/comments/preview.html:15 +#: contrib/comments/templates/comments/preview.html:16 msgid "Post your comment" msgstr "Envie su comentario" -#: contrib/comments/templates/comments/preview.html:15 +#: contrib/comments/templates/comments/preview.html:16 msgid "or make changes" msgstr "o haga cambios" -#: contrib/contenttypes/models.py:67 +#: contrib/contenttypes/models.py:70 msgid "python model class name" msgstr "nombre de la clase modelo de python" -#: contrib/contenttypes/models.py:71 -msgid "content type" -msgstr "tipo de contenido" - -#: contrib/contenttypes/models.py:72 +#: contrib/contenttypes/models.py:75 msgid "content types" msgstr "tipos de contenido" @@ -1762,18 +1798,26 @@ msgstr "" "Lo sentimos, pero su formulario ha expirado. Por favor, continue rellenando " "el formulario en esta página." -#: contrib/gis/forms/fields.py:14 +#: contrib/gis/forms/fields.py:17 msgid "No geometry value provided." msgstr "No se indico ningún valor de geometría." -#: contrib/gis/forms/fields.py:15 +#: contrib/gis/forms/fields.py:18 msgid "Invalid geometry value." msgstr "Valor de geometría inválido." -#: contrib/gis/forms/fields.py:16 +#: contrib/gis/forms/fields.py:19 msgid "Invalid geometry type." msgstr "Tipo de geometría inválido." +#: contrib/gis/forms/fields.py:20 +msgid "" +"An error occurred when transforming the geometry to the SRID of the geometry " +"form field." +msgstr "" +"Ocurrió un error al transformar la geometria al SRID de la geometria " +"del campo de formulario." + #: contrib/humanize/templatetags/humanize.py:19 msgid "th" msgstr "º" @@ -1891,11 +1935,11 @@ msgstr "Carinthia" #: contrib/localflavor/at/at_states.py:7 msgid "Lower Austria" -msgstr "" +msgstr "Australia Baja" #: contrib/localflavor/at/at_states.py:8 msgid "Upper Austria" -msgstr "" +msgstr "Australia Alta" #: contrib/localflavor/at/at_states.py:9 msgid "Salzburg" @@ -2112,47 +2156,47 @@ msgstr "Región Bohemia Sur" #: contrib/localflavor/cz/cz_regions.py:11 msgid "Pilsen Region" -msgstr "" +msgstr "Región Pilsen" #: contrib/localflavor/cz/cz_regions.py:12 msgid "Carlsbad Region" -msgstr "" +msgstr "Región Carlsbad" #: contrib/localflavor/cz/cz_regions.py:13 msgid "Usti Region" -msgstr "" +msgstr "Región Usti" #: contrib/localflavor/cz/cz_regions.py:14 msgid "Liberec Region" -msgstr "" +msgstr "Región Liberec" #: contrib/localflavor/cz/cz_regions.py:15 msgid "Hradec Region" -msgstr "" +msgstr "Región Hradec" #: contrib/localflavor/cz/cz_regions.py:16 msgid "Pardubice Region" -msgstr "" +msgstr "Región Pardubice" #: contrib/localflavor/cz/cz_regions.py:17 msgid "Vysocina Region" -msgstr "" +msgstr "Región Vysocina" #: contrib/localflavor/cz/cz_regions.py:18 msgid "South Moravian Region" -msgstr "" +msgstr "Región Moravia Sur" #: contrib/localflavor/cz/cz_regions.py:19 msgid "Olomouc Region" -msgstr "" +msgstr "Región Olomouc" #: contrib/localflavor/cz/cz_regions.py:20 msgid "Zlin Region" -msgstr "" +msgstr "Región Zlin" #: contrib/localflavor/cz/cz_regions.py:21 msgid "Moravian-Silesian Region" -msgstr "" +msgstr "Región Moravia-Silesiana" #: contrib/localflavor/cz/forms.py:27 contrib/localflavor/sk/forms.py:30 msgid "Enter a postal code in the format XXXXX or XXX XX." @@ -2165,7 +2209,8 @@ msgstr "" #: contrib/localflavor/cz/forms.py:48 msgid "Invalid optional parameter Gender, valid values are 'f' and 'm'" -msgstr "El parámetro opcional 'Género' es inválido, los valores válidos son 'f' y 'm'" +msgstr "" +"El parámetro opcional 'Género' es inválido, los valores válidos son 'f' y 'm'" #: contrib/localflavor/cz/forms.py:49 msgid "Enter a valid birth number." @@ -3004,16 +3049,16 @@ msgstr "" msgid "Wrong checksum for the Tax Number (NIP)." msgstr "El Número de Identificación Tributaria (NIP) es incorrecto." -#: contrib/localflavor/pl/forms.py:111 -msgid "National Business Register Number (REGON) consists of 7 or 9 digits." +#: contrib/localflavor/pl/forms.py:109 +msgid "National Business Register Number (REGON) consists of 9 or 14 digits." msgstr "" -"El Número Nacional de Registro de Negocios (REGON) consiste en 7 o 9 dígitos." +"El Número Nacional de Registro de Negocios (REGON) consiste en 9 o 14 dígitos." -#: contrib/localflavor/pl/forms.py:112 +#: contrib/localflavor/pl/forms.py:110 msgid "Wrong checksum for the National Business Register Number (REGON)." msgstr "El Número Nacional de Registro de Negocios (REGON) es incorrecto." -#: contrib/localflavor/pl/forms.py:155 +#: contrib/localflavor/pl/forms.py:148 msgid "Enter a postal code in the format XX-XXX." msgstr "Introduzca un código postal en el formato XX-XXX." @@ -3850,60 +3895,60 @@ msgstr "nombre para mostrar" msgid "sites" msgstr "sitios" -#: db/models/fields/__init__.py:356 db/models/fields/__init__.py:700 +#: db/models/fields/__init__.py:356 db/models/fields/__init__.py:710 msgid "This value must be an integer." msgstr "Este valor debe ser un entero." -#: db/models/fields/__init__.py:387 +#: db/models/fields/__init__.py:388 msgid "This value must be either True or False." msgstr "Este valor debe ser Verdadero o Falso." -#: db/models/fields/__init__.py:420 +#: db/models/fields/__init__.py:427 msgid "This field cannot be null." msgstr "Este campo no puede estar vacío." -#: db/models/fields/__init__.py:436 +#: db/models/fields/__init__.py:443 msgid "Enter only digits separated by commas." msgstr "Introduzca sólo dígitos separados por comas." -#: db/models/fields/__init__.py:467 +#: db/models/fields/__init__.py:474 msgid "Enter a valid date in YYYY-MM-DD format." msgstr "Introduzca una fecha válida en formato AAAA-MM-DD." -#: db/models/fields/__init__.py:476 +#: db/models/fields/__init__.py:483 #, python-format msgid "Invalid date: %s" msgstr "Fecha no válida: %s" -#: db/models/fields/__init__.py:540 db/models/fields/__init__.py:558 +#: db/models/fields/__init__.py:547 db/models/fields/__init__.py:565 msgid "Enter a valid date/time in YYYY-MM-DD HH:MM[:ss[.uuuuuu]] format." msgstr "" "Introduzca una fecha/hora válida en formato AAAA-MM-DD HH:MM[:ss[.uuuuuu]]." -#: db/models/fields/__init__.py:594 +#: db/models/fields/__init__.py:601 msgid "This value must be a decimal number." msgstr "Este valor debe ser un entero." -#: db/models/fields/__init__.py:676 +#: db/models/fields/__init__.py:686 msgid "This value must be a float." msgstr "Este valor debe ser un número con coma flotante." -#: db/models/fields/__init__.py:736 +#: db/models/fields/__init__.py:746 msgid "This value must be either None, True or False." msgstr "Este valor debe ser Verdadero, Falso o Ninguno." -#: db/models/fields/__init__.py:839 db/models/fields/__init__.py:853 +#: db/models/fields/__init__.py:849 db/models/fields/__init__.py:863 msgid "Enter a valid time in HH:MM[:ss[.uuuuuu]] format." msgstr "Introduzca una hora válida en formato HH:MM[:ss[.uuuuuu]]." -#: db/models/fields/related.py:779 +#: db/models/fields/related.py:816 msgid "" "Hold down \"Control\", or \"Command\" on a Mac, to select more than one." msgstr "" "Mantenga presionado \"Control\", o \"Command\" en un Mac, para seleccionar " "más de una opción." -#: db/models/fields/related.py:857 +#: db/models/fields/related.py:894 #, python-format msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid." msgid_plural "" @@ -3970,11 +4015,11 @@ msgstr "Asegúrese de que no hay más de %s decimales." msgid "Ensure that there are no more than %s digits before the decimal point." msgstr "Asegúrese de que no hay más de %s dígitos antes de la coma decimal." -#: forms/fields.py:288 forms/fields.py:850 +#: forms/fields.py:288 forms/fields.py:863 msgid "Enter a valid date." msgstr "Introduzca una fecha válida." -#: forms/fields.py:322 forms/fields.py:851 +#: forms/fields.py:322 forms/fields.py:864 msgid "Enter a valid time." msgstr "Introduzca una hora válida." @@ -3996,7 +4041,15 @@ msgstr "No se ha enviado ningún fichero" msgid "The submitted file is empty." msgstr "El fichero enviado está vacío." -#: forms/fields.py:478 +#: forms/fields.py:450 +#, python-format +msgid "" +"Ensure this filename has at most %(max)d characters (it has %(length)d)." +msgstr "" +"Asegúrese de que su texto tiene no más de %(max)d caracteres (actualmente " +"tiene %(length)d)." + +#: forms/fields.py:483 msgid "" "Upload a valid image. The file you uploaded was either not an image or a " "corrupted image." @@ -4004,106 +4057,140 @@ msgstr "" "Envíe una imagen válida. El fichero que ha enviado no era una imagen o se " "trataba de una imagen corrupta." -#: forms/fields.py:539 +#: forms/fields.py:544 msgid "Enter a valid URL." msgstr "Introduzca una URL válida." -#: forms/fields.py:540 +#: forms/fields.py:545 msgid "This URL appears to be a broken link." msgstr "La URL parece ser un enlace roto." -#: forms/fields.py:619 forms/fields.py:697 +#: forms/fields.py:625 forms/fields.py:703 #, python-format msgid "Select a valid choice. %(value)s is not one of the available choices." msgstr "" "Escoja una opción válida. %(value)s no es una de las opciones disponibles." -#: forms/fields.py:698 forms/fields.py:759 forms/models.py:729 +#: forms/fields.py:704 forms/fields.py:765 forms/models.py:1003 msgid "Enter a list of values." msgstr "Introduzca una lista de valores." -#: forms/fields.py:879 +#: forms/fields.py:892 msgid "Enter a valid IPv4 address." msgstr "Introduzca una dirección IPv4 válida." -#: forms/fields.py:889 +#: forms/fields.py:902 msgid "" "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens." msgstr "" "Introduzca un 'slug' válido, consistente en letras, números, guiones bajos o " "medios." -#: forms/formsets.py:247 forms/formsets.py:249 +#: forms/formsets.py:271 forms/formsets.py:273 msgid "Order" msgstr "Orden" -#: forms/models.py:289 forms/models.py:298 +#: forms/models.py:367 +#, python-format +msgid "%(field_name)s must be unique for %(date_field)s %(lookup)s." +msgstr "El campo %(field_name)s debe ser único para %(lookup)s %(date_field)s" + +#: forms/models.py:381 forms/models.py:389 #, python-format msgid "%(model_name)s with this %(field_label)s already exists." msgstr "Ya existe %(model_name)s con este %(field_label)s." -#: forms/models.py:602 +#: forms/models.py:594 +#, python-format +msgid "Please correct the duplicate data for %(field)s." +msgstr "Por favor, corrija el dato duplicado para %(field)s." + +#: forms/models.py:598 +#, python-format +msgid "Please correct the duplicate data for %(field)s, which must be unique." +msgstr "" +"Por favor corriga el dato duplicado para %(field)s, el cual debe ser único." + +#: forms/models.py:604 +#, python-format +msgid "" +"Please correct the duplicate data for %(field_name)s which must be unique " +"for the %(lookup)s in %(date_field)s." +msgstr "" +"Por favor corriga los datos duplicados para %(field_name)s el cual debe ser " +"único para %(lookup)s en %(date_field)s." + +#: forms/models.py:612 +msgid "Please correct the duplicate values below." +msgstr "Por favor, corrija los valores duplicados abajo." + +#: forms/models.py:867 msgid "The inline foreign key did not match the parent instance primary key." msgstr "" "La clave foránea en linea no coincide con la clave primaria de la instancia " "padre." -#: forms/models.py:659 +#: forms/models.py:930 msgid "Select a valid choice. That choice is not one of the available choices." msgstr "Escoja una opción válida. Esa opción no está entre las disponibles." -#: forms/models.py:730 +#: forms/models.py:1004 #, python-format msgid "Select a valid choice. %s is not one of the available choices." msgstr "Escoja una opción válida; '%s' no es una de las opciones disponibles." -#: template/defaultfilters.py:751 +#: forms/models.py:1006 +#, python-format +msgid "\"%s\" is not a valid value for a primary key." +msgstr "\"%s\" no es un valor válido para una clave primaria." + +#: template/defaultfilters.py:767 msgid "yes,no,maybe" msgstr "sí,no,tal vez" -#: template/defaultfilters.py:782 +#: template/defaultfilters.py:798 #, python-format msgid "%(size)d byte" msgid_plural "%(size)d bytes" msgstr[0] "%(size)d byte" msgstr[1] "%(size)d bytes" -#: template/defaultfilters.py:784 +#: template/defaultfilters.py:800 #, python-format msgid "%.1f KB" msgstr "%.1f KB" -#: template/defaultfilters.py:786 +#: template/defaultfilters.py:802 #, python-format msgid "%.1f MB" msgstr "%.1f MB" -#: template/defaultfilters.py:787 +#: template/defaultfilters.py:803 #, python-format msgid "%.1f GB" msgstr "%.1f GB" -#: utils/dateformat.py:41 +#: utils/dateformat.py:42 msgid "p.m." msgstr "p.m." -#: utils/dateformat.py:42 +#: utils/dateformat.py:43 msgid "a.m." msgstr "a.m." -#: utils/dateformat.py:47 +#: utils/dateformat.py:48 msgid "PM" msgstr "PM" -#: utils/dateformat.py:48 +#: utils/dateformat.py:49 msgid "AM" msgstr "AM" -#: utils/dateformat.py:97 +#: utils/dateformat.py:98 msgid "midnight" msgstr "media noche" -#: utils/dateformat.py:99 +#: utils/dateformat.py:100 msgid "noon" msgstr "medio día" @@ -4327,16 +4414,16 @@ msgid_plural "minutes" msgstr[0] "minuto" msgstr[1] "minutos" -#: utils/timesince.py:43 +#: utils/timesince.py:45 msgid "minutes" msgstr "minutos" -#: utils/timesince.py:48 +#: utils/timesince.py:50 #, python-format msgid "%(number)d %(type)s" msgstr "%(number)d %(type)s" -#: utils/timesince.py:54 +#: utils/timesince.py:56 #, python-format msgid ", %(number)d %(type)s" msgstr ", %(number)d %(type)s" @@ -4372,6 +4459,11 @@ msgstr "Se actualizó con éxito el %(verbose_name)s." msgid "The %(verbose_name)s was deleted." msgstr "El/La %(verbose_name)s ha sido borrado." +#~ msgid "verbose_name" +#~ msgid_plural "verbose_name_plural" +#~ msgstr[0] "verbose_name" +#~ msgstr[1] "verbose_name_plural" + #~ msgid "DATE_WITH_TIME_FULL" #~ msgstr "j M Y P" @@ -4411,9 +4503,6 @@ msgstr "El/La %(verbose_name)s ha sido borrado." #~ msgid "is valid rating" #~ msgstr "puntuación válida" -#~ msgid "comments" -#~ msgstr "comentarios" - #~ msgid "Content object" #~ msgstr "Objeto contenido" @@ -4610,9 +4699,6 @@ msgstr "El/La %(verbose_name)s ha sido borrado." #~ msgid "Please enter both fields or leave them both empty." #~ msgstr "Por favor, rellene ambos campos o deje ambos vacíos." -#~ msgid "This field must be given if %(field)s is %(value)s" -#~ msgstr "Se debe proporcionar este campo si %(field)s es %(value)s" - #~ msgid "This field must be given if %(field)s is not %(value)s" #~ msgstr "Se debe proporcionar este campo si %(field)s no es %(value)s" diff --git a/django/conf/urls/defaults.py b/django/conf/urls/defaults.py index 26cdd3e1ff..3ab8bab3ec 100644 --- a/django/conf/urls/defaults.py +++ b/django/conf/urls/defaults.py @@ -6,7 +6,16 @@ __all__ = ['handler404', 'handler500', 'include', 'patterns', 'url'] handler404 = 'django.views.defaults.page_not_found' handler500 = 'django.views.defaults.server_error' -include = lambda urlconf_module: [urlconf_module] +def include(arg, namespace=None, app_name=None): + if isinstance(arg, tuple): + # callable returning a namespace hint + if namespace: + raise ImproperlyConfigured('Cannot override the namespace for a dynamic module that provides a namespace') + urlconf_module, app_name, namespace = arg + else: + # No namespace hint - use manually provided namespace + urlconf_module = arg + return (urlconf_module, app_name, namespace) def patterns(prefix, *args): pattern_list = [] @@ -19,9 +28,10 @@ def patterns(prefix, *args): return pattern_list def url(regex, view, kwargs=None, name=None, prefix=''): - if type(view) == list: + if isinstance(view, (list,tuple)): # For include(...) processing. - return RegexURLResolver(regex, view[0], kwargs) + urlconf_module, app_name, namespace = view + return RegexURLResolver(regex, urlconf_module, kwargs, app_name=app_name, namespace=namespace) else: if isinstance(view, basestring): if not view: diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 8297eca74e..31a28ccf0b 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -226,24 +226,24 @@ class ModelAdmin(BaseModelAdmin): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) - info = self.admin_site.name, self.model._meta.app_label, self.model._meta.module_name + info = self.model._meta.app_label, self.model._meta.module_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), - name='%sadmin_%s_%s_changelist' % info), + name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), - name='%sadmin_%s_%s_add' % info), + name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), - name='%sadmin_%s_%s_history' % info), + name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), - name='%sadmin_%s_%s_delete' % info), + name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), - name='%sadmin_%s_%s_change' % info), + name='%s_%s_change' % info), ) return urlpatterns @@ -582,11 +582,12 @@ class ModelAdmin(BaseModelAdmin): 'save_on_top': self.save_on_top, 'root_path': self.admin_site.root_path, }) + context_instance = template.RequestContext(request, current_app=self.admin_site.name) return render_to_response(self.change_form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.object_name.lower()), "admin/%s/change_form.html" % app_label, "admin/change_form.html" - ], context, context_instance=template.RequestContext(request)) + ], context, context_instance=context_instance) def response_add(self, request, obj, post_url_continue='../%s/'): """ @@ -977,11 +978,12 @@ class ModelAdmin(BaseModelAdmin): 'actions_on_bottom': self.actions_on_bottom, } context.update(extra_context or {}) + context_instance = template.RequestContext(request, current_app=self.admin_site.name) return render_to_response(self.change_list_template or [ 'admin/%s/%s/change_list.html' % (app_label, opts.object_name.lower()), 'admin/%s/change_list.html' % app_label, 'admin/change_list.html' - ], context, context_instance=template.RequestContext(request)) + ], context, context_instance=context_instance) def delete_view(self, request, object_id, extra_context=None): "The 'delete' admin view for this model." @@ -1032,11 +1034,12 @@ class ModelAdmin(BaseModelAdmin): "app_label": app_label, } context.update(extra_context or {}) + context_instance = template.RequestContext(request, current_app=self.admin_site.name) return render_to_response(self.delete_confirmation_template or [ "admin/%s/%s/delete_confirmation.html" % (app_label, opts.object_name.lower()), "admin/%s/delete_confirmation.html" % app_label, "admin/delete_confirmation.html" - ], context, context_instance=template.RequestContext(request)) + ], context, context_instance=context_instance) def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." @@ -1059,11 +1062,12 @@ class ModelAdmin(BaseModelAdmin): 'app_label': app_label, } context.update(extra_context or {}) + context_instance = template.RequestContext(request, current_app=self.admin_site.name) return render_to_response(self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.object_name.lower()), "admin/%s/object_history.html" % app_label, "admin/object_history.html" - ], context, context_instance=template.RequestContext(request)) + ], context, context_instance=context_instance) # # DEPRECATED methods. diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py index 6e9ef1161f..abcff14cd1 100644 --- a/django/contrib/admin/sites.py +++ b/django/contrib/admin/sites.py @@ -5,6 +5,7 @@ from django.contrib.admin import actions from django.contrib.auth import authenticate, login from django.db.models.base import ModelBase from django.core.exceptions import ImproperlyConfigured +from django.core.urlresolvers import reverse from django.shortcuts import render_to_response from django.utils.functional import update_wrapper from django.utils.safestring import mark_safe @@ -38,17 +39,14 @@ class AdminSite(object): login_template = None app_index_template = None - def __init__(self, name=None): + def __init__(self, name=None, app_name='admin'): self._registry = {} # model_class class -> admin_class instance - # TODO Root path is used to calculate urls under the old root() method - # in order to maintain backwards compatibility we are leaving that in - # so root_path isn't needed, not sure what to do about this. - self.root_path = 'admin/' + self.root_path = None if name is None: - name = '' + self.name = 'admin' else: - name += '_' - self.name = name + self.name = name + self.app_name = app_name self._actions = {'delete_selected': actions.delete_selected} self._global_actions = self._actions.copy() @@ -114,20 +112,20 @@ class AdminSite(object): name = name or action.__name__ self._actions[name] = action self._global_actions[name] = action - + def disable_action(self, name): """ Disable a globally-registered action. Raises KeyError for invalid names. """ del self._actions[name] - + def get_action(self, name): """ Explicitally get a registered global action wheather it's enabled or not. Raises KeyError for invalid names. """ return self._global_actions[name] - + def actions(self): """ Get all the enabled actions as an iterable of (name, func). @@ -159,9 +157,9 @@ class AdminSite(object): if 'django.core.context_processors.auth' not in settings.TEMPLATE_CONTEXT_PROCESSORS: raise ImproperlyConfigured("Put 'django.core.context_processors.auth' in your TEMPLATE_CONTEXT_PROCESSORS setting in order to use the admin application.") - def admin_view(self, view): + def admin_view(self, view, cacheable=False): """ - Decorator to create an "admin view attached to this ``AdminSite``. This + Decorator to create an admin view attached to this ``AdminSite``. This wraps the view and provides permission checking by calling ``self.has_permission``. @@ -177,43 +175,49 @@ class AdminSite(object): url(r'^my_view/$', self.admin_view(some_view)) ) return urls + + By default, admin_views are marked non-cacheable using the + ``never_cache`` decorator. If the view can be safely cached, set + cacheable=True. """ def inner(request, *args, **kwargs): if not self.has_permission(request): return self.login(request) return view(request, *args, **kwargs) + if not cacheable: + inner = never_cache(inner) return update_wrapper(inner, view) def get_urls(self): from django.conf.urls.defaults import patterns, url, include - def wrap(view): + def wrap(view, cacheable=False): def wrapper(*args, **kwargs): - return self.admin_view(view)(*args, **kwargs) + return self.admin_view(view, cacheable)(*args, **kwargs) return update_wrapper(wrapper, view) # Admin-site-wide views. urlpatterns = patterns('', url(r'^$', wrap(self.index), - name='%sadmin_index' % self.name), + name='index'), url(r'^logout/$', wrap(self.logout), - name='%sadmin_logout'), + name='logout'), url(r'^password_change/$', - wrap(self.password_change), - name='%sadmin_password_change' % self.name), + wrap(self.password_change, cacheable=True), + name='password_change'), url(r'^password_change/done/$', - wrap(self.password_change_done), - name='%sadmin_password_change_done' % self.name), + wrap(self.password_change_done, cacheable=True), + name='password_change_done'), url(r'^jsi18n/$', - wrap(self.i18n_javascript), - name='%sadmin_jsi18n' % self.name), + wrap(self.i18n_javascript, cacheable=True), + name='jsi18n'), url(r'^r/(?P\d+)/(?P.+)/$', 'django.views.defaults.shortcut'), url(r'^(?P\w+)/$', wrap(self.app_index), - name='%sadmin_app_list' % self.name), + name='app_list') ) # Add in each model's views. @@ -225,7 +229,7 @@ class AdminSite(object): return urlpatterns def urls(self): - return self.get_urls() + return self.get_urls(), self.app_name, self.name urls = property(urls) def password_change(self, request): @@ -233,8 +237,11 @@ class AdminSite(object): Handles the "change password" task -- both form display and validation. """ from django.contrib.auth.views import password_change - return password_change(request, - post_change_redirect='%spassword_change/done/' % self.root_path) + if self.root_path is not None: + url = '%spassword_change/done/' % self.root_path + else: + url = reverse('admin:password_change_done', current_app=self.name) + return password_change(request, post_change_redirect=url) def password_change_done(self, request): """ @@ -362,8 +369,9 @@ class AdminSite(object): 'root_path': self.root_path, } context.update(extra_context or {}) + context_instance = template.RequestContext(request, current_app=self.name) return render_to_response(self.index_template or 'admin/index.html', context, - context_instance=template.RequestContext(request) + context_instance=context_instance ) index = never_cache(index) @@ -376,8 +384,9 @@ class AdminSite(object): 'root_path': self.root_path, } context.update(extra_context or {}) + context_instance = template.RequestContext(request, current_app=self.name) return render_to_response(self.login_template or 'admin/login.html', context, - context_instance=template.RequestContext(request) + context_instance=context_instance ) def app_index(self, request, app_label, extra_context=None): @@ -419,9 +428,10 @@ class AdminSite(object): 'root_path': self.root_path, } context.update(extra_context or {}) + context_instance = template.RequestContext(request, current_app=self.name) return render_to_response(self.app_index_template or ('admin/%s/app_index.html' % app_label, 'admin/app_index.html'), context, - context_instance=template.RequestContext(request) + context_instance=context_instance ) def root(self, request, url): diff --git a/django/contrib/admin/templates/admin/base.html b/django/contrib/admin/templates/admin/base.html index 8cab43963a..95257285eb 100644 --- a/django/contrib/admin/templates/admin/base.html +++ b/django/contrib/admin/templates/admin/base.html @@ -23,7 +23,30 @@ {% block branding %}{% endblock %} {% if user.is_authenticated and user.is_staff %} -

{% trans 'Welcome,' %} {% firstof user.first_name user.username %}. {% block userlinks %}{% url django-admindocs-docroot as docsroot %}{% if docsroot %}{% trans 'Documentation' %} / {% endif %}{% trans 'Change password' %} / {% trans 'Log out' %}{% endblock %}
+
+ {% trans 'Welcome,' %} + {% firstof user.first_name user.username %}. + {% block userlinks %} + {% url django-admindocs-docroot as docsroot %} + {% if docsroot %} + {% trans 'Documentation' %} / + {% endif %} + {% url admin:password_change as password_change_url %} + {% if password_change_url %} + + {% else %} + + {% endif %} + {% trans 'Change password' %} / + {% url admin:logout as logout_url %} + {% if logout_url %} + + {% else %} + + {% endif %} + {% trans 'Log out' %} + {% endblock %} +
{% endif %} {% block nav-global %}{% endblock %} diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index 7ae5e647db..1a081bc293 100644 --- a/django/contrib/admin/widgets.py +++ b/django/contrib/admin/widgets.py @@ -125,7 +125,7 @@ class ForeignKeyRawIdWidget(forms.TextInput): if value: output.append(self.label_for_value(value)) return mark_safe(u''.join(output)) - + def base_url_parameters(self): params = {} if self.rel.limit_choices_to: @@ -137,14 +137,14 @@ class ForeignKeyRawIdWidget(forms.TextInput): v = str(v) items.append((k, v)) params.update(dict(items)) - return params - + return params + def url_parameters(self): from django.contrib.admin.views.main import TO_FIELD_VAR params = self.base_url_parameters() params.update({TO_FIELD_VAR: self.rel.get_related_field().name}) return params - + def label_for_value(self, value): key = self.rel.get_related_field().name obj = self.rel.to._default_manager.get(**{key: value}) @@ -165,10 +165,10 @@ class ManyToManyRawIdWidget(ForeignKeyRawIdWidget): else: value = '' return super(ManyToManyRawIdWidget, self).render(name, value, attrs) - + def url_parameters(self): return self.base_url_parameters() - + def label_for_value(self, value): return '' @@ -222,8 +222,7 @@ class RelatedFieldWidgetWrapper(forms.Widget): rel_to = self.rel.to info = (rel_to._meta.app_label, rel_to._meta.object_name.lower()) try: - related_info = (self.admin_site.name,) + info - related_url = reverse('%sadmin_%s_%s_add' % related_info) + related_url = reverse('admin:%s_%s_add' % info, current_app=self.admin_site.name) except NoReverseMatch: related_url = '../../../%s/%s/add/' % info self.widget.choices = self.choices diff --git a/django/contrib/admindocs/templates/admin_doc/index.html b/django/contrib/admindocs/templates/admin_doc/index.html index 242fc7339a..a8b21c330d 100644 --- a/django/contrib/admindocs/templates/admin_doc/index.html +++ b/django/contrib/admindocs/templates/admin_doc/index.html @@ -1,6 +1,6 @@ {% extends "admin/base_site.html" %} {% load i18n %} -{% block breadcrumbs %}{% endblock %} +{% block breadcrumbs %}{% endblock %} {% block title %}Documentation{% endblock %} {% block content %} diff --git a/django/contrib/admindocs/views.py b/django/contrib/admindocs/views.py index 4f22fe0a0a..571f393ff8 100644 --- a/django/contrib/admindocs/views.py +++ b/django/contrib/admindocs/views.py @@ -22,11 +22,14 @@ class GenericSite(object): name = 'my site' def get_root_path(): - from django.contrib import admin try: - return urlresolvers.reverse(admin.site.root, args=['']) + return urlresolvers.reverse('admin:index') except urlresolvers.NoReverseMatch: - return getattr(settings, "ADMIN_SITE_ROOT_URL", "/admin/") + from django.contrib import admin + try: + return urlresolvers.reverse(admin.site.root, args=['']) + except urlresolvers.NoReverseMatch: + return getattr(settings, "ADMIN_SITE_ROOT_URL", "/admin/") def doc_index(request): if not utils.docutils_is_available: @@ -179,7 +182,7 @@ model_index = staff_member_required(model_index) def model_detail(request, app_label, model_name): if not utils.docutils_is_available: return missing_docutils_page(request) - + # Get the model class. try: app_mod = models.get_app(app_label) diff --git a/django/contrib/gis/db/models/manager.py b/django/contrib/gis/db/models/manager.py index 2bfda990ff..eac66f4a83 100644 --- a/django/contrib/gis/db/models/manager.py +++ b/django/contrib/gis/db/models/manager.py @@ -19,6 +19,9 @@ class GeoManager(Manager): def centroid(self, *args, **kwargs): return self.get_query_set().centroid(*args, **kwargs) + def collect(self, *args, **kwargs): + return self.get_query_set().collect(*args, **kwargs) + def difference(self, *args, **kwargs): return self.get_query_set().difference(*args, **kwargs) diff --git a/django/contrib/gis/db/models/query.py b/django/contrib/gis/db/models/query.py index 3d31f73c29..d055260a58 100644 --- a/django/contrib/gis/db/models/query.py +++ b/django/contrib/gis/db/models/query.py @@ -62,6 +62,14 @@ class GeoQuerySet(QuerySet): """ return self._geom_attribute('centroid', **kwargs) + def collect(self, **kwargs): + """ + Performs an aggregate collect operation on the given geometry field. + This is analagous to a union operation, but much faster because + boundaries are not dissolved. + """ + return self._spatial_aggregate(aggregates.Collect, **kwargs) + def difference(self, geom, **kwargs): """ Returns the spatial difference of the geographic field in a `difference` diff --git a/django/contrib/gis/db/models/sql/query.py b/django/contrib/gis/db/models/sql/query.py index 5df15a88b1..094fc5815f 100644 --- a/django/contrib/gis/db/models/sql/query.py +++ b/django/contrib/gis/db/models/sql/query.py @@ -13,7 +13,9 @@ from django.contrib.gis.measure import Area, Distance ALL_TERMS = sql.constants.QUERY_TERMS.copy() ALL_TERMS.update(SpatialBackend.gis_terms) +# Pulling out other needed constants/routines to avoid attribute lookups. TABLE_NAME = sql.constants.TABLE_NAME +get_proxied_model = sql.query.get_proxied_model class GeoQuery(sql.Query): """ @@ -153,7 +155,9 @@ class GeoQuery(sql.Query): opts = self.model._meta aliases = set() only_load = self.deferred_to_columns() - proxied_model = opts.proxy and opts.proxy_for_model or 0 + # Skip all proxy to the root proxied model + proxied_model = get_proxied_model(opts) + if start_alias: seen = {None: start_alias} for field, model in opts.get_fields_with_model(): @@ -205,6 +209,10 @@ class GeoQuery(sql.Query): """ values = [] aliases = self.extra_select.keys() + if self.aggregates: + # If we have an aggregate annotation, must extend the aliases + # so their corresponding row values are included. + aliases.extend([None for i in xrange(len(self.aggregates))]) # Have to set a starting row number offset that is used for # determining the correct starting row index -- needed for diff --git a/django/contrib/gis/gdal/prototypes/generation.py b/django/contrib/gis/gdal/prototypes/generation.py index bba715d67c..1303532372 100644 --- a/django/contrib/gis/gdal/prototypes/generation.py +++ b/django/contrib/gis/gdal/prototypes/generation.py @@ -8,6 +8,9 @@ from django.contrib.gis.gdal.prototypes.errcheck import \ check_arg_errcode, check_errcode, check_geom, check_geom_offset, \ check_pointer, check_srs, check_str_arg, check_string, check_const_string +class gdal_char_p(c_char_p): + pass + def double_output(func, argtypes, errcheck=False, strarg=False): "Generates a ctypes function that returns a double value." func.argtypes = argtypes @@ -77,9 +80,9 @@ def string_output(func, argtypes, offset=-1, str_result=False): """ func.argtypes = argtypes if str_result: - # String is the result, don't explicitly define - # the argument type so we can get the pointer. - pass + # Use subclass of c_char_p so the error checking routine + # can free the memory at the pointer's address. + func.restype = gdal_char_p else: # Error code is returned func.restype = c_int diff --git a/django/contrib/gis/geos/prototypes/topology.py b/django/contrib/gis/geos/prototypes/topology.py index 633340901b..65c26f9f37 100644 --- a/django/contrib/gis/geos/prototypes/topology.py +++ b/django/contrib/gis/geos/prototypes/topology.py @@ -10,6 +10,7 @@ __all__ = ['geos_boundary', 'geos_buffer', 'geos_centroid', 'geos_convexhull', from ctypes import c_char_p, c_double, c_int from django.contrib.gis.geos.libgeos import lgeos, GEOM_PTR, GEOS_PREPARE from django.contrib.gis.geos.prototypes.errcheck import check_geom, check_string +from django.contrib.gis.geos.prototypes.geom import geos_char_p def topology(func, *args): "For GEOS unary topology functions." @@ -38,6 +39,7 @@ geos_union = topology(lgeos.GEOSUnion, GEOM_PTR) # GEOSRelate returns a string, not a geometry. geos_relate = lgeos.GEOSRelate geos_relate.argtypes = [GEOM_PTR, GEOM_PTR] +geos_relate.restype = geos_char_p geos_relate.errcheck = check_string # Routines only in GEOS 3.1+ diff --git a/django/contrib/gis/tests/relatedapp/tests.py b/django/contrib/gis/tests/relatedapp/tests.py index 502a3c0be9..60528f177c 100644 --- a/django/contrib/gis/tests/relatedapp/tests.py +++ b/django/contrib/gis/tests/relatedapp/tests.py @@ -1,7 +1,7 @@ import os, unittest from django.contrib.gis.geos import * from django.contrib.gis.db.backend import SpatialBackend -from django.contrib.gis.db.models import Count, Extent, F, Union +from django.contrib.gis.db.models import Collect, Count, Extent, F, Union from django.contrib.gis.tests.utils import no_mysql, no_oracle, no_spatialite from django.conf import settings from models import City, Location, DirectoryEntry, Parcel, Book, Author @@ -231,8 +231,12 @@ class RelatedGeoModelTest(unittest.TestCase): q = pickle.loads(q_str) self.assertEqual(GeoQuery, q.__class__) - def test12_count(self): - "Testing `Count` aggregate use with the `GeoManager`. See #11087." + # TODO: fix on Oracle -- get the following error because the SQL is ordered + # by a geometry object, which Oracle apparently doesn't like: + # ORA-22901: cannot compare nested table or VARRAY or LOB attributes of an object type + @no_oracle + def test12a_count(self): + "Testing `Count` aggregate use with the `GeoManager` on geo-fields." # Creating a new City, 'Fort Worth', that uses the same location # as Dallas. dallas = City.objects.get(name='Dallas') @@ -242,6 +246,8 @@ class RelatedGeoModelTest(unittest.TestCase): loc = Location.objects.annotate(num_cities=Count('city')).get(id=dallas.location.id) self.assertEqual(2, loc.num_cities) + def test12b_count(self): + "Testing `Count` aggregate use with the `GeoManager` on non geo-fields. See #11087." # Creating some data for the Book/Author non-geo models that # use GeoManager. See #11087. tp = Author.objects.create(name='Trevor Paglen') @@ -250,13 +256,19 @@ class RelatedGeoModelTest(unittest.TestCase): Book.objects.create(title='Blank Spots on the Map', author=tp) wp = Author.objects.create(name='William Patry') Book.objects.create(title='Patry on Copyright', author=wp) - + # Should only be one author (Trevor Paglen) returned by this query, and - # the annotation should have 3 for the number of books. + # the annotation should have 3 for the number of books. Also testing + # with a `GeoValuesQuerySet` (see #11489). qs = Author.objects.annotate(num_books=Count('books')).filter(num_books__gt=1) + vqs = Author.objects.values('name').annotate(num_books=Count('books')).filter(num_books__gt=1) self.assertEqual(1, len(qs)) self.assertEqual(3, qs[0].num_books) + self.assertEqual(1, len(vqs)) + self.assertEqual(3, vqs[0]['num_books']) + # TODO: The phantom model does appear on Oracle. + @no_oracle def test13_select_related_null_fk(self): "Testing `select_related` on a nullable ForeignKey via `GeoManager`. See #11381." no_author = Book.objects.create(title='Without Author') @@ -264,6 +276,26 @@ class RelatedGeoModelTest(unittest.TestCase): # Should be `None`, and not a 'dummy' model. self.assertEqual(None, b.author) + @no_mysql + @no_oracle + @no_spatialite + def test14_collect(self): + "Testing the `collect` GeoQuerySet method and `Collect` aggregate." + # Reference query: + # SELECT AsText(ST_Collect("relatedapp_location"."point")) FROM "relatedapp_city" LEFT OUTER JOIN + # "relatedapp_location" ON ("relatedapp_city"."location_id" = "relatedapp_location"."id") + # WHERE "relatedapp_city"."state" = 'TX'; + ref_geom = fromstr('MULTIPOINT(-97.516111 33.058333,-96.801611 32.782057,-95.363151 29.763374,-96.801611 32.782057)') + + c1 = City.objects.filter(state='TX').collect(field_name='location__point') + c2 = City.objects.filter(state='TX').aggregate(Collect('location__point'))['location__point__collect'] + + for coll in (c1, c2): + # Even though Dallas and Ft. Worth share same point, Collect doesn't + # consolidate -- that's why 4 points in MultiPoint. + self.assertEqual(4, len(coll)) + self.assertEqual(ref_geom, coll) + # TODO: Related tests for KML, GML, and distance lookups. def suite(): diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py index 10e97bbcd5..4f9eb982e2 100644 --- a/django/core/urlresolvers.py +++ b/django/core/urlresolvers.py @@ -139,7 +139,7 @@ class RegexURLPattern(object): callback = property(_get_callback) class RegexURLResolver(object): - def __init__(self, regex, urlconf_name, default_kwargs=None): + def __init__(self, regex, urlconf_name, default_kwargs=None, app_name=None, namespace=None): # regex is a string representing a regular expression. # urlconf_name is a string representing the module containing URLconfs. self.regex = re.compile(regex, re.UNICODE) @@ -148,19 +148,29 @@ class RegexURLResolver(object): self._urlconf_module = self.urlconf_name self.callback = None self.default_kwargs = default_kwargs or {} - self._reverse_dict = MultiValueDict() + self.namespace = namespace + self.app_name = app_name + self._reverse_dict = None + self._namespace_dict = None + self._app_dict = None def __repr__(self): - return '<%s %s %s>' % (self.__class__.__name__, self.urlconf_name, self.regex.pattern) + return '<%s %s (%s:%s) %s>' % (self.__class__.__name__, self.urlconf_name, self.app_name, self.namespace, self.regex.pattern) - def _get_reverse_dict(self): - if not self._reverse_dict: - lookups = MultiValueDict() - for pattern in reversed(self.url_patterns): - p_pattern = pattern.regex.pattern - if p_pattern.startswith('^'): - p_pattern = p_pattern[1:] - if isinstance(pattern, RegexURLResolver): + def _populate(self): + lookups = MultiValueDict() + namespaces = {} + apps = {} + for pattern in reversed(self.url_patterns): + p_pattern = pattern.regex.pattern + if p_pattern.startswith('^'): + p_pattern = p_pattern[1:] + if isinstance(pattern, RegexURLResolver): + if pattern.namespace: + namespaces[pattern.namespace] = (p_pattern, pattern) + if pattern.app_name: + apps.setdefault(pattern.app_name, []).append(pattern.namespace) + else: parent = normalize(pattern.regex.pattern) for name in pattern.reverse_dict: for matches, pat in pattern.reverse_dict.getlist(name): @@ -168,14 +178,36 @@ class RegexURLResolver(object): for piece, p_args in parent: new_matches.extend([(piece + suffix, p_args + args) for (suffix, args) in matches]) lookups.appendlist(name, (new_matches, p_pattern + pat)) - else: - bits = normalize(p_pattern) - lookups.appendlist(pattern.callback, (bits, p_pattern)) - lookups.appendlist(pattern.name, (bits, p_pattern)) - self._reverse_dict = lookups + for namespace, (prefix, sub_pattern) in pattern.namespace_dict.items(): + namespaces[namespace] = (p_pattern + prefix, sub_pattern) + for app_name, namespace_list in pattern.app_dict.items(): + apps.setdefault(app_name, []).extend(namespace_list) + else: + bits = normalize(p_pattern) + lookups.appendlist(pattern.callback, (bits, p_pattern)) + lookups.appendlist(pattern.name, (bits, p_pattern)) + self._reverse_dict = lookups + self._namespace_dict = namespaces + self._app_dict = apps + + def _get_reverse_dict(self): + if self._reverse_dict is None: + self._populate() return self._reverse_dict reverse_dict = property(_get_reverse_dict) + def _get_namespace_dict(self): + if self._namespace_dict is None: + self._populate() + return self._namespace_dict + namespace_dict = property(_get_namespace_dict) + + def _get_app_dict(self): + if self._app_dict is None: + self._populate() + return self._app_dict + app_dict = property(_get_app_dict) + def resolve(self, path): tried = [] match = self.regex.search(path) @@ -261,12 +293,51 @@ class RegexURLResolver(object): def resolve(path, urlconf=None): return get_resolver(urlconf).resolve(path) -def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None): +def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, current_app=None): + resolver = get_resolver(urlconf) args = args or [] kwargs = kwargs or {} + if prefix is None: prefix = get_script_prefix() - return iri_to_uri(u'%s%s' % (prefix, get_resolver(urlconf).reverse(viewname, + + if not isinstance(viewname, basestring): + view = viewname + else: + parts = viewname.split(':') + parts.reverse() + view = parts[0] + path = parts[1:] + + resolved_path = [] + while path: + ns = path.pop() + + # Lookup the name to see if it could be an app identifier + try: + app_list = resolver.app_dict[ns] + # Yes! Path part matches an app in the current Resolver + if current_app and current_app in app_list: + # If we are reversing for a particular app, use that namespace + ns = current_app + elif ns not in app_list: + # The name isn't shared by one of the instances (i.e., the default) + # so just pick the first instance as the default. + ns = app_list[0] + except KeyError: + pass + + try: + extra, resolver = resolver.namespace_dict[ns] + resolved_path.append(ns) + prefix = prefix + extra + except KeyError, key: + if resolved_path: + raise NoReverseMatch("%s is not a registered namespace inside '%s'" % (key, ':'.join(resolved_path))) + else: + raise NoReverseMatch("%s is not a registered namespace" % key) + + return iri_to_uri(u'%s%s' % (prefix, resolver.reverse(view, *args, **kwargs))) def clear_url_caches(): diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index 8f96049cc4..7d85979294 100644 --- a/django/db/backends/oracle/base.py +++ b/django/db/backends/oracle/base.py @@ -217,12 +217,13 @@ WHEN (new.%(col_name)s IS NULL) # continue to loop break for f in model._meta.many_to_many: - table_name = self.quote_name(f.m2m_db_table()) - sequence_name = get_sequence_name(f.m2m_db_table()) - column_name = self.quote_name('id') - output.append(query % {'sequence': sequence_name, - 'table': table_name, - 'column': column_name}) + if not f.rel.through: + table_name = self.quote_name(f.m2m_db_table()) + sequence_name = get_sequence_name(f.m2m_db_table()) + column_name = self.quote_name('id') + output.append(query % {'sequence': sequence_name, + 'table': table_name, + 'column': column_name}) return output def start_transaction_sql(self): diff --git a/django/db/backends/postgresql/operations.py b/django/db/backends/postgresql/operations.py index ee74be1624..331156ee11 100644 --- a/django/db/backends/postgresql/operations.py +++ b/django/db/backends/postgresql/operations.py @@ -121,14 +121,15 @@ class DatabaseOperations(BaseDatabaseOperations): style.SQL_TABLE(qn(model._meta.db_table)))) break # Only one AutoField is allowed per model, so don't bother continuing. for f in model._meta.many_to_many: - output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ - (style.SQL_KEYWORD('SELECT'), - style.SQL_FIELD(qn('%s_id_seq' % f.m2m_db_table())), - style.SQL_FIELD(qn('id')), - style.SQL_FIELD(qn('id')), - style.SQL_KEYWORD('IS NOT'), - style.SQL_KEYWORD('FROM'), - style.SQL_TABLE(qn(f.m2m_db_table())))) + if not f.rel.through: + output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ + (style.SQL_KEYWORD('SELECT'), + style.SQL_FIELD(qn('%s_id_seq' % f.m2m_db_table())), + style.SQL_FIELD(qn('id')), + style.SQL_FIELD(qn('id')), + style.SQL_KEYWORD('IS NOT'), + style.SQL_KEYWORD('FROM'), + style.SQL_TABLE(qn(f.m2m_db_table())))) return output def savepoint_create_sql(self, sid): diff --git a/django/template/context.py b/django/template/context.py index 0ccb5faecf..1c43387468 100644 --- a/django/template/context.py +++ b/django/template/context.py @@ -9,10 +9,11 @@ class ContextPopException(Exception): class Context(object): "A stack container for variable context" - def __init__(self, dict_=None, autoescape=True): + def __init__(self, dict_=None, autoescape=True, current_app=None): dict_ = dict_ or {} self.dicts = [dict_] self.autoescape = autoescape + self.current_app = current_app def __repr__(self): return repr(self.dicts) @@ -96,8 +97,8 @@ class RequestContext(Context): Additional processors can be specified as a list of callables using the "processors" keyword argument. """ - def __init__(self, request, dict=None, processors=None): - Context.__init__(self, dict) + def __init__(self, request, dict=None, processors=None, current_app=None): + Context.__init__(self, dict, current_app=current_app) if processors is None: processors = () else: diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index 7d91cd6415..de746997ab 100644 --- a/django/template/defaulttags.py +++ b/django/template/defaulttags.py @@ -367,17 +367,17 @@ class URLNode(Node): # {% url ... as var %} construct in which cause return nothing. url = '' try: - url = reverse(self.view_name, args=args, kwargs=kwargs) + url = reverse(self.view_name, args=args, kwargs=kwargs, current_app=context.current_app) except NoReverseMatch, e: if settings.SETTINGS_MODULE: project_name = settings.SETTINGS_MODULE.split('.')[0] try: url = reverse(project_name + '.' + self.view_name, - args=args, kwargs=kwargs) + args=args, kwargs=kwargs, current_app=context.current_app) except NoReverseMatch: if self.asvar is None: # Re-raise the original exception, not the one with - # the path relative to the project. This makes a + # the path relative to the project. This makes a # better error message. raise e else: diff --git a/docs/howto/custom-model-fields.txt b/docs/howto/custom-model-fields.txt index 709ea49b87..9f798f14d5 100644 --- a/docs/howto/custom-model-fields.txt +++ b/docs/howto/custom-model-fields.txt @@ -464,7 +464,7 @@ should raise either a ``ValueError`` if the ``value`` is of the wrong sort (a list when you were expecting an object, for example) or a ``TypeError`` if your field does not support that type of lookup. For many fields, you can get by with handling the lookup types that need special handling for your field -and pass the rest of the :meth:`get_db_prep_lookup` method of the parent class. +and pass the rest to the :meth:`get_db_prep_lookup` method of the parent class. If you needed to implement ``get_db_prep_save()``, you will usually need to implement ``get_db_prep_lookup()``. If you don't, ``get_db_prep_value`` will be diff --git a/docs/howto/deployment/modwsgi.txt b/docs/howto/deployment/modwsgi.txt index 902e312551..308ef2b4d2 100644 --- a/docs/howto/deployment/modwsgi.txt +++ b/docs/howto/deployment/modwsgi.txt @@ -1,69 +1,118 @@ -.. _howto-deployment-modwsgi: - -========================================== -How to use Django with Apache and mod_wsgi -========================================== - -Deploying Django with Apache_ and `mod_wsgi`_ is the recommended way to get -Django into production. - -.. _Apache: http://httpd.apache.org/ -.. _mod_wsgi: http://code.google.com/p/modwsgi/ - -mod_wsgi is an Apache module which can be used to host any Python application -which supports the `Python WSGI interface`_, including Django. Django will work -with any version of Apache which supports mod_wsgi. - -.. _python wsgi interface: http://www.python.org/dev/peps/pep-0333/ - -The `official mod_wsgi documentation`_ is fantastic; it's your source for all -the details about how to use mod_wsgi. You'll probably want to start with the -`installation and configuration documentation`_. - -.. _official mod_wsgi documentation: http://code.google.com/p/modwsgi/ -.. _installation and configuration documentation: http://code.google.com/p/modwsgi/wiki/InstallationInstructions - -Basic Configuration -=================== - -Once you've got mod_wsgi installed and activated, edit your ``httpd.conf`` file -and add:: - - WSGIScriptAlias / /path/to/mysite/apache/django.wsgi - -The first bit above is the url you want to be serving your application at (``/`` -indicates the root url), and the second is the location of a "WSGI file" -- see -below -- on your system, usually inside of your project. This tells Apache -to serve any request below the given URL using the WSGI application defined by that file. - -Next we'll need to actually create this WSGI application, so create the file -mentioned in the second part of ``WSGIScriptAlias`` and add:: - - import os - import sys - - os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' - - import django.core.handlers.wsgi - application = django.core.handlers.wsgi.WSGIHandler() - -If your project is not on your ``PYTHONPATH`` by default you can add:: - - sys.path.append('/usr/local/django') - -just above the final ``import`` line to place your project on the path. Remember to -replace 'mysite.settings' with your correct settings file, and '/usr/local/django' -with your own project's location. - -See the :ref:`Apache/mod_python documentation` for -directions on serving static media, and the `mod_wsgi documentation`_ for an -explanation of other directives and configuration options you can use. - -Details -======= - -For more details, see the `mod_wsgi documentation`_, which explains the above in -more detail, and walks through all the various options you've got when deploying -under mod_wsgi. - -.. _mod_wsgi documentation: http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango +.. _howto-deployment-modwsgi: + +========================================== +How to use Django with Apache and mod_wsgi +========================================== + +Deploying Django with Apache_ and `mod_wsgi`_ is the recommended way to get +Django into production. + +.. _Apache: http://httpd.apache.org/ +.. _mod_wsgi: http://code.google.com/p/modwsgi/ + +mod_wsgi is an Apache module which can be used to host any Python application +which supports the `Python WSGI interface`_, including Django. Django will work +with any version of Apache which supports mod_wsgi. + +.. _python wsgi interface: http://www.python.org/dev/peps/pep-0333/ + +The `official mod_wsgi documentation`_ is fantastic; it's your source for all +the details about how to use mod_wsgi. You'll probably want to start with the +`installation and configuration documentation`_. + +.. _official mod_wsgi documentation: http://code.google.com/p/modwsgi/ +.. _installation and configuration documentation: http://code.google.com/p/modwsgi/wiki/InstallationInstructions + +Basic Configuration +=================== + +Once you've got mod_wsgi installed and activated, edit your ``httpd.conf`` file +and add:: + + WSGIScriptAlias / /path/to/mysite/apache/django.wsgi + +The first bit above is the url you want to be serving your application at (``/`` +indicates the root url), and the second is the location of a "WSGI file" -- see +below -- on your system, usually inside of your project. This tells Apache +to serve any request below the given URL using the WSGI application defined by that file. + +Next we'll need to actually create this WSGI application, so create the file +mentioned in the second part of ``WSGIScriptAlias`` and add:: + + import os + import sys + + os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' + + import django.core.handlers.wsgi + application = django.core.handlers.wsgi.WSGIHandler() + +If your project is not on your ``PYTHONPATH`` by default you can add:: + + sys.path.append('/usr/local/django') + +just above the final ``import`` line to place your project on the path. Remember to +replace 'mysite.settings' with your correct settings file, and '/usr/local/django' +with your own project's location. + +Serving media files +=================== + +Django doesn't serve media files itself; it leaves that job to whichever Web +server you choose. + +We recommend using a separate Web server -- i.e., one that's not also running +Django -- for serving media. Here are some good choices: + + * lighttpd_ + * Nginx_ + * TUX_ + * A stripped-down version of Apache_ + * Cherokee_ + +If, however, you have no option but to serve media files on the same Apache +``VirtualHost`` as Django, you can set up Apache to serve some URLs as +static media, and others using the mod_wsgi interface to Django. + +This example sets up Django at the site root, but explicitly serves ``robots.txt``, +``favicon.ico``, any CSS file, and anything in the ``/media/`` URL space as a static +file. All other URLs will be served using mod_wsgi:: + + Alias /robots.txt /usr/local/wsgi/static/robots.txt + Alias /favicon.ico /usr/local/wsgi/static/favicon.ico + + AliasMatch /([^/]*\.css) /usr/local/wsgi/static/styles/$1 + + Alias /media/ /usr/local/wsgi/static/media/ + + + Order deny,allow + Allow from all + + + WSGIScriptAlias / /usr/local/wsgi/scripts/django.wsgi + + + Order allow,deny + Allow from all + + +.. _lighttpd: http://www.lighttpd.net/ +.. _Nginx: http://wiki.codemongers.com/Main +.. _TUX: http://en.wikipedia.org/wiki/TUX_web_server +.. _Apache: http://httpd.apache.org/ +.. _Cherokee: http://www.cherokee-project.com/ + +More details on configuring a mod_wsgi site to serve static files can be found +in the mod_wsgi documentation on `hosting static files`_. + +.. _hosting static files: http://code.google.com/p/modwsgi/wiki/ConfigurationGuidelines#Hosting_Of_Static_Files + +Details +======== + +For more details, see the `mod_wsgi documentation on Django integration`_, +which explains the above in more detail, and walks through all the various +options you've got when deploying under mod_wsgi. + +.. _mod_wsgi documentation on Django integration: http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango diff --git a/docs/howto/error-reporting.txt b/docs/howto/error-reporting.txt index e0750ce327..246e7445d0 100644 --- a/docs/howto/error-reporting.txt +++ b/docs/howto/error-reporting.txt @@ -23,6 +23,10 @@ administrators immediate notification of any errors. The :setting:`ADMINS` will get a description of the error, a complete Python traceback, and details about the HTTP request that caused the error. +By default, Django will send email from root@localhost. However, some mail +providers reject all email from this address. To use a different sender +address, modify the :setting:`SERVER_EMAIL` setting. + To disable this behavior, just remove all entries from the :setting:`ADMINS` setting. @@ -33,12 +37,12 @@ Django can also be configured to email errors about broken links (404 "page not found" errors). Django sends emails about 404 errors when: * :setting:`DEBUG` is ``False`` - + * :setting:`SEND_BROKEN_LINK_EMAILS` is ``True`` - + * Your :setting:`MIDDLEWARE_CLASSES` setting includes ``CommonMiddleware`` (which it does by default). - + If those conditions are met, Django will e-mail the users listed in the :setting:`MANAGERS` setting whenever your code raises a 404 and the request has a referer. (It doesn't bother to e-mail for 404s that don't have a referer -- diff --git a/docs/intro/tutorial03.txt b/docs/intro/tutorial03.txt index f4ef5f76fe..687407a284 100644 --- a/docs/intro/tutorial03.txt +++ b/docs/intro/tutorial03.txt @@ -365,7 +365,7 @@ That takes care of setting ``handler404`` in the current module. As you can see in ``django/conf/urls/defaults.py``, ``handler404`` is set to :func:`django.views.defaults.page_not_found` by default. -Three more things to note about 404 views: +Four more things to note about 404 views: * If :setting:`DEBUG` is set to ``True`` (in your settings module) then your 404 view will never be used (and thus the ``404.html`` template will never diff --git a/docs/ref/contrib/admin/_images/article_actions.png b/docs/ref/contrib/admin/_images/article_actions.png index 254a8ad5576f9f5d1a4d5a00375a06b4b9a5c1ff..df4ab8f1ecd5dbd2046cbdef46a129ad98505fcd 100644 GIT binary patch literal 13367 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. If no instance name is +provided, a default instance name of ``admin`` will be used. + ``AdminSite`` attributes ------------------------ @@ -1339,10 +1361,10 @@ a pattern for your new view. .. note:: Any view you render that uses the admin templates, or extends the base - admin template, should include in it's context a variable named - ``admin_site`` that contains the name of the :class:`AdminSite` instance. For - :class:`AdminSite` instances, this means ``self.name``; for :class:`ModelAdmin` - instances, this means ``self.admin_site.name``. + admin template, should provide the ``current_app`` argument to + ``RequestContext`` or ``Context`` when rendering the template. It should + be set to either ``self.name`` if your view is on an ``AdminSite`` or + ``self.admin_site.name`` if your view is on a ``ModelAdmin``. .. _admin-reverse-urls: @@ -1356,37 +1378,31 @@ accessible using Django's :ref:`URL reversing system `. The :class:`AdminSite` provides the following named URL patterns: - ====================== =============================== ============= - Page URL name Parameters - ====================== =============================== ============= - Index ``admin_index`` - Logout ``admin_logout`` - Password change ``admin_password_change`` - Password change done ``admin_password_change_done`` - i18n javascript ``admin_jsi18n`` - Application index page ``admin_app_list`` ``app_label`` - ====================== =============================== ============= - -These names will be prefixed with the name of the :class:`AdminSite` instance, -plus an underscore. For example, if your :class:`AdminSite` was named -``custom``, then the Logout view would be served using a URL with the name -``custom_admin_logout``. The default :class:`AdminSite` doesn't use a prefix -in it's URL names. + ====================== ======================== ============= + Page URL name Parameters + ====================== ======================== ============= + Index ``index`` + Logout ``logout`` + Password change ``password_change`` + Password change done ``password_change_done`` + i18n javascript ``jsi18n`` + Application index page ``app_list`` ``app_label`` + ====================== ======================== ============= Each :class:`ModelAdmin` instance provides an additional set of named URLs: - ====================== ===================================================== ============= - Page URL name Parameters - ====================== ===================================================== ============= - Changelist ``admin_{{ app_label }}_{{ model_name }}_changelist`` - Add ``admin_{{ app_label }}_{{ model_name }}_add`` - History ``admin_{{ app_label }}_{{ model_name }}_history`` ``object_id`` - Delete ``admin_{{ app_label }}_{{ model_name }}_delete`` ``object_id`` - Change ``admin_{{ app_label }}_{{ model_name }}_change`` ``object_id`` - ====================== ===================================================== ============= + ====================== =============================================== ============= + Page URL name Parameters + ====================== =============================================== ============= + Changelist ``{{ app_label }}_{{ model_name }}_changelist`` + Add ``{{ app_label }}_{{ model_name }}_add`` + History ``{{ app_label }}_{{ model_name }}_history`` ``object_id`` + Delete ``{{ app_label }}_{{ model_name }}_delete`` ``object_id`` + Change ``{{ app_label }}_{{ model_name }}_change`` ``object_id`` + ====================== =============================================== ============= -Again, these names will be prefixed by the name of the :class:`AdminSite` in -which they are deployed. +These named URLs are registered with the application namespace ``admin``, and +with an instance namespace corresponding to the name of the Site instance. So - if you wanted to get a reference to the Change view for a particular ``Choice`` object (from the polls application) in the default admin, you would @@ -1394,8 +1410,16 @@ call:: >>> from django.core import urlresolvers >>> c = Choice.objects.get(...) - >>> change_url = urlresolvers.reverse('admin_polls_choice_change', args=(c.id,)) + >>> change_url = urlresolvers.reverse('admin:polls_choice_change', args=(c.id,)) -However, if the admin instance was named ``custom``, you would need to call:: +This will find the first registered instance of the admin application (whatever the instance +name), and resolve to the view for changing ``poll.Choice`` instances in that instance. - >>> change_url = urlresolvers.reverse('custom_admin_polls_choice_change', args=(c.id,)) +If you want to find a URL in a specific admin instance, provide the name of that instance +as a ``current_app`` hint to the reverse call. For example, if you specifically wanted +the admin view from the admin instance named ``custom``, you would need to call:: + + >>> change_url = urlresolvers.reverse('custom:polls_choice_change', args=(c.id,)) + +For more details, see the documentation on :ref:`reversing namespaced URLs +`. diff --git a/docs/ref/contrib/contenttypes.txt b/docs/ref/contrib/contenttypes.txt index 94900b3892..8a926afc97 100644 --- a/docs/ref/contrib/contenttypes.txt +++ b/docs/ref/contrib/contenttypes.txt @@ -177,9 +177,9 @@ The ``ContentTypeManager`` .. method:: models.ContentTypeManager.clear_cache() Clears an internal cache used by - :class:`~django.contrib.contenttypes.models.ContentType>` to keep track + :class:`~django.contrib.contenttypes.models.ContentType` to keep track of which models for which it has created - :class:`django.contrib.contenttypes.models.ContentType>` instances. You + :class:`django.contrib.contenttypes.models.ContentType` instances. You probably won't ever need to call this method yourself; Django will call it automatically when it's needed. diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt index e532971179..4bb6a7c444 100644 --- a/docs/ref/forms/fields.txt +++ b/docs/ref/forms/fields.txt @@ -275,7 +275,7 @@ For each field, we describe the default widget used if you don't specify * Default widget: ``CheckboxInput`` * Empty value: ``False`` * Normalizes to: A Python ``True`` or ``False`` value. - * Validates that the check box is checked (i.e. the value is ``True``) if + * Validates that the value is ``True`` (e.g. the check box is checked) if the field has ``required=True``. * Error message keys: ``required`` @@ -287,9 +287,10 @@ For each field, we describe the default widget used if you don't specify .. note:: Since all ``Field`` subclasses have ``required=True`` by default, the - validation condition here is important. If you want to include a checkbox - in your form that can be either checked or unchecked, you must remember to - pass in ``required=False`` when creating the ``BooleanField``. + validation condition here is important. If you want to include a boolean + in your form that can be either ``True`` or ``False`` (e.g. a checked or + unchecked checkbox), you must remember to pass in ``required=False`` when + creating the ``BooleanField``. ``CharField`` ~~~~~~~~~~~~~ @@ -328,7 +329,7 @@ Takes one extra required argument: An iterable (e.g., a list or tuple) of 2-tuples to use as choices for this field. - + ``TypedChoiceField`` ~~~~~~~~~~~~~~~~~~~~ @@ -437,7 +438,7 @@ If no ``input_formats`` argument is provided, the default input formats are:: ``min_value``, ``max_digits``, ``max_decimal_places``, ``max_whole_digits`` -Takes four optional arguments: +Takes four optional arguments: .. attribute:: DecimalField.max_value .. attribute:: DecimalField.min_value @@ -449,7 +450,7 @@ Takes four optional arguments: The maximum number of digits (those before the decimal point plus those after the decimal point, with leading zeros stripped) permitted in the value. - + .. attribute:: DecimalField.decimal_places The maximum number of decimal places permitted. @@ -522,18 +523,18 @@ extra arguments; only ``path`` is required: A regular expression pattern; only files with names matching this expression will be allowed as choices. -``FloatField`` -~~~~~~~~~~~~~~ +``FloatField`` +~~~~~~~~~~~~~~ - * Default widget: ``TextInput`` - * Empty value: ``None`` - * Normalizes to: A Python float. - * Validates that the given value is an float. Leading and trailing - whitespace is allowed, as in Python's ``float()`` function. - * Error message keys: ``required``, ``invalid``, ``max_value``, - ``min_value`` - -Takes two optional arguments for validation, ``max_value`` and ``min_value``. + * Default widget: ``TextInput`` + * Empty value: ``None`` + * Normalizes to: A Python float. + * Validates that the given value is an float. Leading and trailing + whitespace is allowed, as in Python's ``float()`` function. + * Error message keys: ``required``, ``invalid``, ``max_value``, + ``min_value`` + +Takes two optional arguments for validation, ``max_value`` and ``min_value``. These control the range of values permitted in the field. ``ImageField`` @@ -779,10 +780,10 @@ example:: (which is ``"---------"`` by default) with the ``empty_label`` attribute, or you can disable the empty label entirely by setting ``empty_label`` to ``None``:: - + # A custom empty label field1 = forms.ModelChoiceField(queryset=..., empty_label="(Nothing)") - + # No empty label field2 = forms.ModelChoiceField(queryset=..., empty_label=None) diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt index 348486b341..f78ebc506a 100644 --- a/docs/ref/models/querysets.txt +++ b/docs/ref/models/querysets.txt @@ -668,7 +668,7 @@ of the arguments is required, but you should use at least one of them. The resulting SQL of the above example would be:: - SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) + SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count FROM blog_blog; Note that the parenthesis required by most database engines around diff --git a/docs/ref/templates/api.txt b/docs/ref/templates/api.txt index 05097b7e59..e3260a96f8 100644 --- a/docs/ref/templates/api.txt +++ b/docs/ref/templates/api.txt @@ -86,9 +86,16 @@ Rendering a context Once you have a compiled ``Template`` object, you can render a context -- or multiple contexts -- with it. The ``Context`` class lives at -``django.template.Context``, and the constructor takes one (optional) -argument: a dictionary mapping variable names to variable values. Call the -``Template`` object's ``render()`` method with the context to "fill" the +``django.template.Context``, and the constructor takes two (optional) +arguments: + + * A dictionary mapping variable names to variable values. + + * The name of the current application. This application name is used + to help :ref:`resolve namespaced URLs`. + If you're not using namespaced URLs, you can ignore this argument. + +Call the ``Template`` object's ``render()`` method with the context to "fill" the template:: >>> from django.template import Context, Template @@ -549,13 +556,13 @@ Here are the template loaders that come with Django: Note that the loader performs an optimization when it is first imported: It caches a list of which :setting:`INSTALLED_APPS` packages have a ``templates`` subdirectory. - + This loader is enabled by default. ``django.template.loaders.eggs.load_template_source`` Just like ``app_directories`` above, but it loads templates from Python eggs rather than from the filesystem. - + This loader is disabled by default. Django uses the template loaders in order according to the diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index aedad6562f..a2f8b9f8b3 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -795,6 +795,16 @@ missing. In practice you'll use this to link to views that are optional:: Link to optional stuff {% endif %} +.. versionadded:: 1.1 + +If you'd like to retrieve a namespaced URL, specify the fully qualified name:: + + {% url myapp:view-name %} + +This will follow the normal :ref:`namespaced URL resolution strategy +`, including using any hints provided +by the context as to the current application. + .. templatetag:: widthratio widthratio diff --git a/docs/topics/forms/formsets.txt b/docs/topics/forms/formsets.txt index 8e90b54ced..e6146aeaba 100644 --- a/docs/topics/forms/formsets.txt +++ b/docs/topics/forms/formsets.txt @@ -86,9 +86,9 @@ displayed. Formset validation ------------------ -Validation with a formset is about identical to a regular ``Form``. There is +Validation with a formset is almost identical to a regular ``Form``. There is an ``is_valid`` method on the formset to provide a convenient way to validate -each form in the formset:: +all forms in the formset:: >>> ArticleFormSet = formset_factory(ArticleForm) >>> formset = ArticleFormSet({}) @@ -97,22 +97,25 @@ each form in the formset:: We passed in no data to the formset which is resulting in a valid form. The formset is smart enough to ignore extra forms that were not changed. If we -attempt to provide an article, but fail to do so:: +provide an invalid article:: >>> data = { - ... 'form-TOTAL_FORMS': u'1', - ... 'form-INITIAL_FORMS': u'1', + ... 'form-TOTAL_FORMS': u'2', + ... 'form-INITIAL_FORMS': u'0', ... 'form-0-title': u'Test', - ... 'form-0-pub_date': u'', + ... 'form-0-pub_date': u'16 June 1904', + ... 'form-1-title': u'Test', + ... 'form-1-pub_date': u'', # <-- this date is missing but required ... } >>> formset = ArticleFormSet(data) >>> formset.is_valid() False >>> formset.errors - [{'pub_date': [u'This field is required.']}] + [{}, {'pub_date': [u'This field is required.']}] -As we can see the formset properly performed validation and gave us the -expected errors. +As we can see, ``formset.errors`` is a list whose entries correspond to the +forms in the formset. Validation was performed for each of the two forms, and +the expected error message appears for the second item. .. _understanding-the-managementform: @@ -155,20 +158,40 @@ Custom formset validation ~~~~~~~~~~~~~~~~~~~~~~~~~ A formset has a ``clean`` method similar to the one on a ``Form`` class. This -is where you define your own validation that deals at the formset level:: +is where you define your own validation that works at the formset level:: >>> from django.forms.formsets import BaseFormSet >>> class BaseArticleFormSet(BaseFormSet): ... def clean(self): - ... raise forms.ValidationError, u'An error occured.' + ... """Checks that no two articles have the same title.""" + ... if any(self.errors): + ... # Don't bother validating the formset unless each form is valid on its own + ... return + ... titles = [] + ... for i in range(0, self.total_form_count()): + ... form = self.forms[i] + ... title = form.cleaned_data['title'] + ... if title in titles: + ... raise forms.ValidationError, "Articles in a set must have distinct titles." + ... titles.append(title) >>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet) - >>> formset = ArticleFormSet({}) + >>> data = { + ... 'form-TOTAL_FORMS': u'2', + ... 'form-INITIAL_FORMS': u'0', + ... 'form-0-title': u'Test', + ... 'form-0-pub_date': u'16 June 1904', + ... 'form-1-title': u'Test', + ... 'form-1-pub_date': u'23 June 1912', + ... } + >>> formset = ArticleFormSet(data) >>> formset.is_valid() False + >>> formset.errors + [{}, {}] >>> formset.non_form_errors() - [u'An error occured.'] + [u'Articles in a set must have distinct titles.'] The formset ``clean`` method is called after all the ``Form.clean`` methods have been called. The errors will be found using the ``non_form_errors()`` diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt index 4248d4f02e..b2e99dce7f 100644 --- a/docs/topics/http/urls.txt +++ b/docs/topics/http/urls.txt @@ -4,6 +4,8 @@ URL dispatcher ============== +.. module:: django.core.urlresolvers + A clean, elegant URL scheme is an important detail in a high-quality Web application. Django lets you design URLs however you want, with no framework limitations. @@ -40,14 +42,14 @@ algorithm the system follows to determine which Python code to execute: this is the value of the ``ROOT_URLCONF`` setting, but if the incoming ``HttpRequest`` object has an attribute called ``urlconf``, its value will be used in place of the ``ROOT_URLCONF`` setting. - + 2. Django loads that Python module and looks for the variable ``urlpatterns``. This should be a Python list, in the format returned by the function ``django.conf.urls.defaults.patterns()``. - + 3. Django runs through each URL pattern, in order, and stops at the first one that matches the requested URL. - + 4. Once one of the regexes matches, Django imports and calls the given view, which is a simple Python function. The view gets passed an :class:`~django.http.HttpRequest` as its first argument and any values @@ -182,11 +184,13 @@ your URLconf. This gives your module access to these objects: patterns -------- +.. function:: patterns(prefix, pattern_description, ...) + A function that takes a prefix, and an arbitrary number of URL patterns, and returns a list of URL patterns in the format Django needs. The first argument to ``patterns()`` is a string ``prefix``. See -"The view prefix" below. +`The view prefix`_ below. The remaining arguments should be tuples in this format:: @@ -222,6 +226,8 @@ url .. versionadded:: 1.0 +.. function:: url(regex, view, kwargs=None, name=None, prefix='') + You can use the ``url()`` function, instead of a tuple, as an argument to ``patterns()``. This is convenient if you want to specify a name without the optional extra arguments dictionary. For example:: @@ -244,6 +250,8 @@ The ``prefix`` parameter has the same meaning as the first argument to handler404 ---------- +.. data:: handler404 + A string representing the full Python import path to the view that should be called if none of the URL patterns match. @@ -253,6 +261,8 @@ value should suffice. handler500 ---------- +.. data:: handler500 + A string representing the full Python import path to the view that should be called in case of server errors. Server errors happen when you have runtime errors in view code. @@ -263,8 +273,17 @@ value should suffice. include ------- -A function that takes a full Python import path to another URLconf that should -be "included" in this place. See `Including other URLconfs`_ below. +.. function:: include() + +A function that takes a full Python import path to another URLconf module that +should be "included" in this place. + +.. versionadded:: 1.1 + +:func:`include` also accepts as an argument an iterable that returns URL +patterns. + +See `Including other URLconfs`_ below. Notes on capturing text in URLs =============================== @@ -391,6 +410,32 @@ Django encounters ``include()``, it chops off whatever part of the URL matched up to that point and sends the remaining string to the included URLconf for further processing. +.. versionadded:: 1.1 + +Another possibility is to include additional URL patterns not by specifying the +URLconf Python module defining them as the `include`_ argument but by using +directly the pattern list as returned by `patterns`_ instead. For example:: + + from django.conf.urls.defaults import * + + extra_patterns = patterns('', + url(r'reports/(?P\d+)/$', 'credit.views.report', name='credit-reports'), + url(r'charge/$', 'credit.views.charge', name='credit-charge'), + ) + + urlpatterns = patterns('', + url(r'^$', 'apps.main.views.homepage', name='site-homepage'), + (r'^help/', include('apps.help.urls')), + (r'^credit/', include(extra_patterns)), + ) + +This approach can be seen in use when you deploy an instance of the Django +Admin application. The Django Admin is deployed as instances of a +:class:`AdminSite`; each :class:`AdminSite` instance has an attribute +``urls`` that returns the url patterns available to that instance. It is this +attribute that you ``include()`` into your projects ``urlpatterns`` when you +deploy the admin instance. + .. _`Django Web site`: http://www.djangoproject.com/ Captured parameters @@ -413,6 +458,58 @@ the following example is valid:: In the above example, the captured ``"username"`` variable is passed to the included URLconf, as expected. +.. _topics-http-defining-url-namespaces: + +Defining URL Namespaces +----------------------- + +When you need to deploy multiple instances of a single application, it can be +helpful to be able to differentiate between instances. This is especially +important when using _`named URL patterns `, since +multiple instances of a single application will share named URLs. Namespaces +provide a way to tell these named URLs apart. + +A URL namespace comes in two parts, both of which are strings: + + * An **application namespace**. This describes the name of the application + that is being deployed. Every instance of a single application will have + the same application namespace. For example, Django's admin application + has the somewhat predictable application namespace of ``admin``. + + * An **instance namespace**. This identifies a specific instance of an + application. Instance namespaces should be unique across your entire + project. However, an instance namespace can be the same as the + application namespace. This is used to specify a default instance of an + application. For example, the default Django Admin instance has an + instance namespace of ``admin``. + +URL Namespaces can be specified in two ways. + +Firstly, you can provide the application and instance namespace as arguments +to ``include()`` when you construct your URL patterns. For example,:: + + (r'^help/', include('apps.help.urls', namespace='foo', app_name='bar')), + +This will include the URLs defined in ``apps.help.urls`` into the application +namespace ``bar``, with the instance namespace ``foo``. + +Secondly, you can include an object that contains embedded namespace data. If +you ``include()`` a ``patterns`` object, that object will be added to the +global namespace. However, you can also ``include()`` an object that contains +a 3-tuple containing:: + + (, , ) + +This will include the nominated URL patterns into the given application and +instance namespace. For example, the ``urls`` attribute of Django's +:class:`AdminSite` object returns a 3-tuple that contains all the patterns in +an admin site, plus the name of the admin instance, and the application +namespace ``admin``. + +Once you have defined namespaced URLs, you can reverse them. For details on +reversing namespaced urls, see the documentation on :ref:`reversing namespaced +URLs `. + Passing extra options to view functions ======================================= @@ -587,6 +684,86 @@ not restricted to valid Python names. name, will decrease the chances of collision. We recommend something like ``myapp-comment`` instead of ``comment``. +.. _topics-http-reversing-url-namespaces: + +URL namespaces +-------------- + +.. versionadded:: 1.1 + +Namespaced URLs are specified using the ``:`` operator. For example, the main +index page of the admin application is referenced using ``admin:index``. This +indicates a namespace of ``admin``, and a named URL of ``index``. + +Namespaces can also be nested. The named URL ``foo:bar:whiz`` would look for +a pattern named ``whiz`` in the namespace ``bar`` that is itself defined within +the top-level namespace ``foo``. + +When given a namespaced URL (e.g. ``myapp:index``) to resolve, Django splits +the fully qualified name into parts, and then tries the following lookup: + + 1. First, Django looks for a matching application namespace (in this + example, ``myapp``). This will yield a list of instances of that + application. + + 2. If there is a ``current`` application defined, Django finds and returns + the URL resolver for that instance. The ``current`` can be specified + as an attribute on the template context - applications that expect to + have multiple deployments should set the ``current_app`` attribute on + any ``Context`` or ``RequestContext`` that is used to render a + template. + + The current application can also be specified manually as an argument + to the :func:`reverse()` function. + + 3. If there is no current application. Django looks for a default + application instance. The default application instance is the instance + that has an instance namespace matching the application namespace (in + this example, an instance of the ``myapp`` called ``myapp``). + + 4. If there is no default application instance, Django will pick the first + deployed instance of the application, whatever its instance name may be. + + 5. If the provided namespace doesn't match an application namespace in + step 2, Django will attempt a direct lookup of the namespace as an + instance namespace. + +If there are nested namespaces, these steps are repeated for each part of the +namespace until only the view name is unresolved. The view name will then be +resolved into a URL in the namespace that has been found. + +To show this resolution strategy in action, consider an example of two instances +of ``myapp``: one called ``foo``, and one called ``bar``. ``myapp`` has a main +index page with a URL named `index`. Using this setup, the following lookups are +possible: + + * If one of the instances is current - say, if we were rendering a utility page + in the instance ``bar`` - ``myapp:index`` will resolve to the index page of + the instance ``bar``. + + * If there is no current instance - say, if we were rendering a page + somewhere else on the site - ``myapp:index`` will resolve to the first + registered instance of ``myapp``. Since there is no default instance, + the first instance of ``myapp`` that is registered will be used. This could + be ``foo`` or ``bar``, depending on the order they are introduced into the + urlpatterns of the project. + + * ``foo:index`` will always resolve to the index page of the instance ``foo``. + +If there was also a default instance - i.e., an instance named `myapp` - the +following would happen: + + * If one of the instances is current - say, if we were rendering a utility page + in the instance ``bar`` - ``myapp:index`` will resolve to the index page of + the instance ``bar``. + + * If there is no current instance - say, if we were rendering a page somewhere + else on the site - ``myapp:index`` will resolve to the index page of the + default instance. + + * ``foo:index`` will again resolve to the index page of the instance ``foo``. + + Utility methods =============== @@ -597,8 +774,7 @@ If you need to use something similar to the :ttag:`url` template tag in your code, Django provides the following method (in the ``django.core.urlresolvers`` module): -.. currentmodule:: django.core.urlresolvers -.. function:: reverse(viewname, urlconf=None, args=None, kwargs=None) +.. function:: reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None) ``viewname`` is either the function name (either a function reference, or the string version of the name, if you used that form in ``urlpatterns``) or the @@ -620,6 +796,14 @@ vertical bar (``"|"``) character. You can quite happily use such patterns for matching against incoming URLs and sending them off to views, but you cannot reverse such patterns. +.. versionadded:: 1.1 + +The ``current_app`` argument allows you to provide a hint to the resolver +indicating the application to which the currently executing view belongs. +This ``current_app`` argument is used as a hint to resolve application +namespaces into URLs on specific application instances, according to the +:ref:`namespaced URL resolution strategy `. + .. admonition:: Make sure your views are all correct As part of working out which URL names map to which patterns, the @@ -639,7 +823,6 @@ resolve() The :func:`django.core.urlresolvers.resolve` function can be used for resolving URL paths to the corresponding view functions. It has the following signature: -.. currentmodule:: django.core.urlresolvers .. function:: resolve(path, urlconf=None) ``path`` is the URL path you want to resolve. As with ``reverse()`` above, you diff --git a/docs/topics/i18n.txt b/docs/topics/i18n.txt index 7bf51c11c5..c5f4ab6481 100644 --- a/docs/topics/i18n.txt +++ b/docs/topics/i18n.txt @@ -959,11 +959,11 @@ Using the JavaScript translation catalog To use the catalog, just pull in the dynamically generated script like this:: - + -This is how the admin fetches the translation catalog from the server. When the -catalog is loaded, your JavaScript code can use the standard ``gettext`` -interface to access it:: +This uses reverse URL lookup to find the URL of the JavaScript catalog view. +When the catalog is loaded, your JavaScript code can use the standard +``gettext`` interface to access it:: document.write(gettext('this is to be translated')); diff --git a/docs/topics/testing.txt b/docs/topics/testing.txt index d235e0deba..cec6002b7b 100644 --- a/docs/topics/testing.txt +++ b/docs/topics/testing.txt @@ -686,7 +686,13 @@ arguments at time of construction: user accounts that are valid on your production site will not work under test conditions. You'll need to create users as part of the test suite -- either manually (using the Django model API) or with a test - fixture. + fixture. Remember that if you want your test user to have a password, + you can't set the user's password by setting the password attribute + directly -- you must use the + :meth:`~django.contrib.auth.models.User.set_password()` function to + store a correctly hashed password. Alternatively, you can use the + :meth:`~django.contrib.auth.models.UserManager.create_user` helper + method to create a new user with a correctly hashed password. .. method:: Client.logout() diff --git a/tests/regressiontests/admin_views/customadmin.py b/tests/regressiontests/admin_views/customadmin.py index 70e87ebcfe..80570ea51d 100644 --- a/tests/regressiontests/admin_views/customadmin.py +++ b/tests/regressiontests/admin_views/customadmin.py @@ -10,19 +10,19 @@ import models class Admin2(admin.AdminSite): login_template = 'custom_admin/login.html' index_template = 'custom_admin/index.html' - + # A custom index view. def index(self, request, extra_context=None): return super(Admin2, self).index(request, {'foo': '*bar*'}) - + def get_urls(self): return patterns('', (r'^my_view/$', self.admin_view(self.my_view)), ) + super(Admin2, self).get_urls() - + def my_view(self, request): return HttpResponse("Django is a magical pony!") - + site = Admin2(name="admin2") site.register(models.Article, models.ArticleAdmin) diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py index 99168fdeee..aafa303cec 100644 --- a/tests/regressiontests/admin_views/tests.py +++ b/tests/regressiontests/admin_views/tests.py @@ -10,6 +10,7 @@ from django.contrib.admin.models import LogEntry, DELETION from django.contrib.admin.sites import LOGIN_FORM_KEY from django.contrib.admin.util import quote from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME +from django.utils.cache import get_max_age from django.utils.html import escape # local test models @@ -204,6 +205,11 @@ class AdminViewBasicTest(TestCase): response = self.client.get('/test_admin/%s/admin_views/thing/' % self.urlbit, {'color__id__exact': 'StringNotInteger!'}) self.assertRedirects(response, '/test_admin/%s/admin_views/thing/?e=1' % self.urlbit) + def testLogoutAndPasswordChangeURLs(self): + response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit) + self.failIf('' % self.urlbit not in response.content) + self.failIf('' % self.urlbit not in response.content) + def testNamedGroupFieldChoicesChangeList(self): """ Ensures the admin changelist shows correct values in the relevant column @@ -1527,3 +1533,76 @@ class AdminInlineTests(TestCase): self.failUnlessEqual(Category.objects.get(id=2).order, 13) self.failUnlessEqual(Category.objects.get(id=3).order, 1) self.failUnlessEqual(Category.objects.get(id=4).order, 0) + + +class NeverCacheTests(TestCase): + fixtures = ['admin-views-users.xml', 'admin-views-colors.xml', 'admin-views-fabrics.xml'] + + def setUp(self): + self.client.login(username='super', password='secret') + + def tearDown(self): + self.client.logout() + + def testAdminIndex(self): + "Check the never-cache status of the main index" + response = self.client.get('/test_admin/admin/') + self.failUnlessEqual(get_max_age(response), 0) + + def testAppIndex(self): + "Check the never-cache status of an application index" + response = self.client.get('/test_admin/admin/admin_views/') + self.failUnlessEqual(get_max_age(response), 0) + + def testModelIndex(self): + "Check the never-cache status of a model index" + response = self.client.get('/test_admin/admin/admin_views/fabric/') + self.failUnlessEqual(get_max_age(response), 0) + + def testModelAdd(self): + "Check the never-cache status of a model add page" + response = self.client.get('/test_admin/admin/admin_views/fabric/add/') + self.failUnlessEqual(get_max_age(response), 0) + + def testModelView(self): + "Check the never-cache status of a model edit page" + response = self.client.get('/test_admin/admin/admin_views/section/1/') + self.failUnlessEqual(get_max_age(response), 0) + + def testModelHistory(self): + "Check the never-cache status of a model history page" + response = self.client.get('/test_admin/admin/admin_views/section/1/history/') + self.failUnlessEqual(get_max_age(response), 0) + + def testModelDelete(self): + "Check the never-cache status of a model delete page" + response = self.client.get('/test_admin/admin/admin_views/section/1/delete/') + self.failUnlessEqual(get_max_age(response), 0) + + def testLogin(self): + "Check the never-cache status of login views" + self.client.logout() + response = self.client.get('/test_admin/admin/') + self.failUnlessEqual(get_max_age(response), 0) + + def testLogout(self): + "Check the never-cache status of logout view" + response = self.client.get('/test_admin/admin/logout/') + self.failUnlessEqual(get_max_age(response), 0) + + def testPasswordChange(self): + "Check the never-cache status of the password change view" + self.client.logout() + response = self.client.get('/test_admin/password_change/') + self.failUnlessEqual(get_max_age(response), None) + + def testPasswordChangeDone(self): + "Check the never-cache status of the password change done view" + response = self.client.get('/test_admin/admin/password_change/done/') + self.failUnlessEqual(get_max_age(response), None) + + def testJsi18n(self): + "Check the never-cache status of the Javascript i18n view" + response = self.client.get('/test_admin/jsi18n/') + self.failUnlessEqual(get_max_age(response), None) + diff --git a/tests/regressiontests/admin_widgets/widgetadmin.py b/tests/regressiontests/admin_widgets/widgetadmin.py index bd68954a70..9257c306c9 100644 --- a/tests/regressiontests/admin_widgets/widgetadmin.py +++ b/tests/regressiontests/admin_widgets/widgetadmin.py @@ -19,7 +19,7 @@ class CarTireAdmin(admin.ModelAdmin): return db_field.formfield(**kwargs) return super(CarTireAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs) -site = WidgetAdmin() +site = WidgetAdmin(name='widget-admin') site.register(models.User) site.register(models.Car, CarAdmin) diff --git a/tests/regressiontests/m2m_through_regress/fixtures/m2m_through.json b/tests/regressiontests/m2m_through_regress/fixtures/m2m_through.json new file mode 100644 index 0000000000..6f24886f02 --- /dev/null +++ b/tests/regressiontests/m2m_through_regress/fixtures/m2m_through.json @@ -0,0 +1,34 @@ +[ + { + "pk": "1", + "model": "m2m_through_regress.person", + "fields": { + "name": "Guido" + } + }, + { + "pk": "1", + "model": "auth.user", + "fields": { + "username": "Guido", + "email": "bdfl@python.org", + "password": "abcde" + } + }, + { + "pk": "1", + "model": "m2m_through_regress.group", + "fields": { + "name": "Python Core Group" + } + }, + { + "pk": "1", + "model": "m2m_through_regress.usermembership", + "fields": { + "user": "1", + "group": "1", + "price": "100" + } + } +] \ No newline at end of file diff --git a/tests/regressiontests/m2m_through_regress/models.py b/tests/regressiontests/m2m_through_regress/models.py index 8594f19dee..dcf5f8115b 100644 --- a/tests/regressiontests/m2m_through_regress/models.py +++ b/tests/regressiontests/m2m_through_regress/models.py @@ -12,7 +12,9 @@ class Membership(models.Model): def __unicode__(self): return "%s is a member of %s" % (self.person.name, self.group.name) +# using custom id column to test ticket #11107 class UserMembership(models.Model): + id = models.AutoField(db_column='usermembership_id', primary_key=True) user = models.ForeignKey(User) group = models.ForeignKey('Group') price = models.IntegerField(default=100) @@ -196,4 +198,12 @@ doing a join. # Flush the database, just to make sure we can. >>> management.call_command('flush', verbosity=0, interactive=False) +## Regression test for #11107 +Ensure that sequences on m2m_through tables are being created for the through +model, not for a phantom auto-generated m2m table. + +>>> management.call_command('loaddata', 'm2m_through', verbosity=0) +>>> management.call_command('dumpdata', 'm2m_through_regress', format='json') +[{"pk": 1, "model": "m2m_through_regress.usermembership", "fields": {"price": 100, "group": 1, "user": 1}}, {"pk": 1, "model": "m2m_through_regress.person", "fields": {"name": "Guido"}}, {"pk": 1, "model": "m2m_through_regress.group", "fields": {"name": "Python Core Group"}}] + """} diff --git a/tests/regressiontests/urlpatterns_reverse/included_namespace_urls.py b/tests/regressiontests/urlpatterns_reverse/included_namespace_urls.py new file mode 100644 index 0000000000..073190657c --- /dev/null +++ b/tests/regressiontests/urlpatterns_reverse/included_namespace_urls.py @@ -0,0 +1,13 @@ +from django.conf.urls.defaults import * +from namespace_urls import URLObject + +testobj3 = URLObject('testapp', 'test-ns3') + +urlpatterns = patterns('regressiontests.urlpatterns_reverse.views', + url(r'^normal/$', 'empty_view', name='inc-normal-view'), + url(r'^normal/(?P\d+)/(?P\d+)/$', 'empty_view', name='inc-normal-view'), + + (r'^test3/', include(testobj3.urls)), + (r'^ns-included3/', include('regressiontests.urlpatterns_reverse.included_urls', namespace='inc-ns3')), +) + diff --git a/tests/regressiontests/urlpatterns_reverse/namespace_urls.py b/tests/regressiontests/urlpatterns_reverse/namespace_urls.py new file mode 100644 index 0000000000..27cc7f7a22 --- /dev/null +++ b/tests/regressiontests/urlpatterns_reverse/namespace_urls.py @@ -0,0 +1,38 @@ +from django.conf.urls.defaults import * + +class URLObject(object): + def __init__(self, app_name, namespace): + self.app_name = app_name + self.namespace = namespace + + def urls(self): + return patterns('', + url(r'^inner/$', 'empty_view', name='urlobject-view'), + url(r'^inner/(?P\d+)/(?P\d+)/$', 'empty_view', name='urlobject-view'), + ), self.app_name, self.namespace + urls = property(urls) + +testobj1 = URLObject('testapp', 'test-ns1') +testobj2 = URLObject('testapp', 'test-ns2') +default_testobj = URLObject('testapp', 'testapp') + +otherobj1 = URLObject('nodefault', 'other-ns1') +otherobj2 = URLObject('nodefault', 'other-ns2') + +urlpatterns = patterns('regressiontests.urlpatterns_reverse.views', + url(r'^normal/$', 'empty_view', name='normal-view'), + url(r'^normal/(?P\d+)/(?P\d+)/$', 'empty_view', name='normal-view'), + + (r'^test1/', include(testobj1.urls)), + (r'^test2/', include(testobj2.urls)), + (r'^default/', include(default_testobj.urls)), + + (r'^other1/', include(otherobj1.urls)), + (r'^other2/', include(otherobj2.urls)), + + (r'^ns-included1/', include('regressiontests.urlpatterns_reverse.included_namespace_urls', namespace='inc-ns1')), + (r'^ns-included2/', include('regressiontests.urlpatterns_reverse.included_namespace_urls', namespace='inc-ns2')), + + (r'^included/', include('regressiontests.urlpatterns_reverse.included_namespace_urls')), + +) diff --git a/tests/regressiontests/urlpatterns_reverse/tests.py b/tests/regressiontests/urlpatterns_reverse/tests.py index 9def6b2eb2..d4f281ba81 100644 --- a/tests/regressiontests/urlpatterns_reverse/tests.py +++ b/tests/regressiontests/urlpatterns_reverse/tests.py @@ -158,4 +158,84 @@ class ReverseShortcutTests(TestCase): res = redirect('/foo/') self.assertEqual(res['Location'], '/foo/') res = redirect('http://example.com/') - self.assertEqual(res['Location'], 'http://example.com/') \ No newline at end of file + self.assertEqual(res['Location'], 'http://example.com/') + + +class NamespaceTests(TestCase): + urls = 'regressiontests.urlpatterns_reverse.namespace_urls' + + def test_ambiguous_object(self): + "Names deployed via dynamic URL objects that require namespaces can't be resolved" + self.assertRaises(NoReverseMatch, reverse, 'urlobject-view') + self.assertRaises(NoReverseMatch, reverse, 'urlobject-view', args=[37,42]) + self.assertRaises(NoReverseMatch, reverse, 'urlobject-view', kwargs={'arg1':42, 'arg2':37}) + + def test_ambiguous_urlpattern(self): + "Names deployed via dynamic URL objects that require namespaces can't be resolved" + self.assertRaises(NoReverseMatch, reverse, 'inner-nothing') + self.assertRaises(NoReverseMatch, reverse, 'inner-nothing', args=[37,42]) + self.assertRaises(NoReverseMatch, reverse, 'inner-nothing', kwargs={'arg1':42, 'arg2':37}) + + def test_non_existent_namespace(self): + "Non-existent namespaces raise errors" + self.assertRaises(NoReverseMatch, reverse, 'blahblah:urlobject-view') + self.assertRaises(NoReverseMatch, reverse, 'test-ns1:blahblah:urlobject-view') + + def test_normal_name(self): + "Normal lookups work as expected" + self.assertEquals('/normal/', reverse('normal-view')) + self.assertEquals('/normal/37/42/', reverse('normal-view', args=[37,42])) + self.assertEquals('/normal/42/37/', reverse('normal-view', kwargs={'arg1':42, 'arg2':37})) + + def test_simple_included_name(self): + "Normal lookups work on names included from other patterns" + self.assertEquals('/included/normal/', reverse('inc-normal-view')) + self.assertEquals('/included/normal/37/42/', reverse('inc-normal-view', args=[37,42])) + self.assertEquals('/included/normal/42/37/', reverse('inc-normal-view', kwargs={'arg1':42, 'arg2':37})) + + def test_namespace_object(self): + "Dynamic URL objects can be found using a namespace" + self.assertEquals('/test1/inner/', reverse('test-ns1:urlobject-view')) + self.assertEquals('/test1/inner/37/42/', reverse('test-ns1:urlobject-view', args=[37,42])) + self.assertEquals('/test1/inner/42/37/', reverse('test-ns1:urlobject-view', kwargs={'arg1':42, 'arg2':37})) + + def test_embedded_namespace_object(self): + "Namespaces can be installed anywhere in the URL pattern tree" + self.assertEquals('/included/test3/inner/', reverse('test-ns3:urlobject-view')) + self.assertEquals('/included/test3/inner/37/42/', reverse('test-ns3:urlobject-view', args=[37,42])) + self.assertEquals('/included/test3/inner/42/37/', reverse('test-ns3:urlobject-view', kwargs={'arg1':42, 'arg2':37})) + + def test_namespace_pattern(self): + "Namespaces can be applied to include()'d urlpatterns" + self.assertEquals('/ns-included1/normal/', reverse('inc-ns1:inc-normal-view')) + self.assertEquals('/ns-included1/normal/37/42/', reverse('inc-ns1:inc-normal-view', args=[37,42])) + self.assertEquals('/ns-included1/normal/42/37/', reverse('inc-ns1:inc-normal-view', kwargs={'arg1':42, 'arg2':37})) + + def test_multiple_namespace_pattern(self): + "Namespaces can be embedded" + self.assertEquals('/ns-included1/test3/inner/', reverse('inc-ns1:test-ns3:urlobject-view')) + self.assertEquals('/ns-included1/test3/inner/37/42/', reverse('inc-ns1:test-ns3:urlobject-view', args=[37,42])) + self.assertEquals('/ns-included1/test3/inner/42/37/', reverse('inc-ns1:test-ns3:urlobject-view', kwargs={'arg1':42, 'arg2':37})) + + def test_app_lookup_object(self): + "A default application namespace can be used for lookup" + self.assertEquals('/default/inner/', reverse('testapp:urlobject-view')) + self.assertEquals('/default/inner/37/42/', reverse('testapp:urlobject-view', args=[37,42])) + self.assertEquals('/default/inner/42/37/', reverse('testapp:urlobject-view', kwargs={'arg1':42, 'arg2':37})) + + def test_app_lookup_object_with_default(self): + "A default application namespace is sensitive to the 'current' app can be used for lookup" + self.assertEquals('/included/test3/inner/', reverse('testapp:urlobject-view', current_app='test-ns3')) + self.assertEquals('/included/test3/inner/37/42/', reverse('testapp:urlobject-view', args=[37,42], current_app='test-ns3')) + self.assertEquals('/included/test3/inner/42/37/', reverse('testapp:urlobject-view', kwargs={'arg1':42, 'arg2':37}, current_app='test-ns3')) + + def test_app_lookup_object_without_default(self): + "An application namespace without a default is sensitive to the 'current' app can be used for lookup" + self.assertEquals('/other2/inner/', reverse('nodefault:urlobject-view')) + self.assertEquals('/other2/inner/37/42/', reverse('nodefault:urlobject-view', args=[37,42])) + self.assertEquals('/other2/inner/42/37/', reverse('nodefault:urlobject-view', kwargs={'arg1':42, 'arg2':37})) + + self.assertEquals('/other1/inner/', reverse('nodefault:urlobject-view', current_app='other-ns1')) + self.assertEquals('/other1/inner/37/42/', reverse('nodefault:urlobject-view', args=[37,42], current_app='other-ns1')) + self.assertEquals('/other1/inner/42/37/', reverse('nodefault:urlobject-view', kwargs={'arg1':42, 'arg2':37}, current_app='other-ns1')) +