mirror of
https://github.com/django/django.git
synced 2025-07-07 11:19:12 +00:00
[soc2009/model-validation] Merged to trunk at r11791
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/model-validation@11798 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
30ea350dab
commit
3b895d4a9a
1
AUTHORS
1
AUTHORS
@ -17,6 +17,7 @@ The PRIMARY AUTHORS are (and/or have been):
|
|||||||
* Justin Bronn
|
* Justin Bronn
|
||||||
* Karen Tracey
|
* Karen Tracey
|
||||||
* Jannis Leidel
|
* Jannis Leidel
|
||||||
|
* James Tauber
|
||||||
|
|
||||||
More information on the main contributors to Django can be found in
|
More information on the main contributors to Django can be found in
|
||||||
docs/internals/committers.txt.
|
docs/internals/committers.txt.
|
||||||
|
Binary file not shown.
@ -5,7 +5,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Django\n"
|
"Project-Id-Version: Django\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2009-07-07 15:04+0200\n"
|
"POT-Creation-Date: 2009-11-30 11:19+0100\n"
|
||||||
"PO-Revision-Date: 2009-03-24 13:28+0100\n"
|
"PO-Revision-Date: 2009-03-24 13:28+0100\n"
|
||||||
"Last-Translator: Django Catalan Group <django-cat@googlegroups.com>\n"
|
"Last-Translator: Django Catalan Group <django-cat@googlegroups.com>\n"
|
||||||
"Language-Team: Catalan <ca@li.org>\n"
|
"Language-Team: Catalan <ca@li.org>\n"
|
||||||
@ -223,7 +223,7 @@ msgstr "xinès tradicional"
|
|||||||
msgid "Successfully deleted %(count)d %(items)s."
|
msgid "Successfully deleted %(count)d %(items)s."
|
||||||
msgstr "Eliminat/s %(count)d %(items)s satisfactòriament."
|
msgstr "Eliminat/s %(count)d %(items)s satisfactòriament."
|
||||||
|
|
||||||
#: contrib/admin/actions.py:67 contrib/admin/options.py:1025
|
#: contrib/admin/actions.py:67 contrib/admin/options.py:1033
|
||||||
msgid "Are you sure?"
|
msgid "Are you sure?"
|
||||||
msgstr "Esteu segurs?"
|
msgstr "Esteu segurs?"
|
||||||
|
|
||||||
@ -266,15 +266,15 @@ msgstr "Aquest mes"
|
|||||||
msgid "This year"
|
msgid "This year"
|
||||||
msgstr "Aquest any"
|
msgstr "Aquest any"
|
||||||
|
|
||||||
#: contrib/admin/filterspecs.py:147 forms/widgets.py:434
|
#: contrib/admin/filterspecs.py:147 forms/widgets.py:435
|
||||||
msgid "Yes"
|
msgid "Yes"
|
||||||
msgstr "Si"
|
msgstr "Si"
|
||||||
|
|
||||||
#: contrib/admin/filterspecs.py:147 forms/widgets.py:434
|
#: contrib/admin/filterspecs.py:147 forms/widgets.py:435
|
||||||
msgid "No"
|
msgid "No"
|
||||||
msgstr "No"
|
msgstr "No"
|
||||||
|
|
||||||
#: contrib/admin/filterspecs.py:154 forms/widgets.py:434
|
#: contrib/admin/filterspecs.py:154 forms/widgets.py:435
|
||||||
msgid "Unknown"
|
msgid "Unknown"
|
||||||
msgstr "Desconegut"
|
msgstr "Desconegut"
|
||||||
|
|
||||||
@ -310,61 +310,61 @@ msgstr "entrada del registre"
|
|||||||
msgid "log entries"
|
msgid "log entries"
|
||||||
msgstr "entrades del registre"
|
msgstr "entrades del registre"
|
||||||
|
|
||||||
#: contrib/admin/options.py:133 contrib/admin/options.py:147
|
#: contrib/admin/options.py:134 contrib/admin/options.py:148
|
||||||
msgid "None"
|
msgid "None"
|
||||||
msgstr "cap"
|
msgstr "cap"
|
||||||
|
|
||||||
#: contrib/admin/options.py:519
|
#: contrib/admin/options.py:521
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Changed %s."
|
msgid "Changed %s."
|
||||||
msgstr "Modificat %s."
|
msgstr "Modificat %s."
|
||||||
|
|
||||||
#: contrib/admin/options.py:519 contrib/admin/options.py:529
|
#: contrib/admin/options.py:521 contrib/admin/options.py:531
|
||||||
#: contrib/comments/templates/comments/preview.html:16 forms/models.py:388
|
#: contrib/comments/templates/comments/preview.html:16 forms/models.py:384
|
||||||
#: forms/models.py:600
|
#: forms/models.py:596
|
||||||
msgid "and"
|
msgid "and"
|
||||||
msgstr "i"
|
msgstr "i"
|
||||||
|
|
||||||
#: contrib/admin/options.py:524
|
#: contrib/admin/options.py:526
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Added %(name)s \"%(object)s\"."
|
msgid "Added %(name)s \"%(object)s\"."
|
||||||
msgstr "Afegit %(name)s \"%(object)s\""
|
msgstr "Afegit %(name)s \"%(object)s\""
|
||||||
|
|
||||||
#: contrib/admin/options.py:528
|
#: contrib/admin/options.py:530
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Changed %(list)s for %(name)s \"%(object)s\"."
|
msgid "Changed %(list)s for %(name)s \"%(object)s\"."
|
||||||
msgstr "Modificat %(list)s per a %(name)s \"%(object)s\"."
|
msgstr "Modificat %(list)s per a %(name)s \"%(object)s\"."
|
||||||
|
|
||||||
#: contrib/admin/options.py:533
|
#: contrib/admin/options.py:535
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Deleted %(name)s \"%(object)s\"."
|
msgid "Deleted %(name)s \"%(object)s\"."
|
||||||
msgstr "Eliminat %(name)s \"%(object)s\"."
|
msgstr "Eliminat %(name)s \"%(object)s\"."
|
||||||
|
|
||||||
#: contrib/admin/options.py:537
|
#: contrib/admin/options.py:539
|
||||||
msgid "No fields changed."
|
msgid "No fields changed."
|
||||||
msgstr "Cap camp canviat."
|
msgstr "Cap camp canviat."
|
||||||
|
|
||||||
#: contrib/admin/options.py:598 contrib/auth/admin.py:67
|
#: contrib/admin/options.py:601 contrib/auth/admin.py:67
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The %(name)s \"%(obj)s\" was added successfully."
|
msgid "The %(name)s \"%(obj)s\" was added successfully."
|
||||||
msgstr "El/la %(name)s \"%(obj)s\".ha estat afegit/da amb èxit."
|
msgstr "El/la %(name)s \"%(obj)s\".ha estat afegit/da amb èxit."
|
||||||
|
|
||||||
#: contrib/admin/options.py:602 contrib/admin/options.py:635
|
#: contrib/admin/options.py:605 contrib/admin/options.py:638
|
||||||
#: contrib/auth/admin.py:75
|
#: contrib/auth/admin.py:75
|
||||||
msgid "You may edit it again below."
|
msgid "You may edit it again below."
|
||||||
msgstr "Podeu editar-lo de nou a baix."
|
msgstr "Podeu editar-lo de nou a baix."
|
||||||
|
|
||||||
#: contrib/admin/options.py:612 contrib/admin/options.py:645
|
#: contrib/admin/options.py:615 contrib/admin/options.py:648
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "You may add another %s below."
|
msgid "You may add another %s below."
|
||||||
msgstr "Podeu afegir un altre %s a baix."
|
msgstr "Podeu afegir un altre %s a baix."
|
||||||
|
|
||||||
#: contrib/admin/options.py:633
|
#: contrib/admin/options.py:636
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The %(name)s \"%(obj)s\" was changed successfully."
|
msgid "The %(name)s \"%(obj)s\" was changed successfully."
|
||||||
msgstr "S'ha modificat amb èxit el/la %(name)s \"%(obj)s."
|
msgstr "S'ha modificat amb èxit el/la %(name)s \"%(obj)s."
|
||||||
|
|
||||||
#: contrib/admin/options.py:641
|
#: contrib/admin/options.py:644
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
|
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
|
||||||
@ -372,43 +372,43 @@ msgstr ""
|
|||||||
"S'ha afegit exitosament el/la %(name)s \"%(obj)s\". Pot editar-lo de nou "
|
"S'ha afegit exitosament el/la %(name)s \"%(obj)s\". Pot editar-lo de nou "
|
||||||
"abaix."
|
"abaix."
|
||||||
|
|
||||||
#: contrib/admin/options.py:772
|
#: contrib/admin/options.py:777
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Add %s"
|
msgid "Add %s"
|
||||||
msgstr "Afegir %s"
|
msgstr "Afegir %s"
|
||||||
|
|
||||||
#: contrib/admin/options.py:803 contrib/admin/options.py:1003
|
#: contrib/admin/options.py:809 contrib/admin/options.py:1011
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(name)s object with primary key %(key)r does not exist."
|
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."
|
msgstr "No existèix cap objecte %(name)s amb la clau primària %(key)r."
|
||||||
|
|
||||||
#: contrib/admin/options.py:860
|
#: contrib/admin/options.py:866
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Change %s"
|
msgid "Change %s"
|
||||||
msgstr "Modificar %s"
|
msgstr "Modificar %s"
|
||||||
|
|
||||||
#: contrib/admin/options.py:904
|
#: contrib/admin/options.py:910
|
||||||
msgid "Database error"
|
msgid "Database error"
|
||||||
msgstr "Error de base de dades"
|
msgstr "Error de base de dades"
|
||||||
|
|
||||||
#: contrib/admin/options.py:940
|
#: contrib/admin/options.py:946
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(count)s %(name)s was changed successfully."
|
msgid "%(count)s %(name)s was changed successfully."
|
||||||
msgid_plural "%(count)s %(name)s were changed successfully."
|
msgid_plural "%(count)s %(name)s were changed successfully."
|
||||||
msgstr[0] "%(count)s %(name)s s'ha modificat amb èxit."
|
msgstr[0] "%(count)s %(name)s s'ha modificat amb èxit."
|
||||||
msgstr[1] "%(count)s %(name)s s'han modificat amb èxit."
|
msgstr[1] "%(count)s %(name)s s'han modificat amb èxit."
|
||||||
|
|
||||||
#: contrib/admin/options.py:1018
|
#: contrib/admin/options.py:1026
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The %(name)s \"%(obj)s\" was deleted successfully."
|
msgid "The %(name)s \"%(obj)s\" was deleted successfully."
|
||||||
msgstr "El/la %(name)s \"%(obj)s\" ha estat eliminat amb èxit."
|
msgstr "El/la %(name)s \"%(obj)s\" ha estat eliminat amb èxit."
|
||||||
|
|
||||||
#: contrib/admin/options.py:1054
|
#: contrib/admin/options.py:1063
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Change history: %s"
|
msgid "Change history: %s"
|
||||||
msgstr "Modificar històric: %s"
|
msgstr "Modificar històric: %s"
|
||||||
|
|
||||||
#: contrib/admin/sites.py:20 contrib/admin/views/decorators.py:14
|
#: contrib/admin/sites.py:22 contrib/admin/views/decorators.py:14
|
||||||
#: contrib/auth/forms.py:80
|
#: contrib/auth/forms.py:80
|
||||||
msgid ""
|
msgid ""
|
||||||
"Please enter a correct username and password. Note that both fields are case-"
|
"Please enter a correct username and password. Note that both fields are case-"
|
||||||
@ -417,11 +417,11 @@ msgstr ""
|
|||||||
"Si us plau, introduïu un nom d'usuari i contrasenya vàlids. Tingueu en "
|
"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."
|
"compte que tots dos camps son sensibles a majúscules i minúscules."
|
||||||
|
|
||||||
#: contrib/admin/sites.py:278 contrib/admin/views/decorators.py:40
|
#: contrib/admin/sites.py:292 contrib/admin/views/decorators.py:40
|
||||||
msgid "Please log in again, because your session has expired."
|
msgid "Please log in again, because your session has expired."
|
||||||
msgstr "Si us plau, identifiqueu-vos de nou doncs la vostra sessió ha expirat."
|
msgstr "Si us plau, identifiqueu-vos de nou doncs la vostra sessió ha expirat."
|
||||||
|
|
||||||
#: contrib/admin/sites.py:285 contrib/admin/views/decorators.py:47
|
#: contrib/admin/sites.py:299 contrib/admin/views/decorators.py:47
|
||||||
msgid ""
|
msgid ""
|
||||||
"Looks like your browser isn't configured to accept cookies. Please enable "
|
"Looks like your browser isn't configured to accept cookies. Please enable "
|
||||||
"cookies, reload this page, and try again."
|
"cookies, reload this page, and try again."
|
||||||
@ -430,29 +430,29 @@ msgstr ""
|
|||||||
"'cookies' (galetes). Si us plau, habiliteu les 'cookies', recarregueu "
|
"'cookies' (galetes). Si us plau, habiliteu les 'cookies', recarregueu "
|
||||||
"aquesta pàgina i proveu-ho de nou. "
|
"aquesta pàgina i proveu-ho de nou. "
|
||||||
|
|
||||||
#: contrib/admin/sites.py:301 contrib/admin/sites.py:307
|
#: contrib/admin/sites.py:315 contrib/admin/sites.py:321
|
||||||
#: contrib/admin/views/decorators.py:66
|
#: contrib/admin/views/decorators.py:66
|
||||||
msgid "Usernames cannot contain the '@' character."
|
msgid "Usernames cannot contain the '@' character."
|
||||||
msgstr "Els noms d'usuari no poden contenir el caracter '@'."
|
msgstr "Els noms d'usuari no poden contenir el caracter '@'."
|
||||||
|
|
||||||
#: contrib/admin/sites.py:304 contrib/admin/views/decorators.py:62
|
#: contrib/admin/sites.py:318 contrib/admin/views/decorators.py:62
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Your e-mail address is not your username. Try '%s' instead."
|
msgid "Your e-mail address is not your username. Try '%s' instead."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"La vostra adreça de correu no és el vostre nom d'usuari. Provi '%s' en tot "
|
"La vostra adreça de correu no és el vostre nom d'usuari. Provi '%s' en tot "
|
||||||
"cas."
|
"cas."
|
||||||
|
|
||||||
#: contrib/admin/sites.py:360
|
#: contrib/admin/sites.py:374
|
||||||
msgid "Site administration"
|
msgid "Site administration"
|
||||||
msgstr "Lloc administratiu"
|
msgstr "Lloc administratiu"
|
||||||
|
|
||||||
#: contrib/admin/sites.py:373 contrib/admin/templates/admin/login.html:26
|
#: contrib/admin/sites.py:388 contrib/admin/templates/admin/login.html:26
|
||||||
#: contrib/admin/templates/registration/password_reset_complete.html:14
|
#: contrib/admin/templates/registration/password_reset_complete.html:14
|
||||||
#: contrib/admin/views/decorators.py:20
|
#: contrib/admin/views/decorators.py:20
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Iniciar sessió"
|
msgstr "Iniciar sessió"
|
||||||
|
|
||||||
#: contrib/admin/sites.py:417
|
#: contrib/admin/sites.py:433
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%s administration"
|
msgid "%s administration"
|
||||||
msgstr "Administració de %s"
|
msgstr "Administració de %s"
|
||||||
@ -467,27 +467,27 @@ msgstr "Un o més %(fieldname)s en %(name)s: %(obj)s"
|
|||||||
msgid "One or more %(fieldname)s in %(name)s:"
|
msgid "One or more %(fieldname)s in %(name)s:"
|
||||||
msgstr "Un o més %(fieldname)s en %(name)s:"
|
msgstr "Un o més %(fieldname)s en %(name)s:"
|
||||||
|
|
||||||
#: contrib/admin/widgets.py:71
|
#: contrib/admin/widgets.py:72
|
||||||
msgid "Date:"
|
msgid "Date:"
|
||||||
msgstr "Data:"
|
msgstr "Data:"
|
||||||
|
|
||||||
#: contrib/admin/widgets.py:71
|
#: contrib/admin/widgets.py:72
|
||||||
msgid "Time:"
|
msgid "Time:"
|
||||||
msgstr "Hora:"
|
msgstr "Hora:"
|
||||||
|
|
||||||
#: contrib/admin/widgets.py:95
|
#: contrib/admin/widgets.py:96
|
||||||
msgid "Currently:"
|
msgid "Currently:"
|
||||||
msgstr "Actualment:"
|
msgstr "Actualment:"
|
||||||
|
|
||||||
#: contrib/admin/widgets.py:95
|
#: contrib/admin/widgets.py:96
|
||||||
msgid "Change:"
|
msgid "Change:"
|
||||||
msgstr "Modificar:"
|
msgstr "Modificar:"
|
||||||
|
|
||||||
#: contrib/admin/widgets.py:124
|
#: contrib/admin/widgets.py:125
|
||||||
msgid "Lookup"
|
msgid "Lookup"
|
||||||
msgstr "Cercar"
|
msgstr "Cercar"
|
||||||
|
|
||||||
#: contrib/admin/widgets.py:236
|
#: contrib/admin/widgets.py:237
|
||||||
msgid "Add Another"
|
msgid "Add Another"
|
||||||
msgstr "Afegir un altre"
|
msgstr "Afegir un altre"
|
||||||
|
|
||||||
@ -502,7 +502,7 @@ 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/500.html:4
|
||||||
#: contrib/admin/templates/admin/app_index.html:8
|
#: contrib/admin/templates/admin/app_index.html:8
|
||||||
#: contrib/admin/templates/admin/base.html:31
|
#: contrib/admin/templates/admin/base.html:54
|
||||||
#: contrib/admin/templates/admin/change_form.html:17
|
#: contrib/admin/templates/admin/change_form.html:17
|
||||||
#: contrib/admin/templates/admin/change_list.html:25
|
#: contrib/admin/templates/admin/change_list.html:25
|
||||||
#: contrib/admin/templates/admin/delete_confirmation.html:6
|
#: contrib/admin/templates/admin/delete_confirmation.html:6
|
||||||
@ -555,18 +555,18 @@ msgstr "Anar"
|
|||||||
msgid "%(name)s"
|
msgid "%(name)s"
|
||||||
msgstr "%(name)s"
|
msgstr "%(name)s"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin/base.html:26
|
#: contrib/admin/templates/admin/base.html:27
|
||||||
msgid "Welcome,"
|
msgid "Welcome,"
|
||||||
msgstr "Benvingut/da,"
|
msgstr "Benvingut/da,"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin/base.html:26
|
#: contrib/admin/templates/admin/base.html:32
|
||||||
#: contrib/admin/templates/registration/password_change_done.html:3
|
#: contrib/admin/templates/registration/password_change_done.html:3
|
||||||
#: contrib/admin/templates/registration/password_change_form.html:3
|
#: contrib/admin/templates/registration/password_change_form.html:3
|
||||||
#: contrib/admindocs/templates/admin_doc/bookmarklets.html:3
|
#: contrib/admindocs/templates/admin_doc/bookmarklets.html:3
|
||||||
msgid "Documentation"
|
msgid "Documentation"
|
||||||
msgstr "Documentació"
|
msgstr "Documentació"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin/base.html:26
|
#: contrib/admin/templates/admin/base.html:40
|
||||||
#: contrib/admin/templates/admin/auth/user/change_password.html:14
|
#: contrib/admin/templates/admin/auth/user/change_password.html:14
|
||||||
#: contrib/admin/templates/admin/auth/user/change_password.html:47
|
#: 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_done.html:3
|
||||||
@ -574,7 +574,7 @@ msgstr "Documentació"
|
|||||||
msgid "Change password"
|
msgid "Change password"
|
||||||
msgstr "Canviar contrasenya"
|
msgstr "Canviar contrasenya"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin/base.html:26
|
#: contrib/admin/templates/admin/base.html:47
|
||||||
#: contrib/admin/templates/registration/password_change_done.html:3
|
#: contrib/admin/templates/registration/password_change_done.html:3
|
||||||
#: contrib/admin/templates/registration/password_change_form.html:3
|
#: contrib/admin/templates/registration/password_change_form.html:3
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
@ -600,7 +600,7 @@ msgstr "Històric"
|
|||||||
|
|
||||||
#: contrib/admin/templates/admin/change_form.html:28
|
#: contrib/admin/templates/admin/change_form.html:28
|
||||||
#: contrib/admin/templates/admin/edit_inline/stacked.html:13
|
#: contrib/admin/templates/admin/edit_inline/stacked.html:13
|
||||||
#: contrib/admin/templates/admin/edit_inline/tabular.html:27
|
#: contrib/admin/templates/admin/edit_inline/tabular.html:28
|
||||||
msgid "View on site"
|
msgid "View on site"
|
||||||
msgstr "Veure al lloc"
|
msgstr "Veure al lloc"
|
||||||
|
|
||||||
@ -670,9 +670,9 @@ msgstr ""
|
|||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure you want to delete the selected %(object_name)s objects? All of "
|
"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:"
|
"the following objects and their related items will be deleted:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Esteu segurs de voler esborrar els/les %(object_name)s seleccionats?Tots "
|
"Esteu segurs de voler esborrar els/les %(object_name)s seleccionats? Tots "
|
||||||
"aquests objectes i els seus elements relacionats s'esborraran:"
|
"aquests objectes i els seus elements relacionats s'esborraran:"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin/filter.html:2
|
#: contrib/admin/templates/admin/filter.html:2
|
||||||
@ -736,7 +736,6 @@ msgid "User"
|
|||||||
msgstr "Usuari"
|
msgstr "Usuari"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin/object_history.html:24
|
#: contrib/admin/templates/admin/object_history.html:24
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:33
|
|
||||||
msgid "Action"
|
msgid "Action"
|
||||||
msgstr "Acció"
|
msgstr "Acció"
|
||||||
|
|
||||||
@ -985,7 +984,7 @@ msgstr "Adreça de correu electrònic:"
|
|||||||
msgid "Reset my password"
|
msgid "Reset my password"
|
||||||
msgstr "Restablir la meva contrasenya"
|
msgstr "Restablir la meva contrasenya"
|
||||||
|
|
||||||
#: contrib/admin/templatetags/admin_list.py:299
|
#: contrib/admin/templatetags/admin_list.py:304
|
||||||
msgid "All dates"
|
msgid "All dates"
|
||||||
msgstr "Totes les dates"
|
msgstr "Totes les dates"
|
||||||
|
|
||||||
@ -1007,145 +1006,144 @@ msgstr "lloc"
|
|||||||
msgid "template"
|
msgid "template"
|
||||||
msgstr "plantilla"
|
msgstr "plantilla"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:58 contrib/admindocs/views.py:60
|
#: contrib/admindocs/views.py:61 contrib/admindocs/views.py:63
|
||||||
#: contrib/admindocs/views.py:62
|
#: contrib/admindocs/views.py:65
|
||||||
msgid "tag:"
|
msgid "tag:"
|
||||||
msgstr "etiqueta:"
|
msgstr "etiqueta:"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:91 contrib/admindocs/views.py:93
|
#: contrib/admindocs/views.py:94 contrib/admindocs/views.py:96
|
||||||
#: contrib/admindocs/views.py:95
|
#: contrib/admindocs/views.py:98
|
||||||
msgid "filter:"
|
msgid "filter:"
|
||||||
msgstr "filtre:"
|
msgstr "filtre:"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:155 contrib/admindocs/views.py:157
|
#: contrib/admindocs/views.py:158 contrib/admindocs/views.py:160
|
||||||
#: contrib/admindocs/views.py:159
|
#: contrib/admindocs/views.py:162
|
||||||
msgid "view:"
|
msgid "view:"
|
||||||
msgstr "vista:"
|
msgstr "vista:"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:187
|
#: contrib/admindocs/views.py:190
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "App %r not found"
|
msgid "App %r not found"
|
||||||
msgstr "No s'ha pogut trobar l'aplicació %r"
|
msgstr "No s'ha pogut trobar l'aplicació %r"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:194
|
#: contrib/admindocs/views.py:197
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Model %(model_name)r not found in app %(app_label)r"
|
msgid "Model %(model_name)r not found in app %(app_label)r"
|
||||||
msgstr "El model %(model_name)r no s'ha trobat en l'aplicació %(app_label)r"
|
msgstr "El model %(model_name)r no s'ha trobat en l'aplicació %(app_label)r"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:206
|
#: contrib/admindocs/views.py:209
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "the related `%(app_label)s.%(data_type)s` object"
|
msgid "the related `%(app_label)s.%(data_type)s` object"
|
||||||
msgstr "l'objecte relacionat `%(app_label)s.%(data_type)s`"
|
msgstr "l'objecte relacionat `%(app_label)s.%(data_type)s`"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:206 contrib/admindocs/views.py:225
|
#: contrib/admindocs/views.py:209 contrib/admindocs/views.py:228
|
||||||
#: contrib/admindocs/views.py:230 contrib/admindocs/views.py:244
|
#: contrib/admindocs/views.py:233 contrib/admindocs/views.py:247
|
||||||
#: contrib/admindocs/views.py:258 contrib/admindocs/views.py:263
|
#: contrib/admindocs/views.py:261 contrib/admindocs/views.py:266
|
||||||
msgid "model:"
|
msgid "model:"
|
||||||
msgstr "model:"
|
msgstr "model:"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:221 contrib/admindocs/views.py:253
|
#: contrib/admindocs/views.py:224 contrib/admindocs/views.py:256
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "related `%(app_label)s.%(object_name)s` objects"
|
msgid "related `%(app_label)s.%(object_name)s` objects"
|
||||||
msgstr "objectes relacionats `%(app_label)s.%(object_name)s`"
|
msgstr "objectes relacionats `%(app_label)s.%(object_name)s`"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:225 contrib/admindocs/views.py:258
|
#: contrib/admindocs/views.py:228 contrib/admindocs/views.py:261
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "all %s"
|
msgid "all %s"
|
||||||
msgstr "tots %s"
|
msgstr "tots %s"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:230 contrib/admindocs/views.py:263
|
#: contrib/admindocs/views.py:233 contrib/admindocs/views.py:266
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "number of %s"
|
msgid "number of %s"
|
||||||
msgstr "nombre de %s"
|
msgstr "nombre de %s"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:268
|
#: contrib/admindocs/views.py:271
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Fields on %s objects"
|
msgid "Fields on %s objects"
|
||||||
msgstr "Camps en objectes %s"
|
msgstr "Camps en objectes %s"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:331 contrib/admindocs/views.py:342
|
#: contrib/admindocs/views.py:334 contrib/admindocs/views.py:345
|
||||||
#: contrib/admindocs/views.py:344 contrib/admindocs/views.py:350
|
#: contrib/admindocs/views.py:347 contrib/admindocs/views.py:353
|
||||||
#: contrib/admindocs/views.py:351 contrib/admindocs/views.py:353
|
#: contrib/admindocs/views.py:354 contrib/admindocs/views.py:356
|
||||||
msgid "Integer"
|
msgid "Integer"
|
||||||
msgstr "Enter"
|
msgstr "Enter"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:332
|
#: contrib/admindocs/views.py:335
|
||||||
msgid "Boolean (Either True or False)"
|
msgid "Boolean (Either True or False)"
|
||||||
msgstr "Booleà (Verdader o Fals)"
|
msgstr "Booleà (Verdader o Fals)"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:333 contrib/admindocs/views.py:352
|
#: contrib/admindocs/views.py:336 contrib/admindocs/views.py:355
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "String (up to %(max_length)s)"
|
msgid "String (up to %(max_length)s)"
|
||||||
msgstr "Cadena (de fins a %(max_length)s)"
|
msgstr "Cadena (de fins a %(max_length)s)"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:334
|
#: contrib/admindocs/views.py:337
|
||||||
msgid "Comma-separated integers"
|
msgid "Comma-separated integers"
|
||||||
msgstr "Enters separats per comes"
|
msgstr "Enters separats per comes"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:335
|
#: contrib/admindocs/views.py:338
|
||||||
msgid "Date (without time)"
|
msgid "Date (without time)"
|
||||||
msgstr "Data (sense hora)"
|
msgstr "Data (sense hora)"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:336
|
#: contrib/admindocs/views.py:339
|
||||||
msgid "Date (with time)"
|
msgid "Date (with time)"
|
||||||
msgstr "Data (amb hora)"
|
msgstr "Data (amb hora)"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:337
|
#: contrib/admindocs/views.py:340
|
||||||
msgid "Decimal number"
|
msgid "Decimal number"
|
||||||
msgstr "Número decimal"
|
msgstr "Número decimal"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:338
|
#: contrib/admindocs/views.py:341
|
||||||
msgid "E-mail address"
|
msgid "E-mail address"
|
||||||
msgstr "Adreça de correu electrònic"
|
msgstr "Adreça de correu electrònic"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:339 contrib/admindocs/views.py:340
|
#: contrib/admindocs/views.py:342 contrib/admindocs/views.py:343
|
||||||
#: contrib/admindocs/views.py:343
|
#: contrib/admindocs/views.py:346
|
||||||
msgid "File path"
|
msgid "File path"
|
||||||
msgstr "Ruta del fitxer"
|
msgstr "Ruta del fitxer"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:341
|
#: contrib/admindocs/views.py:344
|
||||||
msgid "Floating point number"
|
msgid "Floating point number"
|
||||||
msgstr "Número amb punt de coma flotant"
|
msgstr "Número amb punt de coma flotant"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:345 contrib/comments/models.py:60
|
#: contrib/admindocs/views.py:348 contrib/comments/models.py:60
|
||||||
msgid "IP address"
|
msgid "IP address"
|
||||||
msgstr "Adreça IP"
|
msgstr "Adreça IP"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:347
|
#: contrib/admindocs/views.py:350
|
||||||
msgid "Boolean (Either True, False or None)"
|
msgid "Boolean (Either True, False or None)"
|
||||||
msgstr "Booleà (Verdader, Fals o 'None' (cap))"
|
msgstr "Booleà (Verdader, Fals o 'None' (cap))"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:348
|
#: contrib/admindocs/views.py:351
|
||||||
msgid "Relation to parent model"
|
msgid "Relation to parent model"
|
||||||
msgstr "Relació amb el model pare"
|
msgstr "Relació amb el model pare"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:349
|
#: contrib/admindocs/views.py:352
|
||||||
msgid "Phone number"
|
msgid "Phone number"
|
||||||
msgstr "Número de telèfon"
|
msgstr "Número de telèfon"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:354
|
#: contrib/admindocs/views.py:357
|
||||||
msgid "Text"
|
msgid "Text"
|
||||||
msgstr "Text"
|
msgstr "Text"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:355
|
#: contrib/admindocs/views.py:358
|
||||||
msgid "Time"
|
msgid "Time"
|
||||||
msgstr "Hora"
|
msgstr "Hora"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:356 contrib/comments/forms.py:95
|
#: contrib/admindocs/views.py:359 contrib/comments/forms.py:95
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:37
|
|
||||||
#: contrib/flatpages/admin.py:8 contrib/flatpages/models.py:7
|
#: contrib/flatpages/admin.py:8 contrib/flatpages/models.py:7
|
||||||
msgid "URL"
|
msgid "URL"
|
||||||
msgstr "URL"
|
msgstr "URL"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:357
|
#: contrib/admindocs/views.py:360
|
||||||
msgid "U.S. state (two uppercase letters)"
|
msgid "U.S. state (two uppercase letters)"
|
||||||
msgstr "Estat dels E.U.A. (dues lletres majúscules)"
|
msgstr "Estat dels E.U.A. (dues lletres majúscules)"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:358
|
#: contrib/admindocs/views.py:361
|
||||||
msgid "XML text"
|
msgid "XML text"
|
||||||
msgstr "Text XML"
|
msgstr "Text XML"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:384
|
#: contrib/admindocs/views.py:387
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%s does not appear to be a urlpattern object"
|
msgid "%s does not appear to be a urlpattern object"
|
||||||
msgstr "%s no sembla ser un objecte 'urlpattern'"
|
msgstr "%s no sembla ser un objecte 'urlpattern'"
|
||||||
@ -1438,22 +1436,54 @@ msgstr "usuaris"
|
|||||||
msgid "message"
|
msgid "message"
|
||||||
msgstr "missatge"
|
msgstr "missatge"
|
||||||
|
|
||||||
#: contrib/auth/views.py:56
|
#: contrib/auth/views.py:60
|
||||||
msgid "Logged out"
|
msgid "Logged out"
|
||||||
msgstr "Sessió finalitzada"
|
msgstr "Sessió finalitzada"
|
||||||
|
|
||||||
#: contrib/auth/management/commands/createsuperuser.py:23 forms/fields.py:429
|
#: contrib/auth/management/commands/createsuperuser.py:23 forms/fields.py:428
|
||||||
msgid "Enter a valid e-mail address."
|
msgid "Enter a valid e-mail address."
|
||||||
msgstr "Introduïu una adreça de correu vàlida."
|
msgstr "Introduïu una adreça de correu vàlida."
|
||||||
|
|
||||||
#: contrib/comments/admin.py:11
|
#: contrib/comments/admin.py:12
|
||||||
msgid "Content"
|
msgid "Content"
|
||||||
msgstr "contingut"
|
msgstr "contingut"
|
||||||
|
|
||||||
#: contrib/comments/admin.py:14
|
#: contrib/comments/admin.py:15
|
||||||
msgid "Metadata"
|
msgid "Metadata"
|
||||||
msgstr "metadades"
|
msgstr "metadades"
|
||||||
|
|
||||||
|
# Context problem... waitting for comments from django-i18n
|
||||||
|
#: contrib/comments/admin.py:39
|
||||||
|
msgid "flagged"
|
||||||
|
msgstr "marcat"
|
||||||
|
|
||||||
|
#: contrib/comments/admin.py:40
|
||||||
|
msgid "Flag selected comments"
|
||||||
|
msgstr "Marcar els comentaris seleccionats"
|
||||||
|
|
||||||
|
#: contrib/comments/admin.py:43
|
||||||
|
msgid "approved"
|
||||||
|
msgstr "aprovat"
|
||||||
|
|
||||||
|
#: contrib/comments/admin.py:44
|
||||||
|
msgid "Approve selected comments"
|
||||||
|
msgstr "Aprovar els comentaris seleccionats"
|
||||||
|
|
||||||
|
#: contrib/comments/admin.py:47
|
||||||
|
msgid "removed"
|
||||||
|
msgstr "eliminat"
|
||||||
|
|
||||||
|
#: contrib/comments/admin.py:48
|
||||||
|
msgid "Remove selected comments"
|
||||||
|
msgstr "Eliminar els comentaris seleccionats"
|
||||||
|
|
||||||
|
#: contrib/comments/admin.py:60
|
||||||
|
#, python-format
|
||||||
|
msgid "1 comment was successfully %(action)s."
|
||||||
|
msgid_plural "%(count)s comments were successfully %(action)s."
|
||||||
|
msgstr[0] "1 comentari ha estat %(action)s satisfactòriament."
|
||||||
|
msgstr[1] "%(count)s comentaris han estat %(action)s satisfactòriament."
|
||||||
|
|
||||||
#: contrib/comments/feeds.py:13
|
#: contrib/comments/feeds.py:13
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(site_name)s comments"
|
msgid "%(site_name)s comments"
|
||||||
@ -1465,7 +1495,6 @@ msgid "Latest comments on %(site_name)s"
|
|||||||
msgstr "Últims comentaris a %(site_name)s."
|
msgstr "Últims comentaris a %(site_name)s."
|
||||||
|
|
||||||
#: contrib/comments/forms.py:93
|
#: contrib/comments/forms.py:93
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:34
|
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "nom"
|
msgstr "nom"
|
||||||
|
|
||||||
@ -1474,7 +1503,6 @@ msgid "Email address"
|
|||||||
msgstr "Adreça de correu electrònic"
|
msgstr "Adreça de correu electrònic"
|
||||||
|
|
||||||
#: contrib/comments/forms.py:96
|
#: contrib/comments/forms.py:96
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:35
|
|
||||||
msgid "Comment"
|
msgid "Comment"
|
||||||
msgstr "Comentari"
|
msgstr "Comentari"
|
||||||
|
|
||||||
@ -1606,7 +1634,6 @@ msgid "Really make this comment public?"
|
|||||||
msgstr "Realment vol fer aquest comentari públic?"
|
msgstr "Realment vol fer aquest comentari públic?"
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/approve.html:12
|
#: contrib/comments/templates/comments/approve.html:12
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:49
|
|
||||||
msgid "Approve"
|
msgid "Approve"
|
||||||
msgstr "Aprovar"
|
msgstr "Aprovar"
|
||||||
|
|
||||||
@ -1631,7 +1658,6 @@ msgid "Really remove this comment?"
|
|||||||
msgstr "Realment vol eliminar aquest comentari?"
|
msgstr "Realment vol eliminar aquest comentari?"
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/delete.html:12
|
#: contrib/comments/templates/comments/delete.html:12
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:53
|
|
||||||
msgid "Remove"
|
msgid "Remove"
|
||||||
msgstr "Eliminar"
|
msgstr "Eliminar"
|
||||||
|
|
||||||
@ -1666,39 +1692,6 @@ msgstr "Publicar"
|
|||||||
msgid "Preview"
|
msgid "Preview"
|
||||||
msgstr "Vista prèvia"
|
msgstr "Vista prèvia"
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:4
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:19
|
|
||||||
msgid "Comment moderation queue"
|
|
||||||
msgstr "Cua de moderació de comentaris"
|
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:26
|
|
||||||
msgid "No comments to moderate"
|
|
||||||
msgstr "No hi ha comentaris per a moderar"
|
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:36
|
|
||||||
msgid "Email"
|
|
||||||
msgstr "Correu electrònic"
|
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:38
|
|
||||||
msgid "Authenticated?"
|
|
||||||
msgstr "Autentificat?"
|
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:39
|
|
||||||
msgid "IP Address"
|
|
||||||
msgstr "Adreça IP"
|
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:40
|
|
||||||
msgid "Date posted"
|
|
||||||
msgstr "Data d'enviament"
|
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:63
|
|
||||||
msgid "yes"
|
|
||||||
msgstr "si"
|
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:63
|
|
||||||
msgid "no"
|
|
||||||
msgstr "no"
|
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/posted.html:4
|
#: contrib/comments/templates/comments/posted.html:4
|
||||||
msgid "Thanks for commenting"
|
msgid "Thanks for commenting"
|
||||||
msgstr "Gràcies per comentar"
|
msgstr "Gràcies per comentar"
|
||||||
@ -1793,7 +1786,7 @@ msgstr "pàgina estàtica"
|
|||||||
msgid "flat pages"
|
msgid "flat pages"
|
||||||
msgstr "pàgines estàtiques"
|
msgstr "pàgines estàtiques"
|
||||||
|
|
||||||
#: contrib/formtools/wizard.py:130
|
#: contrib/formtools/wizard.py:132
|
||||||
msgid ""
|
msgid ""
|
||||||
"We apologize, but your form has expired. Please continue filling out the "
|
"We apologize, but your form has expired. Please continue filling out the "
|
||||||
"form from this page."
|
"form from this page."
|
||||||
@ -2615,6 +2608,10 @@ msgstr "Validació invàlida del número de compte bancari."
|
|||||||
msgid "Enter a valid Finnish social security number."
|
msgid "Enter a valid Finnish social security number."
|
||||||
msgstr "Introduïu un número vàlid de la seguretat social finlandesa."
|
msgstr "Introduïu un número vàlid de la seguretat social finlandesa."
|
||||||
|
|
||||||
|
#: contrib/localflavor/fr/forms.py:30
|
||||||
|
msgid "Phone numbers must be in 0X XX XX XX XX format."
|
||||||
|
msgstr "Els números de telèfon han de estar en el format 0X XX XX XX XX."
|
||||||
|
|
||||||
#: contrib/localflavor/in_/forms.py:14
|
#: contrib/localflavor/in_/forms.py:14
|
||||||
msgid "Enter a zip code in the format XXXXXXX."
|
msgid "Enter a zip code in the format XXXXXXX."
|
||||||
msgstr "Introduïu un codi zip en el format XXXXXXX."
|
msgstr "Introduïu un codi zip en el format XXXXXXX."
|
||||||
@ -3053,7 +3050,8 @@ msgstr "Validació invàlida del número tributari (NIP)."
|
|||||||
#: contrib/localflavor/pl/forms.py:109
|
#: contrib/localflavor/pl/forms.py:109
|
||||||
msgid "National Business Register Number (REGON) consists of 9 or 14 digits."
|
msgid "National Business Register Number (REGON) consists of 9 or 14 digits."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"El número nacional de registre de negocis (REGON) consisteix en 9 o 14 dígits."
|
"El número nacional de registre de negocis (REGON) consisteix en 9 o 14 "
|
||||||
|
"dígits."
|
||||||
|
|
||||||
#: contrib/localflavor/pl/forms.py:110
|
#: contrib/localflavor/pl/forms.py:110
|
||||||
msgid "Wrong checksum for the National Business Register Number (REGON)."
|
msgid "Wrong checksum for the National Business Register Number (REGON)."
|
||||||
@ -3943,14 +3941,14 @@ msgstr "Aquest valor ha de ser None (Cap), True (Veritat) o False (Fals)"
|
|||||||
msgid "Enter a valid time in HH:MM[:ss[.uuuuuu]] format."
|
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]]."
|
msgstr "Introduïu una hora vàlida en el format HH:MM[:ss[.uuuuuu]]."
|
||||||
|
|
||||||
#: db/models/fields/related.py:816
|
#: db/models/fields/related.py:869
|
||||||
msgid ""
|
msgid ""
|
||||||
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
|
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Premeu la tecla \"Control\" -o \"Command\" en un Mac- per seleccionar més "
|
"Premeu la tecla \"Control\" -o \"Command\" en un Mac- per seleccionar més "
|
||||||
"d'un valor."
|
"d'un valor."
|
||||||
|
|
||||||
#: db/models/fields/related.py:894
|
#: db/models/fields/related.py:930
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
|
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
|
||||||
msgid_plural ""
|
msgid_plural ""
|
||||||
@ -3962,95 +3960,95 @@ msgstr[1] ""
|
|||||||
"Si us plau, introduïu IDs de %(self)s vàlids. Els valors %(value)r són "
|
"Si us plau, introduïu IDs de %(self)s vàlids. Els valors %(value)r són "
|
||||||
"invàlids."
|
"invàlids."
|
||||||
|
|
||||||
#: forms/fields.py:54
|
#: forms/fields.py:53
|
||||||
msgid "This field is required."
|
msgid "This field is required."
|
||||||
msgstr "Aquest camp és obligatori."
|
msgstr "Aquest camp és obligatori."
|
||||||
|
|
||||||
#: forms/fields.py:55
|
#: forms/fields.py:54
|
||||||
msgid "Enter a valid value."
|
msgid "Enter a valid value."
|
||||||
msgstr "Introduïu un valor vàlid."
|
msgstr "Introduïu un valor vàlid."
|
||||||
|
|
||||||
#: forms/fields.py:138
|
#: forms/fields.py:137
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure this value has at most %(max)d characters (it has %(length)d)."
|
msgid "Ensure this value has at most %(max)d characters (it has %(length)d)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Assegureu-vos de que el valor té com a màxim %(max)d caràcters (en té %"
|
"Assegureu-vos de que el valor té com a màxim %(max)d caràcters (en té %"
|
||||||
"(length)d)."
|
"(length)d)."
|
||||||
|
|
||||||
#: forms/fields.py:139
|
#: forms/fields.py:138
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure this value has at least %(min)d characters (it has %(length)d)."
|
msgid "Ensure this value has at least %(min)d characters (it has %(length)d)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Assegureu-vos de que el valor té com a mínim %(min)d caràcters (en té %"
|
"Assegureu-vos de que el valor té com a mínim %(min)d caràcters (en té %"
|
||||||
"(length)d)."
|
"(length)d)."
|
||||||
|
|
||||||
#: forms/fields.py:166
|
#: forms/fields.py:165
|
||||||
msgid "Enter a whole number."
|
msgid "Enter a whole number."
|
||||||
msgstr "Introduïu un número sencer."
|
msgstr "Introduïu un número sencer."
|
||||||
|
|
||||||
#: forms/fields.py:167 forms/fields.py:196 forms/fields.py:225
|
#: forms/fields.py:166 forms/fields.py:195 forms/fields.py:224
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure this value is less than or equal to %s."
|
msgid "Ensure this value is less than or equal to %s."
|
||||||
msgstr "Aquest valor ha de ser menor o igual a %s."
|
msgstr "Aquest valor ha de ser menor o igual a %s."
|
||||||
|
|
||||||
#: forms/fields.py:168 forms/fields.py:197 forms/fields.py:226
|
#: forms/fields.py:167 forms/fields.py:196 forms/fields.py:225
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure this value is greater than or equal to %s."
|
msgid "Ensure this value is greater than or equal to %s."
|
||||||
msgstr "Assegureu-vos de que aquest valor sigui superior o igual a %s."
|
msgstr "Assegureu-vos de que aquest valor sigui superior o igual a %s."
|
||||||
|
|
||||||
#: forms/fields.py:195 forms/fields.py:224
|
#: forms/fields.py:194 forms/fields.py:223
|
||||||
msgid "Enter a number."
|
msgid "Enter a number."
|
||||||
msgstr "Introduïu un número."
|
msgstr "Introduïu un número."
|
||||||
|
|
||||||
#: forms/fields.py:227
|
#: forms/fields.py:226
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure that there are no more than %s digits in total."
|
msgid "Ensure that there are no more than %s digits in total."
|
||||||
msgstr "Assegureu-vos de que no hi ha més de %s dígits en total."
|
msgstr "Assegureu-vos de que no hi ha més de %s dígits en total."
|
||||||
|
|
||||||
#: forms/fields.py:228
|
#: forms/fields.py:227
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure that there are no more than %s decimal places."
|
msgid "Ensure that there are no more than %s decimal places."
|
||||||
msgstr "Assegureu-vos de que no hi ha més de %s decimals."
|
msgstr "Assegureu-vos de que no hi ha més de %s decimals."
|
||||||
|
|
||||||
#: forms/fields.py:229
|
#: forms/fields.py:228
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure that there are no more than %s digits before the decimal point."
|
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."
|
msgstr "Assegureu-vos de que no hi ha més de %s dígits decimals."
|
||||||
|
|
||||||
#: forms/fields.py:288 forms/fields.py:863
|
#: forms/fields.py:287 forms/fields.py:862
|
||||||
msgid "Enter a valid date."
|
msgid "Enter a valid date."
|
||||||
msgstr "Introduïu una data vàlida."
|
msgstr "Introduïu una data vàlida."
|
||||||
|
|
||||||
#: forms/fields.py:322 forms/fields.py:864
|
#: forms/fields.py:321 forms/fields.py:863
|
||||||
msgid "Enter a valid time."
|
msgid "Enter a valid time."
|
||||||
msgstr "Introduïu una hora vàlida."
|
msgstr "Introduïu una hora vàlida."
|
||||||
|
|
||||||
#: forms/fields.py:361
|
#: forms/fields.py:360
|
||||||
msgid "Enter a valid date/time."
|
msgid "Enter a valid date/time."
|
||||||
msgstr "Introduïu una data/hora vàlides."
|
msgstr "Introduïu una data/hora vàlides."
|
||||||
|
|
||||||
#: forms/fields.py:447
|
#: forms/fields.py:446
|
||||||
msgid "No file was submitted. Check the encoding type on the form."
|
msgid "No file was submitted. Check the encoding type on the form."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"No s'ha enviat cap fitxer. Comprovi el tipus de codificació del formulari."
|
"No s'ha enviat cap fitxer. Comprovi el tipus de codificació del formulari."
|
||||||
|
|
||||||
#: forms/fields.py:448
|
#: forms/fields.py:447
|
||||||
msgid "No file was submitted."
|
msgid "No file was submitted."
|
||||||
msgstr "No s'ha enviat cap fitxer."
|
msgstr "No s'ha enviat cap fitxer."
|
||||||
|
|
||||||
#: forms/fields.py:449
|
#: forms/fields.py:448
|
||||||
msgid "The submitted file is empty."
|
msgid "The submitted file is empty."
|
||||||
msgstr "El fitxer enviat està buit."
|
msgstr "El fitxer enviat està buit."
|
||||||
|
|
||||||
#: forms/fields.py:450
|
#: forms/fields.py:449
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Ensure this filename has at most %(max)d characters (it has %(length)d)."
|
"Ensure this filename has at most %(max)d characters (it has %(length)d)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Assegureu-vos de que el valor té com a màxim %(max)d caràcters "
|
"Assegureu-vos de que el valor té com a màxim %(max)d caràcters (en té %"
|
||||||
"(en té %(length)d)."
|
"(length)d)."
|
||||||
|
|
||||||
#: forms/fields.py:483
|
#: forms/fields.py:482
|
||||||
msgid ""
|
msgid ""
|
||||||
"Upload a valid image. The file you uploaded was either not an image or a "
|
"Upload a valid image. The file you uploaded was either not an image or a "
|
||||||
"corrupted image."
|
"corrupted image."
|
||||||
@ -4058,28 +4056,28 @@ msgstr ""
|
|||||||
"Envieu una imatge vàlida. El fitxer que heu enviat no era una imatge o "
|
"Envieu una imatge vàlida. El fitxer que heu enviat no era una imatge o "
|
||||||
"estava corrupte."
|
"estava corrupte."
|
||||||
|
|
||||||
#: forms/fields.py:544
|
#: forms/fields.py:543
|
||||||
msgid "Enter a valid URL."
|
msgid "Enter a valid URL."
|
||||||
msgstr "Introduïu una URL vàlida."
|
msgstr "Introduïu una URL vàlida."
|
||||||
|
|
||||||
#: forms/fields.py:545
|
#: forms/fields.py:544
|
||||||
msgid "This URL appears to be a broken link."
|
msgid "This URL appears to be a broken link."
|
||||||
msgstr "Aquesta URL sembla ser un enllaç trencat."
|
msgstr "Aquesta URL sembla ser un enllaç trencat."
|
||||||
|
|
||||||
#: forms/fields.py:625 forms/fields.py:703
|
#: forms/fields.py:624 forms/fields.py:702
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Select a valid choice. %(value)s is not one of the available choices."
|
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."
|
msgstr "Esculliu una opció vàlida. %(value)s no és una de les opcions vàlides."
|
||||||
|
|
||||||
#: forms/fields.py:704 forms/fields.py:765 forms/models.py:1003
|
#: forms/fields.py:703 forms/fields.py:764 forms/models.py:999
|
||||||
msgid "Enter a list of values."
|
msgid "Enter a list of values."
|
||||||
msgstr "Introduïu una llista de valors."
|
msgstr "Introduïu una llista de valors."
|
||||||
|
|
||||||
#: forms/fields.py:892
|
#: forms/fields.py:891
|
||||||
msgid "Enter a valid IPv4 address."
|
msgid "Enter a valid IPv4 address."
|
||||||
msgstr "Introduïu una adreça IPv4 vàlida."
|
msgstr "Introduïu una adreça IPv4 vàlida."
|
||||||
|
|
||||||
#: forms/fields.py:902
|
#: forms/fields.py:901
|
||||||
msgid ""
|
msgid ""
|
||||||
"Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."
|
"Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -4090,56 +4088,58 @@ msgstr ""
|
|||||||
msgid "Order"
|
msgid "Order"
|
||||||
msgstr "Ordre"
|
msgstr "Ordre"
|
||||||
|
|
||||||
#: forms/models.py:367
|
#: forms/models.py:363
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(field_name)s must be unique for %(date_field)s %(lookup)s."
|
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."
|
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
|
#: forms/models.py:377 forms/models.py:385
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(model_name)s with this %(field_label)s already exists."
|
msgid "%(model_name)s with this %(field_label)s already exists."
|
||||||
msgstr "Ja existeix %(model_name)s amb aquest %(field_label)s."
|
msgstr "Ja existeix %(model_name)s amb aquest %(field_label)s."
|
||||||
|
|
||||||
#: forms/models.py:594
|
#: forms/models.py:590
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please correct the duplicate data for %(field)s."
|
msgid "Please correct the duplicate data for %(field)s."
|
||||||
msgstr "Si us plau, corregiu la dada duplicada per a %(field)s."
|
msgstr "Si us plau, corregiu la dada duplicada per a %(field)s."
|
||||||
|
|
||||||
#: forms/models.py:598
|
#: forms/models.py:594
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please correct the duplicate data for %(field)s, which must be unique."
|
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."
|
msgstr ""
|
||||||
|
"Si us plau, corregiu la dada duplicada per a %(field)s, la qual ha de ser "
|
||||||
|
"única."
|
||||||
|
|
||||||
#: forms/models.py:604
|
#: forms/models.py:600
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Please correct the duplicate data for %(field_name)s which must be unique "
|
"Please correct the duplicate data for %(field_name)s which must be unique "
|
||||||
"for the %(lookup)s in %(date_field)s."
|
"for the %(lookup)s in %(date_field)s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Si us plau, corregiu la dada duplicada per a %(field_name)s, "
|
"Si us plau, corregiu la dada duplicada per a %(field_name)s, la qual ha de "
|
||||||
"la qual ha de ser única per a la cerca %(lookup)s en %(date_field)s."
|
"ser única per a la cerca %(lookup)s en %(date_field)s."
|
||||||
|
|
||||||
#: forms/models.py:612
|
#: forms/models.py:608
|
||||||
msgid "Please correct the duplicate values below."
|
msgid "Please correct the duplicate values below."
|
||||||
msgstr "Si us plau, corregiu els valors duplicats a baix."
|
msgstr "Si us plau, corregiu els valors duplicats a baix."
|
||||||
|
|
||||||
#: forms/models.py:867
|
#: forms/models.py:863
|
||||||
msgid "The inline foreign key did not match the parent instance primary key."
|
msgid "The inline foreign key did not match the parent instance primary key."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"La clau forànea en línea no coincideix amb la clau primària de la instància "
|
"La clau forànea en línea no coincideix amb la clau primària de la instància "
|
||||||
"del pare"
|
"del pare"
|
||||||
|
|
||||||
#: forms/models.py:930
|
#: forms/models.py:926
|
||||||
msgid "Select a valid choice. That choice is not one of the available choices."
|
msgid "Select a valid choice. That choice is not one of the available choices."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Escolli una opció vàlida; Aquesta opció no és una de les opcions disponibles."
|
"Escolli una opció vàlida; Aquesta opció no és una de les opcions disponibles."
|
||||||
|
|
||||||
#: forms/models.py:1004
|
#: forms/models.py:1000
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Select a valid choice. %s is not one of the available choices."
|
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."
|
msgstr "Escolliu una opció vàlida; %s' no és una de les opcions vàlides."
|
||||||
|
|
||||||
#: forms/models.py:1006
|
#: forms/models.py:1002
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "\"%s\" is not a valid value for a primary key."
|
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."
|
msgstr "\"%s\" no és un valor vàlid per a una clau primària."
|
||||||
@ -4459,6 +4459,30 @@ msgstr "El/la %(verbose_name)s s'ha actualtzat amb èxit."
|
|||||||
msgid "The %(verbose_name)s was deleted."
|
msgid "The %(verbose_name)s was deleted."
|
||||||
msgstr "El %(verbose_name)s s'ha eliminat."
|
msgstr "El %(verbose_name)s s'ha eliminat."
|
||||||
|
|
||||||
|
#~ msgid "Comment moderation queue"
|
||||||
|
#~ msgstr "Cua de moderació de comentaris"
|
||||||
|
|
||||||
|
#~ msgid "No comments to moderate"
|
||||||
|
#~ msgstr "No hi ha comentaris per a moderar"
|
||||||
|
|
||||||
|
#~ msgid "Email"
|
||||||
|
#~ msgstr "Correu electrònic"
|
||||||
|
|
||||||
|
#~ msgid "Authenticated?"
|
||||||
|
#~ msgstr "Autentificat?"
|
||||||
|
|
||||||
|
#~ msgid "IP Address"
|
||||||
|
#~ msgstr "Adreça IP"
|
||||||
|
|
||||||
|
#~ msgid "Date posted"
|
||||||
|
#~ msgstr "Data d'enviament"
|
||||||
|
|
||||||
|
#~ msgid "yes"
|
||||||
|
#~ msgstr "si"
|
||||||
|
|
||||||
|
#~ msgid "no"
|
||||||
|
#~ msgstr "no"
|
||||||
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#~ msgid "verbose_name"
|
#~ msgid "verbose_name"
|
||||||
#~ msgid_plural "verbose_name_plural"
|
#~ msgid_plural "verbose_name_plural"
|
||||||
|
Binary file not shown.
@ -5,8 +5,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Django\n"
|
"Project-Id-Version: Django\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2009-07-07 15:15+0200\n"
|
"POT-Creation-Date: 2009-11-30 11:27+0100\n"
|
||||||
"PO-Revision-Date: 2009-07-07 15:22+0200\n"
|
"PO-Revision-Date: 2009-11-30 11:31+0100\n"
|
||||||
"Last-Translator: Django Spanish Team <django-cat@googlegroups.com>Language-"
|
"Last-Translator: Django Spanish Team <django-cat@googlegroups.com>Language-"
|
||||||
"Team: Django Spanish Team <django-cat@googlegroups.com>MIME-Version: 1.0\n"
|
"Team: Django Spanish Team <django-cat@googlegroups.com>MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
@ -222,7 +222,7 @@ msgstr "chino tradicional"
|
|||||||
msgid "Successfully deleted %(count)d %(items)s."
|
msgid "Successfully deleted %(count)d %(items)s."
|
||||||
msgstr "Eliminado/s %(count)d %(items)s satisfactoriamente."
|
msgstr "Eliminado/s %(count)d %(items)s satisfactoriamente."
|
||||||
|
|
||||||
#: contrib/admin/actions.py:67 contrib/admin/options.py:1025
|
#: contrib/admin/actions.py:67 contrib/admin/options.py:1033
|
||||||
msgid "Are you sure?"
|
msgid "Are you sure?"
|
||||||
msgstr "¿Está seguro?"
|
msgstr "¿Está seguro?"
|
||||||
|
|
||||||
@ -265,15 +265,15 @@ msgstr "Este mes"
|
|||||||
msgid "This year"
|
msgid "This year"
|
||||||
msgstr "Este año"
|
msgstr "Este año"
|
||||||
|
|
||||||
#: contrib/admin/filterspecs.py:147 forms/widgets.py:434
|
#: contrib/admin/filterspecs.py:147 forms/widgets.py:435
|
||||||
msgid "Yes"
|
msgid "Yes"
|
||||||
msgstr "Sí"
|
msgstr "Sí"
|
||||||
|
|
||||||
#: contrib/admin/filterspecs.py:147 forms/widgets.py:434
|
#: contrib/admin/filterspecs.py:147 forms/widgets.py:435
|
||||||
msgid "No"
|
msgid "No"
|
||||||
msgstr "No"
|
msgstr "No"
|
||||||
|
|
||||||
#: contrib/admin/filterspecs.py:154 forms/widgets.py:434
|
#: contrib/admin/filterspecs.py:154 forms/widgets.py:435
|
||||||
msgid "Unknown"
|
msgid "Unknown"
|
||||||
msgstr "Desconocido"
|
msgstr "Desconocido"
|
||||||
|
|
||||||
@ -309,104 +309,104 @@ msgstr "entrada de registro"
|
|||||||
msgid "log entries"
|
msgid "log entries"
|
||||||
msgstr "entradas de registro"
|
msgstr "entradas de registro"
|
||||||
|
|
||||||
#: contrib/admin/options.py:133 contrib/admin/options.py:147
|
#: contrib/admin/options.py:134 contrib/admin/options.py:148
|
||||||
msgid "None"
|
msgid "None"
|
||||||
msgstr "Ninguno"
|
msgstr "Ninguno"
|
||||||
|
|
||||||
#: contrib/admin/options.py:519
|
#: contrib/admin/options.py:521
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Changed %s."
|
msgid "Changed %s."
|
||||||
msgstr "Modificado/a %s."
|
msgstr "Modificado/a %s."
|
||||||
|
|
||||||
#: contrib/admin/options.py:519 contrib/admin/options.py:529
|
#: contrib/admin/options.py:521 contrib/admin/options.py:531
|
||||||
#: contrib/comments/templates/comments/preview.html:16 forms/models.py:388
|
#: contrib/comments/templates/comments/preview.html:16 forms/models.py:384
|
||||||
#: forms/models.py:600
|
#: forms/models.py:596
|
||||||
msgid "and"
|
msgid "and"
|
||||||
msgstr "y"
|
msgstr "y"
|
||||||
|
|
||||||
#: contrib/admin/options.py:524
|
#: contrib/admin/options.py:526
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Added %(name)s \"%(object)s\"."
|
msgid "Added %(name)s \"%(object)s\"."
|
||||||
msgstr "Añadido/a \"%(object)s\" %(name)s."
|
msgstr "Añadido/a \"%(object)s\" %(name)s."
|
||||||
|
|
||||||
#: contrib/admin/options.py:528
|
#: contrib/admin/options.py:530
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Changed %(list)s for %(name)s \"%(object)s\"."
|
msgid "Changed %(list)s for %(name)s \"%(object)s\"."
|
||||||
msgstr "Modificados %(list)s para \"%(object)s\" %(name)s."
|
msgstr "Modificados %(list)s para \"%(object)s\" %(name)s."
|
||||||
|
|
||||||
#: contrib/admin/options.py:533
|
#: contrib/admin/options.py:535
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Deleted %(name)s \"%(object)s\"."
|
msgid "Deleted %(name)s \"%(object)s\"."
|
||||||
msgstr "Eliminado/a \"%(object)s\" %(name)s."
|
msgstr "Eliminado/a \"%(object)s\" %(name)s."
|
||||||
|
|
||||||
#: contrib/admin/options.py:537
|
#: contrib/admin/options.py:539
|
||||||
msgid "No fields changed."
|
msgid "No fields changed."
|
||||||
msgstr "No ha cambiado ningún campo."
|
msgstr "No ha cambiado ningún campo."
|
||||||
|
|
||||||
#: contrib/admin/options.py:598 contrib/auth/admin.py:67
|
#: contrib/admin/options.py:601 contrib/auth/admin.py:67
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The %(name)s \"%(obj)s\" was added successfully."
|
msgid "The %(name)s \"%(obj)s\" was added successfully."
|
||||||
msgstr "Se añadió con éxito el %(name)s \"%(obj)s\"."
|
msgstr "Se añadió con éxito el %(name)s \"%(obj)s\"."
|
||||||
|
|
||||||
#: contrib/admin/options.py:602 contrib/admin/options.py:635
|
#: contrib/admin/options.py:605 contrib/admin/options.py:638
|
||||||
#: contrib/auth/admin.py:75
|
#: contrib/auth/admin.py:75
|
||||||
msgid "You may edit it again below."
|
msgid "You may edit it again below."
|
||||||
msgstr "Puede editarlo de nuevo abajo."
|
msgstr "Puede editarlo de nuevo abajo."
|
||||||
|
|
||||||
#: contrib/admin/options.py:612 contrib/admin/options.py:645
|
#: contrib/admin/options.py:615 contrib/admin/options.py:648
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "You may add another %s below."
|
msgid "You may add another %s below."
|
||||||
msgstr "Puede añadir otro %s abajo."
|
msgstr "Puede añadir otro %s abajo."
|
||||||
|
|
||||||
#: contrib/admin/options.py:633
|
#: contrib/admin/options.py:636
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The %(name)s \"%(obj)s\" was changed successfully."
|
msgid "The %(name)s \"%(obj)s\" was changed successfully."
|
||||||
msgstr "Se modificó con éxito el %(name)s \"%(obj)s\"."
|
msgstr "Se modificó con éxito el %(name)s \"%(obj)s\"."
|
||||||
|
|
||||||
#: contrib/admin/options.py:641
|
#: contrib/admin/options.py:644
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
|
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Se añadió con éxito el %(name)s \"%(obj)s. Puede editarlo de nuevo abajo."
|
"Se añadió con éxito el %(name)s \"%(obj)s. Puede editarlo de nuevo abajo."
|
||||||
|
|
||||||
#: contrib/admin/options.py:772
|
#: contrib/admin/options.py:777
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Add %s"
|
msgid "Add %s"
|
||||||
msgstr "Añadir %s"
|
msgstr "Añadir %s"
|
||||||
|
|
||||||
#: contrib/admin/options.py:803 contrib/admin/options.py:1003
|
#: contrib/admin/options.py:809 contrib/admin/options.py:1011
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(name)s object with primary key %(key)r does not exist."
|
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."
|
msgstr "No existe ningún objeto %(name)s con la clave primaria %(key)r."
|
||||||
|
|
||||||
#: contrib/admin/options.py:860
|
#: contrib/admin/options.py:866
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Change %s"
|
msgid "Change %s"
|
||||||
msgstr "Modificar %s"
|
msgstr "Modificar %s"
|
||||||
|
|
||||||
#: contrib/admin/options.py:904
|
#: contrib/admin/options.py:910
|
||||||
msgid "Database error"
|
msgid "Database error"
|
||||||
msgstr "Error en la base de datos"
|
msgstr "Error en la base de datos"
|
||||||
|
|
||||||
#: contrib/admin/options.py:940
|
#: contrib/admin/options.py:946
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(count)s %(name)s was changed successfully."
|
msgid "%(count)s %(name)s was changed successfully."
|
||||||
msgid_plural "%(count)s %(name)s were changed successfully."
|
msgid_plural "%(count)s %(name)s were changed successfully."
|
||||||
msgstr[0] "%(count)s %(name)s fué modificado con éxito."
|
msgstr[0] "%(count)s %(name)s fué modificado con éxito."
|
||||||
msgstr[1] "%(count)s %(name)s fueron modificados con éxito."
|
msgstr[1] "%(count)s %(name)s fueron modificados con éxito."
|
||||||
|
|
||||||
#: contrib/admin/options.py:1018
|
#: contrib/admin/options.py:1026
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The %(name)s \"%(obj)s\" was deleted successfully."
|
msgid "The %(name)s \"%(obj)s\" was deleted successfully."
|
||||||
msgstr "Se eliminó con éxito el %(name)s \"%(obj)s\"."
|
msgstr "Se eliminó con éxito el %(name)s \"%(obj)s\"."
|
||||||
|
|
||||||
#: contrib/admin/options.py:1054
|
#: contrib/admin/options.py:1063
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Change history: %s"
|
msgid "Change history: %s"
|
||||||
msgstr "Histórico de modificaciones: %s"
|
msgstr "Histórico de modificaciones: %s"
|
||||||
|
|
||||||
#: contrib/admin/sites.py:20 contrib/admin/views/decorators.py:14
|
#: contrib/admin/sites.py:22 contrib/admin/views/decorators.py:14
|
||||||
#: contrib/auth/forms.py:80
|
#: contrib/auth/forms.py:80
|
||||||
msgid ""
|
msgid ""
|
||||||
"Please enter a correct username and password. Note that both fields are case-"
|
"Please enter a correct username and password. Note that both fields are case-"
|
||||||
@ -415,11 +415,11 @@ msgstr ""
|
|||||||
"Por favor, introduzca un nombre de usuario y contraseña correctos. Note que "
|
"Por favor, introduzca un nombre de usuario y contraseña correctos. Note que "
|
||||||
"ambos campos son sensibles a mayúsculas/minúsculas."
|
"ambos campos son sensibles a mayúsculas/minúsculas."
|
||||||
|
|
||||||
#: contrib/admin/sites.py:278 contrib/admin/views/decorators.py:40
|
#: contrib/admin/sites.py:292 contrib/admin/views/decorators.py:40
|
||||||
msgid "Please log in again, because your session has expired."
|
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."
|
msgstr "Por favor, inicie sesión de nuevo, ya que su sesión ha caducado."
|
||||||
|
|
||||||
#: contrib/admin/sites.py:285 contrib/admin/views/decorators.py:47
|
#: contrib/admin/sites.py:299 contrib/admin/views/decorators.py:47
|
||||||
msgid ""
|
msgid ""
|
||||||
"Looks like your browser isn't configured to accept cookies. Please enable "
|
"Looks like your browser isn't configured to accept cookies. Please enable "
|
||||||
"cookies, reload this page, and try again."
|
"cookies, reload this page, and try again."
|
||||||
@ -427,29 +427,29 @@ msgstr ""
|
|||||||
"Parece que su navegador no está configurado para aceptar cookies. "
|
"Parece que su navegador no está configurado para aceptar cookies. "
|
||||||
"Actívelas , recargue esta página, e inténtelo de nuevo."
|
"Actívelas , recargue esta página, e inténtelo de nuevo."
|
||||||
|
|
||||||
#: contrib/admin/sites.py:301 contrib/admin/sites.py:307
|
#: contrib/admin/sites.py:315 contrib/admin/sites.py:321
|
||||||
#: contrib/admin/views/decorators.py:66
|
#: contrib/admin/views/decorators.py:66
|
||||||
msgid "Usernames cannot contain the '@' character."
|
msgid "Usernames cannot contain the '@' character."
|
||||||
msgstr "Los nombres de usuario no pueden contener el carácter '@'."
|
msgstr "Los nombres de usuario no pueden contener el carácter '@'."
|
||||||
|
|
||||||
#: contrib/admin/sites.py:304 contrib/admin/views/decorators.py:62
|
#: contrib/admin/sites.py:318 contrib/admin/views/decorators.py:62
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Your e-mail address is not your username. Try '%s' instead."
|
msgid "Your e-mail address is not your username. Try '%s' instead."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Su dirección de correo no es su nombre de usuario. Pruebe con '%s' en su "
|
"Su dirección de correo no es su nombre de usuario. Pruebe con '%s' en su "
|
||||||
"lugar."
|
"lugar."
|
||||||
|
|
||||||
#: contrib/admin/sites.py:360
|
#: contrib/admin/sites.py:374
|
||||||
msgid "Site administration"
|
msgid "Site administration"
|
||||||
msgstr "Sitio administrativo"
|
msgstr "Sitio administrativo"
|
||||||
|
|
||||||
#: contrib/admin/sites.py:373 contrib/admin/templates/admin/login.html:26
|
#: contrib/admin/sites.py:388 contrib/admin/templates/admin/login.html:26
|
||||||
#: contrib/admin/templates/registration/password_reset_complete.html:14
|
#: contrib/admin/templates/registration/password_reset_complete.html:14
|
||||||
#: contrib/admin/views/decorators.py:20
|
#: contrib/admin/views/decorators.py:20
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Iniciar sesión"
|
msgstr "Iniciar sesión"
|
||||||
|
|
||||||
#: contrib/admin/sites.py:417
|
#: contrib/admin/sites.py:433
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%s administration"
|
msgid "%s administration"
|
||||||
msgstr "Administración de %s"
|
msgstr "Administración de %s"
|
||||||
@ -464,27 +464,27 @@ msgstr "Uno o más %(fieldname)s en %(name)s: %(obj)s"
|
|||||||
msgid "One or more %(fieldname)s in %(name)s:"
|
msgid "One or more %(fieldname)s in %(name)s:"
|
||||||
msgstr "Uno o más %(fieldname)s en %(name)s:"
|
msgstr "Uno o más %(fieldname)s en %(name)s:"
|
||||||
|
|
||||||
#: contrib/admin/widgets.py:71
|
#: contrib/admin/widgets.py:72
|
||||||
msgid "Date:"
|
msgid "Date:"
|
||||||
msgstr "Fecha:"
|
msgstr "Fecha:"
|
||||||
|
|
||||||
#: contrib/admin/widgets.py:71
|
#: contrib/admin/widgets.py:72
|
||||||
msgid "Time:"
|
msgid "Time:"
|
||||||
msgstr "Hora:"
|
msgstr "Hora:"
|
||||||
|
|
||||||
#: contrib/admin/widgets.py:95
|
#: contrib/admin/widgets.py:96
|
||||||
msgid "Currently:"
|
msgid "Currently:"
|
||||||
msgstr "Actualmente:"
|
msgstr "Actualmente:"
|
||||||
|
|
||||||
#: contrib/admin/widgets.py:95
|
#: contrib/admin/widgets.py:96
|
||||||
msgid "Change:"
|
msgid "Change:"
|
||||||
msgstr "Modificar:"
|
msgstr "Modificar:"
|
||||||
|
|
||||||
#: contrib/admin/widgets.py:124
|
#: contrib/admin/widgets.py:125
|
||||||
msgid "Lookup"
|
msgid "Lookup"
|
||||||
msgstr "Buscar"
|
msgstr "Buscar"
|
||||||
|
|
||||||
#: contrib/admin/widgets.py:236
|
#: contrib/admin/widgets.py:237
|
||||||
msgid "Add Another"
|
msgid "Add Another"
|
||||||
msgstr "Añadir otro"
|
msgstr "Añadir otro"
|
||||||
|
|
||||||
@ -499,7 +499,7 @@ msgstr "Lo sentimos, pero no se encuentra la página solicitada."
|
|||||||
|
|
||||||
#: contrib/admin/templates/admin/500.html:4
|
#: contrib/admin/templates/admin/500.html:4
|
||||||
#: contrib/admin/templates/admin/app_index.html:8
|
#: contrib/admin/templates/admin/app_index.html:8
|
||||||
#: contrib/admin/templates/admin/base.html:31
|
#: contrib/admin/templates/admin/base.html:54
|
||||||
#: contrib/admin/templates/admin/change_form.html:17
|
#: contrib/admin/templates/admin/change_form.html:17
|
||||||
#: contrib/admin/templates/admin/change_list.html:25
|
#: contrib/admin/templates/admin/change_list.html:25
|
||||||
#: contrib/admin/templates/admin/delete_confirmation.html:6
|
#: contrib/admin/templates/admin/delete_confirmation.html:6
|
||||||
@ -553,18 +553,18 @@ msgstr "Ir"
|
|||||||
msgid "%(name)s"
|
msgid "%(name)s"
|
||||||
msgstr "%(name)s"
|
msgstr "%(name)s"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin/base.html:26
|
#: contrib/admin/templates/admin/base.html:27
|
||||||
msgid "Welcome,"
|
msgid "Welcome,"
|
||||||
msgstr "Bienvenido/a,"
|
msgstr "Bienvenido/a,"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin/base.html:26
|
#: contrib/admin/templates/admin/base.html:32
|
||||||
#: contrib/admin/templates/registration/password_change_done.html:3
|
#: contrib/admin/templates/registration/password_change_done.html:3
|
||||||
#: contrib/admin/templates/registration/password_change_form.html:3
|
#: contrib/admin/templates/registration/password_change_form.html:3
|
||||||
#: contrib/admindocs/templates/admin_doc/bookmarklets.html:3
|
#: contrib/admindocs/templates/admin_doc/bookmarklets.html:3
|
||||||
msgid "Documentation"
|
msgid "Documentation"
|
||||||
msgstr "Documentación"
|
msgstr "Documentación"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin/base.html:26
|
#: contrib/admin/templates/admin/base.html:40
|
||||||
#: contrib/admin/templates/admin/auth/user/change_password.html:14
|
#: contrib/admin/templates/admin/auth/user/change_password.html:14
|
||||||
#: contrib/admin/templates/admin/auth/user/change_password.html:47
|
#: 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_done.html:3
|
||||||
@ -572,7 +572,7 @@ msgstr "Documentación"
|
|||||||
msgid "Change password"
|
msgid "Change password"
|
||||||
msgstr "Cambiar contraseña"
|
msgstr "Cambiar contraseña"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin/base.html:26
|
#: contrib/admin/templates/admin/base.html:47
|
||||||
#: contrib/admin/templates/registration/password_change_done.html:3
|
#: contrib/admin/templates/registration/password_change_done.html:3
|
||||||
#: contrib/admin/templates/registration/password_change_form.html:3
|
#: contrib/admin/templates/registration/password_change_form.html:3
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
@ -598,7 +598,7 @@ msgstr "Histórico"
|
|||||||
|
|
||||||
#: contrib/admin/templates/admin/change_form.html:28
|
#: contrib/admin/templates/admin/change_form.html:28
|
||||||
#: contrib/admin/templates/admin/edit_inline/stacked.html:13
|
#: contrib/admin/templates/admin/edit_inline/stacked.html:13
|
||||||
#: contrib/admin/templates/admin/edit_inline/tabular.html:27
|
#: contrib/admin/templates/admin/edit_inline/tabular.html:28
|
||||||
msgid "View on site"
|
msgid "View on site"
|
||||||
msgstr "Ver en el sitio"
|
msgstr "Ver en el sitio"
|
||||||
|
|
||||||
@ -668,9 +668,9 @@ msgstr ""
|
|||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure you want to delete the selected %(object_name)s objects? All of "
|
"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:"
|
"the following objects and their related items will be deleted:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"¿Está seguro de que quiere borrar los %(object_name)s? Los siguientes "
|
"¿Está seguro de que quiere eliminar los %(object_name)s seleccionados? Los siguientes "
|
||||||
"objetos y sus elementos relacionados serán eliminados:"
|
"objetos y sus elementos relacionados serán eliminados:"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin/filter.html:2
|
#: contrib/admin/templates/admin/filter.html:2
|
||||||
@ -734,7 +734,6 @@ msgid "User"
|
|||||||
msgstr "Usuario"
|
msgstr "Usuario"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin/object_history.html:24
|
#: contrib/admin/templates/admin/object_history.html:24
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:33
|
|
||||||
msgid "Action"
|
msgid "Action"
|
||||||
msgstr "Acción"
|
msgstr "Acción"
|
||||||
|
|
||||||
@ -987,7 +986,7 @@ msgstr "Dirección de correo electrónico:"
|
|||||||
msgid "Reset my password"
|
msgid "Reset my password"
|
||||||
msgstr "Restablecer mi contraseña"
|
msgstr "Restablecer mi contraseña"
|
||||||
|
|
||||||
#: contrib/admin/templatetags/admin_list.py:299
|
#: contrib/admin/templatetags/admin_list.py:304
|
||||||
msgid "All dates"
|
msgid "All dates"
|
||||||
msgstr "Todas las fechas"
|
msgstr "Todas las fechas"
|
||||||
|
|
||||||
@ -1009,146 +1008,145 @@ msgstr "sitio"
|
|||||||
msgid "template"
|
msgid "template"
|
||||||
msgstr "plantilla"
|
msgstr "plantilla"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:58 contrib/admindocs/views.py:60
|
#: contrib/admindocs/views.py:61 contrib/admindocs/views.py:63
|
||||||
#: contrib/admindocs/views.py:62
|
#: contrib/admindocs/views.py:65
|
||||||
msgid "tag:"
|
msgid "tag:"
|
||||||
msgstr "etiqueta:"
|
msgstr "etiqueta:"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:91 contrib/admindocs/views.py:93
|
#: contrib/admindocs/views.py:94 contrib/admindocs/views.py:96
|
||||||
#: contrib/admindocs/views.py:95
|
#: contrib/admindocs/views.py:98
|
||||||
msgid "filter:"
|
msgid "filter:"
|
||||||
msgstr "filtro:"
|
msgstr "filtro:"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:155 contrib/admindocs/views.py:157
|
#: contrib/admindocs/views.py:158 contrib/admindocs/views.py:160
|
||||||
#: contrib/admindocs/views.py:159
|
#: contrib/admindocs/views.py:162
|
||||||
msgid "view:"
|
msgid "view:"
|
||||||
msgstr "vista:"
|
msgstr "vista:"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:187
|
#: contrib/admindocs/views.py:190
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "App %r not found"
|
msgid "App %r not found"
|
||||||
msgstr "Aplicación %r no encontrada"
|
msgstr "Aplicación %r no encontrada"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:194
|
#: contrib/admindocs/views.py:197
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Model %(model_name)r not found in app %(app_label)r"
|
msgid "Model %(model_name)r not found in app %(app_label)r"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"El modelo %(model_name)r no se ha encontrado en la aplicación %(app_label)r"
|
"El modelo %(model_name)r no se ha encontrado en la aplicación %(app_label)r"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:206
|
#: contrib/admindocs/views.py:209
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "the related `%(app_label)s.%(data_type)s` object"
|
msgid "the related `%(app_label)s.%(data_type)s` object"
|
||||||
msgstr "el objeto relacionado `%(app_label)s.%(data_type)s`"
|
msgstr "el objeto relacionado `%(app_label)s.%(data_type)s`"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:206 contrib/admindocs/views.py:225
|
#: contrib/admindocs/views.py:209 contrib/admindocs/views.py:228
|
||||||
#: contrib/admindocs/views.py:230 contrib/admindocs/views.py:244
|
#: contrib/admindocs/views.py:233 contrib/admindocs/views.py:247
|
||||||
#: contrib/admindocs/views.py:258 contrib/admindocs/views.py:263
|
#: contrib/admindocs/views.py:261 contrib/admindocs/views.py:266
|
||||||
msgid "model:"
|
msgid "model:"
|
||||||
msgstr "modelo:"
|
msgstr "modelo:"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:221 contrib/admindocs/views.py:253
|
#: contrib/admindocs/views.py:224 contrib/admindocs/views.py:256
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "related `%(app_label)s.%(object_name)s` objects"
|
msgid "related `%(app_label)s.%(object_name)s` objects"
|
||||||
msgstr "los objetos relacionados `%(app_label)s.%(object_name)s`"
|
msgstr "los objetos relacionados `%(app_label)s.%(object_name)s`"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:225 contrib/admindocs/views.py:258
|
#: contrib/admindocs/views.py:228 contrib/admindocs/views.py:261
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "all %s"
|
msgid "all %s"
|
||||||
msgstr "todo %s"
|
msgstr "todo %s"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:230 contrib/admindocs/views.py:263
|
#: contrib/admindocs/views.py:233 contrib/admindocs/views.py:266
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "number of %s"
|
msgid "number of %s"
|
||||||
msgstr "número de %s"
|
msgstr "número de %s"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:268
|
#: contrib/admindocs/views.py:271
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Fields on %s objects"
|
msgid "Fields on %s objects"
|
||||||
msgstr "Campos en %s objetos"
|
msgstr "Campos en %s objetos"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:331 contrib/admindocs/views.py:342
|
#: contrib/admindocs/views.py:334 contrib/admindocs/views.py:345
|
||||||
#: contrib/admindocs/views.py:344 contrib/admindocs/views.py:350
|
#: contrib/admindocs/views.py:347 contrib/admindocs/views.py:353
|
||||||
#: contrib/admindocs/views.py:351 contrib/admindocs/views.py:353
|
#: contrib/admindocs/views.py:354 contrib/admindocs/views.py:356
|
||||||
msgid "Integer"
|
msgid "Integer"
|
||||||
msgstr "Entero"
|
msgstr "Entero"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:332
|
#: contrib/admindocs/views.py:335
|
||||||
msgid "Boolean (Either True or False)"
|
msgid "Boolean (Either True or False)"
|
||||||
msgstr "Booleano (Verdadero o Falso)"
|
msgstr "Booleano (Verdadero o Falso)"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:333 contrib/admindocs/views.py:352
|
#: contrib/admindocs/views.py:336 contrib/admindocs/views.py:355
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "String (up to %(max_length)s)"
|
msgid "String (up to %(max_length)s)"
|
||||||
msgstr "Cadena (máximo %(max_length)s)"
|
msgstr "Cadena (máximo %(max_length)s)"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:334
|
#: contrib/admindocs/views.py:337
|
||||||
msgid "Comma-separated integers"
|
msgid "Comma-separated integers"
|
||||||
msgstr "Enteros separados por comas"
|
msgstr "Enteros separados por comas"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:335
|
#: contrib/admindocs/views.py:338
|
||||||
msgid "Date (without time)"
|
msgid "Date (without time)"
|
||||||
msgstr "Fecha (sin hora)"
|
msgstr "Fecha (sin hora)"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:336
|
#: contrib/admindocs/views.py:339
|
||||||
msgid "Date (with time)"
|
msgid "Date (with time)"
|
||||||
msgstr "Fecha (con hora)"
|
msgstr "Fecha (con hora)"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:337
|
#: contrib/admindocs/views.py:340
|
||||||
msgid "Decimal number"
|
msgid "Decimal number"
|
||||||
msgstr "Número decimal"
|
msgstr "Número decimal"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:338
|
#: contrib/admindocs/views.py:341
|
||||||
msgid "E-mail address"
|
msgid "E-mail address"
|
||||||
msgstr "Dirección de correo electrónico"
|
msgstr "Dirección de correo electrónico"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:339 contrib/admindocs/views.py:340
|
#: contrib/admindocs/views.py:342 contrib/admindocs/views.py:343
|
||||||
#: contrib/admindocs/views.py:343
|
#: contrib/admindocs/views.py:346
|
||||||
msgid "File path"
|
msgid "File path"
|
||||||
msgstr "Ruta de fichero"
|
msgstr "Ruta de fichero"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:341
|
#: contrib/admindocs/views.py:344
|
||||||
msgid "Floating point number"
|
msgid "Floating point number"
|
||||||
msgstr "Número en coma flotante"
|
msgstr "Número en coma flotante"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:345 contrib/comments/models.py:60
|
#: contrib/admindocs/views.py:348 contrib/comments/models.py:60
|
||||||
msgid "IP address"
|
msgid "IP address"
|
||||||
msgstr "Dirección IP"
|
msgstr "Dirección IP"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:347
|
#: contrib/admindocs/views.py:350
|
||||||
msgid "Boolean (Either True, False or None)"
|
msgid "Boolean (Either True, False or None)"
|
||||||
msgstr "Booleano (Verdadero, Falso o Nulo)"
|
msgstr "Booleano (Verdadero, Falso o Nulo)"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:348
|
#: contrib/admindocs/views.py:351
|
||||||
msgid "Relation to parent model"
|
msgid "Relation to parent model"
|
||||||
msgstr "Relación con el modelo padre"
|
msgstr "Relación con el modelo padre"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:349
|
#: contrib/admindocs/views.py:352
|
||||||
msgid "Phone number"
|
msgid "Phone number"
|
||||||
msgstr "Número de teléfono"
|
msgstr "Número de teléfono"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:354
|
#: contrib/admindocs/views.py:357
|
||||||
msgid "Text"
|
msgid "Text"
|
||||||
msgstr "Texto"
|
msgstr "Texto"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:355
|
#: contrib/admindocs/views.py:358
|
||||||
msgid "Time"
|
msgid "Time"
|
||||||
msgstr "Hora"
|
msgstr "Hora"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:356 contrib/comments/forms.py:95
|
#: contrib/admindocs/views.py:359 contrib/comments/forms.py:95
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:37
|
|
||||||
#: contrib/flatpages/admin.py:8 contrib/flatpages/models.py:7
|
#: contrib/flatpages/admin.py:8 contrib/flatpages/models.py:7
|
||||||
msgid "URL"
|
msgid "URL"
|
||||||
msgstr "URL"
|
msgstr "URL"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:357
|
#: contrib/admindocs/views.py:360
|
||||||
msgid "U.S. state (two uppercase letters)"
|
msgid "U.S. state (two uppercase letters)"
|
||||||
msgstr "Estado de los EEUU (dos letras mayúsculas)"
|
msgstr "Estado de los EEUU (dos letras mayúsculas)"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:358
|
#: contrib/admindocs/views.py:361
|
||||||
msgid "XML text"
|
msgid "XML text"
|
||||||
msgstr "Texto XML"
|
msgstr "Texto XML"
|
||||||
|
|
||||||
#: contrib/admindocs/views.py:384
|
#: contrib/admindocs/views.py:387
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%s does not appear to be a urlpattern object"
|
msgid "%s does not appear to be a urlpattern object"
|
||||||
msgstr "%s no parece ser un objeto urlpattern"
|
msgstr "%s no parece ser un objeto urlpattern"
|
||||||
@ -1441,22 +1439,53 @@ msgstr "usuarios"
|
|||||||
msgid "message"
|
msgid "message"
|
||||||
msgstr "mensaje"
|
msgstr "mensaje"
|
||||||
|
|
||||||
#: contrib/auth/views.py:56
|
#: contrib/auth/views.py:60
|
||||||
msgid "Logged out"
|
msgid "Logged out"
|
||||||
msgstr "Sesión terminada"
|
msgstr "Sesión terminada"
|
||||||
|
|
||||||
#: contrib/auth/management/commands/createsuperuser.py:23 forms/fields.py:429
|
#: contrib/auth/management/commands/createsuperuser.py:23 forms/fields.py:428
|
||||||
msgid "Enter a valid e-mail address."
|
msgid "Enter a valid e-mail address."
|
||||||
msgstr "Introduzca una dirección de correo electrónico válida."
|
msgstr "Introduzca una dirección de correo electrónico válida."
|
||||||
|
|
||||||
#: contrib/comments/admin.py:11
|
#: contrib/comments/admin.py:12
|
||||||
msgid "Content"
|
msgid "Content"
|
||||||
msgstr "contenido"
|
msgstr "contenido"
|
||||||
|
|
||||||
#: contrib/comments/admin.py:14
|
#: contrib/comments/admin.py:15
|
||||||
msgid "Metadata"
|
msgid "Metadata"
|
||||||
msgstr "metadatos"
|
msgstr "metadatos"
|
||||||
|
|
||||||
|
#: contrib/comments/admin.py:39
|
||||||
|
msgid "flagged"
|
||||||
|
msgstr "marcado"
|
||||||
|
|
||||||
|
#: contrib/comments/admin.py:40
|
||||||
|
msgid "Flag selected comments"
|
||||||
|
msgstr "Marcar los comentarios seleccionados"
|
||||||
|
|
||||||
|
#: contrib/comments/admin.py:43
|
||||||
|
msgid "approved"
|
||||||
|
msgstr "aprobado"
|
||||||
|
|
||||||
|
#: contrib/comments/admin.py:44
|
||||||
|
msgid "Approve selected comments"
|
||||||
|
msgstr "aprobar los comentarios seleccionados"
|
||||||
|
|
||||||
|
#: contrib/comments/admin.py:47
|
||||||
|
msgid "removed"
|
||||||
|
msgstr "eliminado"
|
||||||
|
|
||||||
|
#: contrib/comments/admin.py:48
|
||||||
|
msgid "Remove selected comments"
|
||||||
|
msgstr "Eliminar los comentarios seleccionados"
|
||||||
|
|
||||||
|
#: contrib/comments/admin.py:60
|
||||||
|
#, python-format
|
||||||
|
msgid "1 comment was successfully %(action)s."
|
||||||
|
msgid_plural "%(count)s comments were successfully %(action)s."
|
||||||
|
msgstr[0] "1 comentarios ha sido %(action)s satisfactoriamente."
|
||||||
|
msgstr[1] "%(count)s comentarios han sido %(action)s satisfactoriamente."
|
||||||
|
|
||||||
#: contrib/comments/feeds.py:13
|
#: contrib/comments/feeds.py:13
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(site_name)s comments"
|
msgid "%(site_name)s comments"
|
||||||
@ -1468,7 +1497,6 @@ msgid "Latest comments on %(site_name)s"
|
|||||||
msgstr "Últimos comentarios en %(site_name)s"
|
msgstr "Últimos comentarios en %(site_name)s"
|
||||||
|
|
||||||
#: contrib/comments/forms.py:93
|
#: contrib/comments/forms.py:93
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:34
|
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nombre"
|
msgstr "Nombre"
|
||||||
|
|
||||||
@ -1477,7 +1505,6 @@ msgid "Email address"
|
|||||||
msgstr "dirección de correo electrónico"
|
msgstr "dirección de correo electrónico"
|
||||||
|
|
||||||
#: contrib/comments/forms.py:96
|
#: contrib/comments/forms.py:96
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:35
|
|
||||||
msgid "Comment"
|
msgid "Comment"
|
||||||
msgstr "Comentario"
|
msgstr "Comentario"
|
||||||
|
|
||||||
@ -1598,14 +1625,13 @@ msgstr "marcas de comentario"
|
|||||||
|
|
||||||
#: contrib/comments/templates/comments/approve.html:4
|
#: contrib/comments/templates/comments/approve.html:4
|
||||||
msgid "Approve a comment"
|
msgid "Approve a comment"
|
||||||
msgstr "Aprovar un comentario"
|
msgstr "Aprobar un comentario"
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/approve.html:7
|
#: contrib/comments/templates/comments/approve.html:7
|
||||||
msgid "Really make this comment public?"
|
msgid "Really make this comment public?"
|
||||||
msgstr "Realmente desea hacer este comentario público?"
|
msgstr "Realmente desea hacer este comentario público?"
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/approve.html:12
|
#: contrib/comments/templates/comments/approve.html:12
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:49
|
|
||||||
msgid "Approve"
|
msgid "Approve"
|
||||||
msgstr "Aprobar"
|
msgstr "Aprobar"
|
||||||
|
|
||||||
@ -1631,7 +1657,6 @@ msgid "Really remove this comment?"
|
|||||||
msgstr "¿Realmente desea eliminar este comentario?"
|
msgstr "¿Realmente desea eliminar este comentario?"
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/delete.html:12
|
#: contrib/comments/templates/comments/delete.html:12
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:53
|
|
||||||
msgid "Remove"
|
msgid "Remove"
|
||||||
msgstr "Eliminar"
|
msgstr "Eliminar"
|
||||||
|
|
||||||
@ -1665,39 +1690,6 @@ msgstr "Enviar"
|
|||||||
msgid "Preview"
|
msgid "Preview"
|
||||||
msgstr "Previsualizar"
|
msgstr "Previsualizar"
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:4
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:19
|
|
||||||
msgid "Comment moderation queue"
|
|
||||||
msgstr "Cola de moderación de comentarios"
|
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:26
|
|
||||||
msgid "No comments to moderate"
|
|
||||||
msgstr "No hay comentarios por moderar"
|
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:36
|
|
||||||
msgid "Email"
|
|
||||||
msgstr "Correo electrónico"
|
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:38
|
|
||||||
msgid "Authenticated?"
|
|
||||||
msgstr "¿Autentificado?"
|
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:39
|
|
||||||
msgid "IP Address"
|
|
||||||
msgstr "Dirección IP"
|
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:40
|
|
||||||
msgid "Date posted"
|
|
||||||
msgstr "Fecha de envío"
|
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:63
|
|
||||||
msgid "yes"
|
|
||||||
msgstr "sí"
|
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/moderation_queue.html:63
|
|
||||||
msgid "no"
|
|
||||||
msgstr "no"
|
|
||||||
|
|
||||||
#: contrib/comments/templates/comments/posted.html:4
|
#: contrib/comments/templates/comments/posted.html:4
|
||||||
msgid "Thanks for commenting"
|
msgid "Thanks for commenting"
|
||||||
msgstr "Gracias por comentar"
|
msgstr "Gracias por comentar"
|
||||||
@ -1790,7 +1782,7 @@ msgstr "página estática"
|
|||||||
msgid "flat pages"
|
msgid "flat pages"
|
||||||
msgstr "páginas estáticas"
|
msgstr "páginas estáticas"
|
||||||
|
|
||||||
#: contrib/formtools/wizard.py:130
|
#: contrib/formtools/wizard.py:132
|
||||||
msgid ""
|
msgid ""
|
||||||
"We apologize, but your form has expired. Please continue filling out the "
|
"We apologize, but your form has expired. Please continue filling out the "
|
||||||
"form from this page."
|
"form from this page."
|
||||||
@ -1815,8 +1807,8 @@ msgid ""
|
|||||||
"An error occurred when transforming the geometry to the SRID of the geometry "
|
"An error occurred when transforming the geometry to the SRID of the geometry "
|
||||||
"form field."
|
"form field."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Ocurrió un error al transformar la geometria al SRID de la geometria "
|
"Ocurrió un error al transformar la geometria al SRID de la geometria del "
|
||||||
"del campo de formulario."
|
"campo de formulario."
|
||||||
|
|
||||||
#: contrib/humanize/templatetags/humanize.py:19
|
#: contrib/humanize/templatetags/humanize.py:19
|
||||||
msgid "th"
|
msgid "th"
|
||||||
@ -2611,6 +2603,10 @@ msgstr "El número de cuenta bancaria es incorrecto."
|
|||||||
msgid "Enter a valid Finnish social security number."
|
msgid "Enter a valid Finnish social security number."
|
||||||
msgstr "Introduzca un número de seguro social finlandés válido."
|
msgstr "Introduzca un número de seguro social finlandés válido."
|
||||||
|
|
||||||
|
#: contrib/localflavor/fr/forms.py:30
|
||||||
|
msgid "Phone numbers must be in 0X XX XX XX XX format."
|
||||||
|
msgstr "Los números de teléfono deben tener el formato 0X XX XX XX XX."
|
||||||
|
|
||||||
#: contrib/localflavor/in_/forms.py:14
|
#: contrib/localflavor/in_/forms.py:14
|
||||||
msgid "Enter a zip code in the format XXXXXXX."
|
msgid "Enter a zip code in the format XXXXXXX."
|
||||||
msgstr "Introduzca un código postal en el formato XXXXXXX."
|
msgstr "Introduzca un código postal en el formato XXXXXXX."
|
||||||
@ -3052,7 +3048,8 @@ msgstr "El Número de Identificación Tributaria (NIP) es incorrecto."
|
|||||||
#: contrib/localflavor/pl/forms.py:109
|
#: contrib/localflavor/pl/forms.py:109
|
||||||
msgid "National Business Register Number (REGON) consists of 9 or 14 digits."
|
msgid "National Business Register Number (REGON) consists of 9 or 14 digits."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"El Número Nacional de Registro de Negocios (REGON) consiste en 9 o 14 dígitos."
|
"El Número Nacional de Registro de Negocios (REGON) consiste en 9 o 14 "
|
||||||
|
"dígitos."
|
||||||
|
|
||||||
#: contrib/localflavor/pl/forms.py:110
|
#: contrib/localflavor/pl/forms.py:110
|
||||||
msgid "Wrong checksum for the National Business Register Number (REGON)."
|
msgid "Wrong checksum for the National Business Register Number (REGON)."
|
||||||
@ -3941,14 +3938,14 @@ msgstr "Este valor debe ser Verdadero, Falso o Ninguno."
|
|||||||
msgid "Enter a valid time in HH:MM[:ss[.uuuuuu]] format."
|
msgid "Enter a valid time in HH:MM[:ss[.uuuuuu]] format."
|
||||||
msgstr "Introduzca una hora válida en formato HH:MM[:ss[.uuuuuu]]."
|
msgstr "Introduzca una hora válida en formato HH:MM[:ss[.uuuuuu]]."
|
||||||
|
|
||||||
#: db/models/fields/related.py:816
|
#: db/models/fields/related.py:869
|
||||||
msgid ""
|
msgid ""
|
||||||
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
|
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Mantenga presionado \"Control\", o \"Command\" en un Mac, para seleccionar "
|
"Mantenga presionado \"Control\", o \"Command\" en un Mac, para seleccionar "
|
||||||
"más de una opción."
|
"más de una opción."
|
||||||
|
|
||||||
#: db/models/fields/related.py:894
|
#: db/models/fields/related.py:930
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
|
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
|
||||||
msgid_plural ""
|
msgid_plural ""
|
||||||
@ -3960,88 +3957,88 @@ msgstr[1] ""
|
|||||||
"Por favor, introduzca IDs de %(self)s válidos. Los valores %(value)r no son "
|
"Por favor, introduzca IDs de %(self)s válidos. Los valores %(value)r no son "
|
||||||
"válidos."
|
"válidos."
|
||||||
|
|
||||||
#: forms/fields.py:54
|
#: forms/fields.py:53
|
||||||
msgid "This field is required."
|
msgid "This field is required."
|
||||||
msgstr "Este campo es obligatorio."
|
msgstr "Este campo es obligatorio."
|
||||||
|
|
||||||
#: forms/fields.py:55
|
#: forms/fields.py:54
|
||||||
msgid "Enter a valid value."
|
msgid "Enter a valid value."
|
||||||
msgstr "Introduzca un valor correcto."
|
msgstr "Introduzca un valor correcto."
|
||||||
|
|
||||||
#: forms/fields.py:138
|
#: forms/fields.py:137
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure this value has at most %(max)d characters (it has %(length)d)."
|
msgid "Ensure this value has at most %(max)d characters (it has %(length)d)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Asegúrese de que su texto tiene a lo más %(max)d caracteres (actualmente "
|
"Asegúrese de que su texto tiene a lo más %(max)d caracteres (actualmente "
|
||||||
"tiene %(length)d)."
|
"tiene %(length)d)."
|
||||||
|
|
||||||
#: forms/fields.py:139
|
#: forms/fields.py:138
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure this value has at least %(min)d characters (it has %(length)d)."
|
msgid "Ensure this value has at least %(min)d characters (it has %(length)d)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Asegúrese de que su texto tiene al menos %(min)d caracteres (actualmente "
|
"Asegúrese de que su texto tiene al menos %(min)d caracteres (actualmente "
|
||||||
"tiene %(length)d)."
|
"tiene %(length)d)."
|
||||||
|
|
||||||
#: forms/fields.py:166
|
#: forms/fields.py:165
|
||||||
msgid "Enter a whole number."
|
msgid "Enter a whole number."
|
||||||
msgstr "Introduzca un número entero."
|
msgstr "Introduzca un número entero."
|
||||||
|
|
||||||
#: forms/fields.py:167 forms/fields.py:196 forms/fields.py:225
|
#: forms/fields.py:166 forms/fields.py:195 forms/fields.py:224
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure this value is less than or equal to %s."
|
msgid "Ensure this value is less than or equal to %s."
|
||||||
msgstr "Asegúrese de que este valor es menor o igual a %s."
|
msgstr "Asegúrese de que este valor es menor o igual a %s."
|
||||||
|
|
||||||
#: forms/fields.py:168 forms/fields.py:197 forms/fields.py:226
|
#: forms/fields.py:167 forms/fields.py:196 forms/fields.py:225
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure this value is greater than or equal to %s."
|
msgid "Ensure this value is greater than or equal to %s."
|
||||||
msgstr "Asegúrese de que este valor es mayor o igual a %s."
|
msgstr "Asegúrese de que este valor es mayor o igual a %s."
|
||||||
|
|
||||||
#: forms/fields.py:195 forms/fields.py:224
|
#: forms/fields.py:194 forms/fields.py:223
|
||||||
msgid "Enter a number."
|
msgid "Enter a number."
|
||||||
msgstr "Introduzca un número."
|
msgstr "Introduzca un número."
|
||||||
|
|
||||||
#: forms/fields.py:227
|
#: forms/fields.py:226
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure that there are no more than %s digits in total."
|
msgid "Ensure that there are no more than %s digits in total."
|
||||||
msgstr "Asegúrese de que no hay más de %s dígitos en total."
|
msgstr "Asegúrese de que no hay más de %s dígitos en total."
|
||||||
|
|
||||||
#: forms/fields.py:228
|
#: forms/fields.py:227
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure that there are no more than %s decimal places."
|
msgid "Ensure that there are no more than %s decimal places."
|
||||||
msgstr "Asegúrese de que no hay más de %s decimales."
|
msgstr "Asegúrese de que no hay más de %s decimales."
|
||||||
|
|
||||||
#: forms/fields.py:229
|
#: forms/fields.py:228
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure that there are no more than %s digits before the decimal point."
|
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."
|
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:863
|
#: forms/fields.py:287 forms/fields.py:862
|
||||||
msgid "Enter a valid date."
|
msgid "Enter a valid date."
|
||||||
msgstr "Introduzca una fecha válida."
|
msgstr "Introduzca una fecha válida."
|
||||||
|
|
||||||
#: forms/fields.py:322 forms/fields.py:864
|
#: forms/fields.py:321 forms/fields.py:863
|
||||||
msgid "Enter a valid time."
|
msgid "Enter a valid time."
|
||||||
msgstr "Introduzca una hora válida."
|
msgstr "Introduzca una hora válida."
|
||||||
|
|
||||||
#: forms/fields.py:361
|
#: forms/fields.py:360
|
||||||
msgid "Enter a valid date/time."
|
msgid "Enter a valid date/time."
|
||||||
msgstr "Introduzca una fecha/hora válida."
|
msgstr "Introduzca una fecha/hora válida."
|
||||||
|
|
||||||
#: forms/fields.py:447
|
#: forms/fields.py:446
|
||||||
msgid "No file was submitted. Check the encoding type on the form."
|
msgid "No file was submitted. Check the encoding type on the form."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"No se ha enviado ningún fichero. Compruebe el tipo de codificación en el "
|
"No se ha enviado ningún fichero. Compruebe el tipo de codificación en el "
|
||||||
"formulario."
|
"formulario."
|
||||||
|
|
||||||
#: forms/fields.py:448
|
#: forms/fields.py:447
|
||||||
msgid "No file was submitted."
|
msgid "No file was submitted."
|
||||||
msgstr "No se ha enviado ningún fichero"
|
msgstr "No se ha enviado ningún fichero"
|
||||||
|
|
||||||
#: forms/fields.py:449
|
#: forms/fields.py:448
|
||||||
msgid "The submitted file is empty."
|
msgid "The submitted file is empty."
|
||||||
msgstr "El fichero enviado está vacío."
|
msgstr "El fichero enviado está vacío."
|
||||||
|
|
||||||
#: forms/fields.py:450
|
#: forms/fields.py:449
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Ensure this filename has at most %(max)d characters (it has %(length)d)."
|
"Ensure this filename has at most %(max)d characters (it has %(length)d)."
|
||||||
@ -4049,7 +4046,7 @@ msgstr ""
|
|||||||
"Asegúrese de que su texto tiene no más de %(max)d caracteres (actualmente "
|
"Asegúrese de que su texto tiene no más de %(max)d caracteres (actualmente "
|
||||||
"tiene %(length)d)."
|
"tiene %(length)d)."
|
||||||
|
|
||||||
#: forms/fields.py:483
|
#: forms/fields.py:482
|
||||||
msgid ""
|
msgid ""
|
||||||
"Upload a valid image. The file you uploaded was either not an image or a "
|
"Upload a valid image. The file you uploaded was either not an image or a "
|
||||||
"corrupted image."
|
"corrupted image."
|
||||||
@ -4057,29 +4054,29 @@ msgstr ""
|
|||||||
"Envíe una imagen válida. El fichero que ha enviado no era una imagen o se "
|
"Envíe una imagen válida. El fichero que ha enviado no era una imagen o se "
|
||||||
"trataba de una imagen corrupta."
|
"trataba de una imagen corrupta."
|
||||||
|
|
||||||
#: forms/fields.py:544
|
#: forms/fields.py:543
|
||||||
msgid "Enter a valid URL."
|
msgid "Enter a valid URL."
|
||||||
msgstr "Introduzca una URL válida."
|
msgstr "Introduzca una URL válida."
|
||||||
|
|
||||||
#: forms/fields.py:545
|
#: forms/fields.py:544
|
||||||
msgid "This URL appears to be a broken link."
|
msgid "This URL appears to be a broken link."
|
||||||
msgstr "La URL parece ser un enlace roto."
|
msgstr "La URL parece ser un enlace roto."
|
||||||
|
|
||||||
#: forms/fields.py:625 forms/fields.py:703
|
#: forms/fields.py:624 forms/fields.py:702
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Select a valid choice. %(value)s is not one of the available choices."
|
msgid "Select a valid choice. %(value)s is not one of the available choices."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Escoja una opción válida. %(value)s no es una de las opciones disponibles."
|
"Escoja una opción válida. %(value)s no es una de las opciones disponibles."
|
||||||
|
|
||||||
#: forms/fields.py:704 forms/fields.py:765 forms/models.py:1003
|
#: forms/fields.py:703 forms/fields.py:764 forms/models.py:999
|
||||||
msgid "Enter a list of values."
|
msgid "Enter a list of values."
|
||||||
msgstr "Introduzca una lista de valores."
|
msgstr "Introduzca una lista de valores."
|
||||||
|
|
||||||
#: forms/fields.py:892
|
#: forms/fields.py:891
|
||||||
msgid "Enter a valid IPv4 address."
|
msgid "Enter a valid IPv4 address."
|
||||||
msgstr "Introduzca una dirección IPv4 válida."
|
msgstr "Introduzca una dirección IPv4 válida."
|
||||||
|
|
||||||
#: forms/fields.py:902
|
#: forms/fields.py:901
|
||||||
msgid ""
|
msgid ""
|
||||||
"Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."
|
"Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -4090,28 +4087,28 @@ msgstr ""
|
|||||||
msgid "Order"
|
msgid "Order"
|
||||||
msgstr "Orden"
|
msgstr "Orden"
|
||||||
|
|
||||||
#: forms/models.py:367
|
#: forms/models.py:363
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(field_name)s must be unique for %(date_field)s %(lookup)s."
|
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"
|
msgstr "El campo %(field_name)s debe ser único para %(lookup)s %(date_field)s"
|
||||||
|
|
||||||
#: forms/models.py:381 forms/models.py:389
|
#: forms/models.py:377 forms/models.py:385
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(model_name)s with this %(field_label)s already exists."
|
msgid "%(model_name)s with this %(field_label)s already exists."
|
||||||
msgstr "Ya existe %(model_name)s con este %(field_label)s."
|
msgstr "Ya existe %(model_name)s con este %(field_label)s."
|
||||||
|
|
||||||
#: forms/models.py:594
|
#: forms/models.py:590
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please correct the duplicate data for %(field)s."
|
msgid "Please correct the duplicate data for %(field)s."
|
||||||
msgstr "Por favor, corrija el dato duplicado para %(field)s."
|
msgstr "Por favor, corrija el dato duplicado para %(field)s."
|
||||||
|
|
||||||
#: forms/models.py:598
|
#: forms/models.py:594
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please correct the duplicate data for %(field)s, which must be unique."
|
msgid "Please correct the duplicate data for %(field)s, which must be unique."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Por favor corriga el dato duplicado para %(field)s, el cual debe ser único."
|
"Por favor corriga el dato duplicado para %(field)s, el cual debe ser único."
|
||||||
|
|
||||||
#: forms/models.py:604
|
#: forms/models.py:600
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Please correct the duplicate data for %(field_name)s which must be unique "
|
"Please correct the duplicate data for %(field_name)s which must be unique "
|
||||||
@ -4120,26 +4117,26 @@ msgstr ""
|
|||||||
"Por favor corriga los datos duplicados para %(field_name)s el cual debe ser "
|
"Por favor corriga los datos duplicados para %(field_name)s el cual debe ser "
|
||||||
"único para %(lookup)s en %(date_field)s."
|
"único para %(lookup)s en %(date_field)s."
|
||||||
|
|
||||||
#: forms/models.py:612
|
#: forms/models.py:608
|
||||||
msgid "Please correct the duplicate values below."
|
msgid "Please correct the duplicate values below."
|
||||||
msgstr "Por favor, corrija los valores duplicados abajo."
|
msgstr "Por favor, corrija los valores duplicados abajo."
|
||||||
|
|
||||||
#: forms/models.py:867
|
#: forms/models.py:863
|
||||||
msgid "The inline foreign key did not match the parent instance primary key."
|
msgid "The inline foreign key did not match the parent instance primary key."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"La clave foránea en linea no coincide con la clave primaria de la instancia "
|
"La clave foránea en linea no coincide con la clave primaria de la instancia "
|
||||||
"padre."
|
"padre."
|
||||||
|
|
||||||
#: forms/models.py:930
|
#: forms/models.py:926
|
||||||
msgid "Select a valid choice. That choice is not one of the available choices."
|
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."
|
msgstr "Escoja una opción válida. Esa opción no está entre las disponibles."
|
||||||
|
|
||||||
#: forms/models.py:1004
|
#: forms/models.py:1000
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Select a valid choice. %s is not one of the available choices."
|
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."
|
msgstr "Escoja una opción válida; '%s' no es una de las opciones disponibles."
|
||||||
|
|
||||||
#: forms/models.py:1006
|
#: forms/models.py:1002
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "\"%s\" is not a valid value for a primary key."
|
msgid "\"%s\" is not a valid value for a primary key."
|
||||||
msgstr "\"%s\" no es un valor válido para una clave primaria."
|
msgstr "\"%s\" no es un valor válido para una clave primaria."
|
||||||
@ -4459,6 +4456,30 @@ msgstr "Se actualizó con éxito el %(verbose_name)s."
|
|||||||
msgid "The %(verbose_name)s was deleted."
|
msgid "The %(verbose_name)s was deleted."
|
||||||
msgstr "El/La %(verbose_name)s ha sido borrado."
|
msgstr "El/La %(verbose_name)s ha sido borrado."
|
||||||
|
|
||||||
|
#~ msgid "Comment moderation queue"
|
||||||
|
#~ msgstr "Cola de moderación de comentarios"
|
||||||
|
|
||||||
|
#~ msgid "No comments to moderate"
|
||||||
|
#~ msgstr "No hay comentarios por moderar"
|
||||||
|
|
||||||
|
#~ msgid "Email"
|
||||||
|
#~ msgstr "Correo electrónico"
|
||||||
|
|
||||||
|
#~ msgid "Authenticated?"
|
||||||
|
#~ msgstr "¿Autentificado?"
|
||||||
|
|
||||||
|
#~ msgid "IP Address"
|
||||||
|
#~ msgstr "Dirección IP"
|
||||||
|
|
||||||
|
#~ msgid "Date posted"
|
||||||
|
#~ msgstr "Fecha de envío"
|
||||||
|
|
||||||
|
#~ msgid "yes"
|
||||||
|
#~ msgstr "sí"
|
||||||
|
|
||||||
|
#~ msgid "no"
|
||||||
|
#~ msgstr "no"
|
||||||
|
|
||||||
#~ msgid "verbose_name"
|
#~ msgid "verbose_name"
|
||||||
#~ msgid_plural "verbose_name_plural"
|
#~ msgid_plural "verbose_name_plural"
|
||||||
#~ msgstr[0] "verbose_name"
|
#~ msgstr[0] "verbose_name"
|
||||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -452,7 +452,7 @@ class AdminSite(object):
|
|||||||
import warnings
|
import warnings
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"AdminSite.root() is deprecated; use include(admin.site.urls) instead.",
|
"AdminSite.root() is deprecated; use include(admin.site.urls) instead.",
|
||||||
PendingDeprecationWarning
|
DeprecationWarning
|
||||||
)
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -196,6 +196,11 @@ def validate_base(cls, model):
|
|||||||
check_isseq(cls, 'fields', cls.fields)
|
check_isseq(cls, 'fields', cls.fields)
|
||||||
for field in cls.fields:
|
for field in cls.fields:
|
||||||
check_formfield(cls, model, opts, 'fields', field)
|
check_formfield(cls, model, opts, 'fields', field)
|
||||||
|
f = get_field(cls, model, opts, 'fields', field)
|
||||||
|
if isinstance(f, models.ManyToManyField) and not f.rel.through._meta.auto_created:
|
||||||
|
raise ImproperlyConfigured("'%s.fields' can't include the ManyToManyField "
|
||||||
|
"field '%s' because '%s' manually specifies "
|
||||||
|
"a 'through' model." % (cls.__name__, field, field))
|
||||||
if cls.fieldsets:
|
if cls.fieldsets:
|
||||||
raise ImproperlyConfigured('Both fieldsets and fields are specified in %s.' % cls.__name__)
|
raise ImproperlyConfigured('Both fieldsets and fields are specified in %s.' % cls.__name__)
|
||||||
if len(cls.fields) > len(set(cls.fields)):
|
if len(cls.fields) > len(set(cls.fields)):
|
||||||
@ -214,11 +219,28 @@ def validate_base(cls, model):
|
|||||||
raise ImproperlyConfigured("'fields' key is required in "
|
raise ImproperlyConfigured("'fields' key is required in "
|
||||||
"%s.fieldsets[%d][1] field options dict."
|
"%s.fieldsets[%d][1] field options dict."
|
||||||
% (cls.__name__, idx))
|
% (cls.__name__, idx))
|
||||||
|
for fields in fieldset[1]['fields']:
|
||||||
|
# The entry in fields might be a tuple. If it is a standalone
|
||||||
|
# field, make it into a tuple to make processing easier.
|
||||||
|
if type(fields) != tuple:
|
||||||
|
fields = (fields,)
|
||||||
|
for field in fields:
|
||||||
|
check_formfield(cls, model, opts, "fieldsets[%d][1]['fields']" % idx, field)
|
||||||
|
try:
|
||||||
|
f = opts.get_field(field)
|
||||||
|
if isinstance(f, models.ManyToManyField) and not f.rel.through._meta.auto_created:
|
||||||
|
raise ImproperlyConfigured("'%s.fieldsets[%d][1]['fields']' "
|
||||||
|
"can't include the ManyToManyField field '%s' because "
|
||||||
|
"'%s' manually specifies a 'through' model." % (
|
||||||
|
cls.__name__, idx, field, field))
|
||||||
|
except models.FieldDoesNotExist:
|
||||||
|
# If we can't find a field on the model that matches,
|
||||||
|
# it could be an extra field on the form.
|
||||||
|
pass
|
||||||
flattened_fieldsets = flatten_fieldsets(cls.fieldsets)
|
flattened_fieldsets = flatten_fieldsets(cls.fieldsets)
|
||||||
if len(flattened_fieldsets) > len(set(flattened_fieldsets)):
|
if len(flattened_fieldsets) > len(set(flattened_fieldsets)):
|
||||||
raise ImproperlyConfigured('There are duplicate field(s) in %s.fieldsets' % cls.__name__)
|
raise ImproperlyConfigured('There are duplicate field(s) in %s.fieldsets' % cls.__name__)
|
||||||
for field in flattened_fieldsets:
|
|
||||||
check_formfield(cls, model, opts, "fieldsets[%d][1]['fields']" % idx, field)
|
|
||||||
|
|
||||||
# form
|
# form
|
||||||
if hasattr(cls, 'form') and not issubclass(cls.form, BaseModelForm):
|
if hasattr(cls, 'form') and not issubclass(cls.form, BaseModelForm):
|
||||||
|
@ -18,18 +18,21 @@ SpatialBackend = BaseSpatialBackend(name='postgis', postgis=True,
|
|||||||
distance_spheroid=DISTANCE_SPHEROID,
|
distance_spheroid=DISTANCE_SPHEROID,
|
||||||
envelope=ENVELOPE,
|
envelope=ENVELOPE,
|
||||||
extent=EXTENT,
|
extent=EXTENT,
|
||||||
|
extent3d=EXTENT3D,
|
||||||
gis_terms=POSTGIS_TERMS,
|
gis_terms=POSTGIS_TERMS,
|
||||||
geojson=ASGEOJSON,
|
geojson=ASGEOJSON,
|
||||||
gml=ASGML,
|
gml=ASGML,
|
||||||
intersection=INTERSECTION,
|
intersection=INTERSECTION,
|
||||||
kml=ASKML,
|
kml=ASKML,
|
||||||
length=LENGTH,
|
length=LENGTH,
|
||||||
|
length3d=LENGTH3D,
|
||||||
length_spheroid=LENGTH_SPHEROID,
|
length_spheroid=LENGTH_SPHEROID,
|
||||||
make_line=MAKE_LINE,
|
make_line=MAKE_LINE,
|
||||||
mem_size=MEM_SIZE,
|
mem_size=MEM_SIZE,
|
||||||
num_geom=NUM_GEOM,
|
num_geom=NUM_GEOM,
|
||||||
num_points=NUM_POINTS,
|
num_points=NUM_POINTS,
|
||||||
perimeter=PERIMETER,
|
perimeter=PERIMETER,
|
||||||
|
perimeter3d=PERIMETER3D,
|
||||||
point_on_surface=POINT_ON_SURFACE,
|
point_on_surface=POINT_ON_SURFACE,
|
||||||
scale=SCALE,
|
scale=SCALE,
|
||||||
select=GEOM_SELECT,
|
select=GEOM_SELECT,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
This object provides quoting for GEOS geometries into PostgreSQL/PostGIS.
|
This object provides quoting for GEOS geometries into PostgreSQL/PostGIS.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.contrib.gis.db.backend.postgis.query import GEOM_FROM_WKB
|
from django.contrib.gis.db.backend.postgis.query import GEOM_FROM_EWKB
|
||||||
from psycopg2 import Binary
|
from psycopg2 import Binary
|
||||||
from psycopg2.extensions import ISQLQuote
|
from psycopg2.extensions import ISQLQuote
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ class PostGISAdaptor(object):
|
|||||||
"Initializes on the geometry."
|
"Initializes on the geometry."
|
||||||
# Getting the WKB (in string form, to allow easy pickling of
|
# Getting the WKB (in string form, to allow easy pickling of
|
||||||
# the adaptor) and the SRID from the geometry.
|
# the adaptor) and the SRID from the geometry.
|
||||||
self.wkb = str(geom.wkb)
|
self.ewkb = str(geom.ewkb)
|
||||||
self.srid = geom.srid
|
self.srid = geom.srid
|
||||||
|
|
||||||
def __conform__(self, proto):
|
def __conform__(self, proto):
|
||||||
@ -30,7 +30,7 @@ class PostGISAdaptor(object):
|
|||||||
def getquoted(self):
|
def getquoted(self):
|
||||||
"Returns a properly quoted string for use in PostgreSQL/PostGIS."
|
"Returns a properly quoted string for use in PostgreSQL/PostGIS."
|
||||||
# Want to use WKB, so wrap with psycopg2 Binary() to quote properly.
|
# Want to use WKB, so wrap with psycopg2 Binary() to quote properly.
|
||||||
return "%s(%s, %s)" % (GEOM_FROM_WKB, Binary(self.wkb), self.srid or -1)
|
return "%s(E%s)" % (GEOM_FROM_EWKB, Binary(self.ewkb))
|
||||||
|
|
||||||
def prepare_database_save(self, unused):
|
def prepare_database_save(self, unused):
|
||||||
return self
|
return self
|
||||||
|
@ -63,17 +63,21 @@ if MAJOR_VERSION >= 1:
|
|||||||
DISTANCE_SPHERE = get_func('distance_sphere')
|
DISTANCE_SPHERE = get_func('distance_sphere')
|
||||||
DISTANCE_SPHEROID = get_func('distance_spheroid')
|
DISTANCE_SPHEROID = get_func('distance_spheroid')
|
||||||
ENVELOPE = get_func('Envelope')
|
ENVELOPE = get_func('Envelope')
|
||||||
EXTENT = get_func('extent')
|
EXTENT = get_func('Extent')
|
||||||
|
EXTENT3D = get_func('Extent3D')
|
||||||
GEOM_FROM_TEXT = get_func('GeomFromText')
|
GEOM_FROM_TEXT = get_func('GeomFromText')
|
||||||
|
GEOM_FROM_EWKB = get_func('GeomFromEWKB')
|
||||||
GEOM_FROM_WKB = get_func('GeomFromWKB')
|
GEOM_FROM_WKB = get_func('GeomFromWKB')
|
||||||
INTERSECTION = get_func('Intersection')
|
INTERSECTION = get_func('Intersection')
|
||||||
LENGTH = get_func('Length')
|
LENGTH = get_func('Length')
|
||||||
|
LENGTH3D = get_func('Length3D')
|
||||||
LENGTH_SPHEROID = get_func('length_spheroid')
|
LENGTH_SPHEROID = get_func('length_spheroid')
|
||||||
MAKE_LINE = get_func('MakeLine')
|
MAKE_LINE = get_func('MakeLine')
|
||||||
MEM_SIZE = get_func('mem_size')
|
MEM_SIZE = get_func('mem_size')
|
||||||
NUM_GEOM = get_func('NumGeometries')
|
NUM_GEOM = get_func('NumGeometries')
|
||||||
NUM_POINTS = get_func('npoints')
|
NUM_POINTS = get_func('npoints')
|
||||||
PERIMETER = get_func('Perimeter')
|
PERIMETER = get_func('Perimeter')
|
||||||
|
PERIMETER3D = get_func('Perimeter3D')
|
||||||
POINT_ON_SURFACE = get_func('PointOnSurface')
|
POINT_ON_SURFACE = get_func('PointOnSurface')
|
||||||
SCALE = get_func('Scale')
|
SCALE = get_func('Scale')
|
||||||
SNAP_TO_GRID = get_func('SnapToGrid')
|
SNAP_TO_GRID = get_func('SnapToGrid')
|
||||||
|
@ -24,6 +24,9 @@ class Collect(GeoAggregate):
|
|||||||
class Extent(GeoAggregate):
|
class Extent(GeoAggregate):
|
||||||
name = 'Extent'
|
name = 'Extent'
|
||||||
|
|
||||||
|
class Extent3D(GeoAggregate):
|
||||||
|
name = 'Extent3D'
|
||||||
|
|
||||||
class MakeLine(GeoAggregate):
|
class MakeLine(GeoAggregate):
|
||||||
name = 'MakeLine'
|
name = 'MakeLine'
|
||||||
|
|
||||||
|
@ -34,6 +34,9 @@ class GeoManager(Manager):
|
|||||||
def extent(self, *args, **kwargs):
|
def extent(self, *args, **kwargs):
|
||||||
return self.get_query_set().extent(*args, **kwargs)
|
return self.get_query_set().extent(*args, **kwargs)
|
||||||
|
|
||||||
|
def extent3d(self, *args, **kwargs):
|
||||||
|
return self.get_query_set().extent3d(*args, **kwargs)
|
||||||
|
|
||||||
def geojson(self, *args, **kwargs):
|
def geojson(self, *args, **kwargs):
|
||||||
return self.get_query_set().geojson(*args, **kwargs)
|
return self.get_query_set().geojson(*args, **kwargs)
|
||||||
|
|
||||||
|
@ -110,6 +110,14 @@ class GeoQuerySet(QuerySet):
|
|||||||
"""
|
"""
|
||||||
return self._spatial_aggregate(aggregates.Extent, **kwargs)
|
return self._spatial_aggregate(aggregates.Extent, **kwargs)
|
||||||
|
|
||||||
|
def extent3d(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Returns the aggregate extent, in 3D, of the features in the
|
||||||
|
GeoQuerySet. It is returned as a 6-tuple, comprising:
|
||||||
|
(xmin, ymin, zmin, xmax, ymax, zmax).
|
||||||
|
"""
|
||||||
|
return self._spatial_aggregate(aggregates.Extent3D, **kwargs)
|
||||||
|
|
||||||
def geojson(self, precision=8, crs=False, bbox=False, **kwargs):
|
def geojson(self, precision=8, crs=False, bbox=False, **kwargs):
|
||||||
"""
|
"""
|
||||||
Returns a GeoJSON representation of the geomtry field in a `geojson`
|
Returns a GeoJSON representation of the geomtry field in a `geojson`
|
||||||
@ -524,12 +532,14 @@ class GeoQuerySet(QuerySet):
|
|||||||
else:
|
else:
|
||||||
dist_att = Distance.unit_attname(geo_field.units_name)
|
dist_att = Distance.unit_attname(geo_field.units_name)
|
||||||
|
|
||||||
# Shortcut booleans for what distance function we're using.
|
# Shortcut booleans for what distance function we're using and
|
||||||
|
# whether the geometry field is 3D.
|
||||||
distance = func == 'distance'
|
distance = func == 'distance'
|
||||||
length = func == 'length'
|
length = func == 'length'
|
||||||
perimeter = func == 'perimeter'
|
perimeter = func == 'perimeter'
|
||||||
if not (distance or length or perimeter):
|
if not (distance or length or perimeter):
|
||||||
raise ValueError('Unknown distance function: %s' % func)
|
raise ValueError('Unknown distance function: %s' % func)
|
||||||
|
geom_3d = geo_field.dim == 3
|
||||||
|
|
||||||
# The field's get_db_prep_lookup() is used to get any
|
# The field's get_db_prep_lookup() is used to get any
|
||||||
# extra distance parameters. Here we set up the
|
# extra distance parameters. Here we set up the
|
||||||
@ -604,7 +614,7 @@ class GeoQuerySet(QuerySet):
|
|||||||
# some error checking is required.
|
# some error checking is required.
|
||||||
if not isinstance(geo_field, PointField):
|
if not isinstance(geo_field, PointField):
|
||||||
raise ValueError('Spherical distance calculation only supported on PointFields.')
|
raise ValueError('Spherical distance calculation only supported on PointFields.')
|
||||||
if not str(SpatialBackend.Geometry(buffer(params[0].wkb)).geom_type) == 'Point':
|
if not str(SpatialBackend.Geometry(buffer(params[0].ewkb)).geom_type) == 'Point':
|
||||||
raise ValueError('Spherical distance calculation only supported with Point Geometry parameters')
|
raise ValueError('Spherical distance calculation only supported with Point Geometry parameters')
|
||||||
# The `function` procedure argument needs to be set differently for
|
# The `function` procedure argument needs to be set differently for
|
||||||
# geodetic distance calculations.
|
# geodetic distance calculations.
|
||||||
@ -617,9 +627,16 @@ class GeoQuerySet(QuerySet):
|
|||||||
elif length or perimeter:
|
elif length or perimeter:
|
||||||
procedure_fmt = '%(geo_col)s'
|
procedure_fmt = '%(geo_col)s'
|
||||||
if geodetic and length:
|
if geodetic and length:
|
||||||
# There's no `length_sphere`
|
# There's no `length_sphere`, and `length_spheroid` also
|
||||||
|
# works on 3D geometries.
|
||||||
procedure_fmt += ',%(spheroid)s'
|
procedure_fmt += ',%(spheroid)s'
|
||||||
procedure_args.update({'function' : SpatialBackend.length_spheroid, 'spheroid' : where[1]})
|
procedure_args.update({'function' : SpatialBackend.length_spheroid, 'spheroid' : where[1]})
|
||||||
|
elif geom_3d and SpatialBackend.postgis:
|
||||||
|
# Use 3D variants of perimeter and length routines on PostGIS.
|
||||||
|
if perimeter:
|
||||||
|
procedure_args.update({'function' : SpatialBackend.perimeter3d})
|
||||||
|
elif length:
|
||||||
|
procedure_args.update({'function' : SpatialBackend.length3d})
|
||||||
|
|
||||||
# Setting up the settings for `_spatial_attribute`.
|
# Setting up the settings for `_spatial_attribute`.
|
||||||
s = {'select_field' : DistanceField(dist_att),
|
s = {'select_field' : DistanceField(dist_att),
|
||||||
|
@ -11,6 +11,9 @@ geo_template = '%(function)s(%(field)s)'
|
|||||||
def convert_extent(box):
|
def convert_extent(box):
|
||||||
raise NotImplementedError('Aggregate extent not implemented for this spatial backend.')
|
raise NotImplementedError('Aggregate extent not implemented for this spatial backend.')
|
||||||
|
|
||||||
|
def convert_extent3d(box):
|
||||||
|
raise NotImplementedError('Aggregate 3D extent not implemented for this spatial backend.')
|
||||||
|
|
||||||
def convert_geom(wkt, geo_field):
|
def convert_geom(wkt, geo_field):
|
||||||
raise NotImplementedError('Aggregate method not implemented for this spatial backend.')
|
raise NotImplementedError('Aggregate method not implemented for this spatial backend.')
|
||||||
|
|
||||||
@ -23,6 +26,14 @@ if SpatialBackend.postgis:
|
|||||||
xmax, ymax = map(float, ur.split())
|
xmax, ymax = map(float, ur.split())
|
||||||
return (xmin, ymin, xmax, ymax)
|
return (xmin, ymin, xmax, ymax)
|
||||||
|
|
||||||
|
def convert_extent3d(box3d):
|
||||||
|
# Box text will be something like "BOX3D(-90.0 30.0 1, -85.0 40.0 2)";
|
||||||
|
# parsing out and returning as a 4-tuple.
|
||||||
|
ll, ur = box3d[6:-1].split(',')
|
||||||
|
xmin, ymin, zmin = map(float, ll.split())
|
||||||
|
xmax, ymax, zmax = map(float, ur.split())
|
||||||
|
return (xmin, ymin, zmin, xmax, ymax, zmax)
|
||||||
|
|
||||||
def convert_geom(hex, geo_field):
|
def convert_geom(hex, geo_field):
|
||||||
if hex: return SpatialBackend.Geometry(hex)
|
if hex: return SpatialBackend.Geometry(hex)
|
||||||
else: return None
|
else: return None
|
||||||
@ -94,7 +105,7 @@ class Collect(GeoAggregate):
|
|||||||
sql_function = SpatialBackend.collect
|
sql_function = SpatialBackend.collect
|
||||||
|
|
||||||
class Extent(GeoAggregate):
|
class Extent(GeoAggregate):
|
||||||
is_extent = True
|
is_extent = '2D'
|
||||||
sql_function = SpatialBackend.extent
|
sql_function = SpatialBackend.extent
|
||||||
|
|
||||||
if SpatialBackend.oracle:
|
if SpatialBackend.oracle:
|
||||||
@ -102,6 +113,10 @@ if SpatialBackend.oracle:
|
|||||||
Extent.conversion_class = GeomField
|
Extent.conversion_class = GeomField
|
||||||
Extent.sql_template = '%(function)s(%(field)s)'
|
Extent.sql_template = '%(function)s(%(field)s)'
|
||||||
|
|
||||||
|
class Extent3D(GeoAggregate):
|
||||||
|
is_extent = '3D'
|
||||||
|
sql_function = SpatialBackend.extent3d
|
||||||
|
|
||||||
class MakeLine(GeoAggregate):
|
class MakeLine(GeoAggregate):
|
||||||
conversion_class = GeomField
|
conversion_class = GeomField
|
||||||
sql_function = SpatialBackend.make_line
|
sql_function = SpatialBackend.make_line
|
||||||
|
@ -262,7 +262,10 @@ class GeoQuery(sql.Query):
|
|||||||
"""
|
"""
|
||||||
if isinstance(aggregate, self.aggregates_module.GeoAggregate):
|
if isinstance(aggregate, self.aggregates_module.GeoAggregate):
|
||||||
if aggregate.is_extent:
|
if aggregate.is_extent:
|
||||||
return self.aggregates_module.convert_extent(value)
|
if aggregate.is_extent == '3D':
|
||||||
|
return self.aggregates_module.convert_extent3d(value)
|
||||||
|
else:
|
||||||
|
return self.aggregates_module.convert_extent(value)
|
||||||
else:
|
else:
|
||||||
return self.aggregates_module.convert_geom(value, aggregate.source)
|
return self.aggregates_module.convert_geom(value, aggregate.source)
|
||||||
else:
|
else:
|
||||||
|
@ -214,13 +214,7 @@ class OGRGeometry(GDALBase):
|
|||||||
@property
|
@property
|
||||||
def geom_type(self):
|
def geom_type(self):
|
||||||
"Returns the Type for this Geometry."
|
"Returns the Type for this Geometry."
|
||||||
try:
|
return OGRGeomType(capi.get_geom_type(self.ptr))
|
||||||
return OGRGeomType(capi.get_geom_type(self.ptr))
|
|
||||||
except OGRException:
|
|
||||||
# VRT datasources return an invalid geometry type
|
|
||||||
# number, but a valid name -- we'll try that instead.
|
|
||||||
# See: http://trac.osgeo.org/gdal/ticket/2491
|
|
||||||
return OGRGeomType(capi.get_geom_name(self.ptr))
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def geom_name(self):
|
def geom_name(self):
|
||||||
@ -684,4 +678,11 @@ GEO_CLASSES = {1 : Point,
|
|||||||
6 : MultiPolygon,
|
6 : MultiPolygon,
|
||||||
7 : GeometryCollection,
|
7 : GeometryCollection,
|
||||||
101: LinearRing,
|
101: LinearRing,
|
||||||
|
1 + OGRGeomType.wkb25bit : Point,
|
||||||
|
2 + OGRGeomType.wkb25bit : LineString,
|
||||||
|
3 + OGRGeomType.wkb25bit : Polygon,
|
||||||
|
4 + OGRGeomType.wkb25bit : MultiPoint,
|
||||||
|
5 + OGRGeomType.wkb25bit : MultiLineString,
|
||||||
|
6 + OGRGeomType.wkb25bit : MultiPolygon,
|
||||||
|
7 + OGRGeomType.wkb25bit : GeometryCollection,
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ from django.contrib.gis.gdal.error import OGRException
|
|||||||
class OGRGeomType(object):
|
class OGRGeomType(object):
|
||||||
"Encapulates OGR Geometry Types."
|
"Encapulates OGR Geometry Types."
|
||||||
|
|
||||||
|
wkb25bit = -2147483648
|
||||||
|
|
||||||
# Dictionary of acceptable OGRwkbGeometryType s and their string names.
|
# Dictionary of acceptable OGRwkbGeometryType s and their string names.
|
||||||
_types = {0 : 'Unknown',
|
_types = {0 : 'Unknown',
|
||||||
1 : 'Point',
|
1 : 'Point',
|
||||||
@ -15,6 +17,13 @@ class OGRGeomType(object):
|
|||||||
7 : 'GeometryCollection',
|
7 : 'GeometryCollection',
|
||||||
100 : 'None',
|
100 : 'None',
|
||||||
101 : 'LinearRing',
|
101 : 'LinearRing',
|
||||||
|
1 + wkb25bit: 'Point25D',
|
||||||
|
2 + wkb25bit: 'LineString25D',
|
||||||
|
3 + wkb25bit: 'Polygon25D',
|
||||||
|
4 + wkb25bit: 'MultiPoint25D',
|
||||||
|
5 + wkb25bit : 'MultiLineString25D',
|
||||||
|
6 + wkb25bit : 'MultiPolygon25D',
|
||||||
|
7 + wkb25bit : 'GeometryCollection25D',
|
||||||
}
|
}
|
||||||
# Reverse type dictionary, keyed by lower-case of the name.
|
# Reverse type dictionary, keyed by lower-case of the name.
|
||||||
_str_types = dict([(v.lower(), k) for k, v in _types.items()])
|
_str_types = dict([(v.lower(), k) for k, v in _types.items()])
|
||||||
@ -68,7 +77,7 @@ class OGRGeomType(object):
|
|||||||
@property
|
@property
|
||||||
def django(self):
|
def django(self):
|
||||||
"Returns the Django GeometryField for this OGR Type."
|
"Returns the Django GeometryField for this OGR Type."
|
||||||
s = self.name
|
s = self.name.replace('25D', '')
|
||||||
if s in ('LinearRing', 'None'):
|
if s in ('LinearRing', 'None'):
|
||||||
return None
|
return None
|
||||||
elif s == 'Unknown':
|
elif s == 'Unknown':
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Needed ctypes routines
|
# Needed ctypes routines
|
||||||
from ctypes import byref
|
from ctypes import c_double, byref
|
||||||
|
|
||||||
# Other GDAL imports.
|
# Other GDAL imports.
|
||||||
from django.contrib.gis.gdal.base import GDALBase
|
from django.contrib.gis.gdal.base import GDALBase
|
||||||
@ -7,11 +7,12 @@ from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
|
|||||||
from django.contrib.gis.gdal.error import OGRException, OGRIndexError, SRSException
|
from django.contrib.gis.gdal.error import OGRException, OGRIndexError, SRSException
|
||||||
from django.contrib.gis.gdal.feature import Feature
|
from django.contrib.gis.gdal.feature import Feature
|
||||||
from django.contrib.gis.gdal.field import OGRFieldTypes
|
from django.contrib.gis.gdal.field import OGRFieldTypes
|
||||||
from django.contrib.gis.gdal.geometries import OGRGeomType
|
from django.contrib.gis.gdal.geomtype import OGRGeomType
|
||||||
|
from django.contrib.gis.gdal.geometries import OGRGeometry
|
||||||
from django.contrib.gis.gdal.srs import SpatialReference
|
from django.contrib.gis.gdal.srs import SpatialReference
|
||||||
|
|
||||||
# GDAL ctypes function prototypes.
|
# GDAL ctypes function prototypes.
|
||||||
from django.contrib.gis.gdal.prototypes import ds as capi, srs as srs_api
|
from django.contrib.gis.gdal.prototypes import ds as capi, geom as geom_api, srs as srs_api
|
||||||
|
|
||||||
# For more information, see the OGR C API source code:
|
# For more information, see the OGR C API source code:
|
||||||
# http://www.gdal.org/ogr/ogr__api_8h.html
|
# http://www.gdal.org/ogr/ogr__api_8h.html
|
||||||
@ -156,6 +157,29 @@ class Layer(GDALBase):
|
|||||||
return [capi.get_field_precision(capi.get_field_defn(self._ldefn, i))
|
return [capi.get_field_precision(capi.get_field_defn(self._ldefn, i))
|
||||||
for i in xrange(self.num_fields)]
|
for i in xrange(self.num_fields)]
|
||||||
|
|
||||||
|
def _get_spatial_filter(self):
|
||||||
|
try:
|
||||||
|
return OGRGeometry(geom_api.clone_geom(capi.get_spatial_filter(self.ptr)))
|
||||||
|
except OGRException:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _set_spatial_filter(self, filter):
|
||||||
|
if isinstance(filter, OGRGeometry):
|
||||||
|
capi.set_spatial_filter(self.ptr, filter.ptr)
|
||||||
|
elif isinstance(filter, (tuple, list)):
|
||||||
|
if not len(filter) == 4:
|
||||||
|
raise ValueError('Spatial filter list/tuple must have 4 elements.')
|
||||||
|
# Map c_double onto params -- if a bad type is passed in it
|
||||||
|
# will be caught here.
|
||||||
|
xmin, ymin, xmax, ymax = map(c_double, filter)
|
||||||
|
capi.set_spatial_filter_rect(self.ptr, xmin, ymin, xmax, ymax)
|
||||||
|
elif filter is None:
|
||||||
|
capi.set_spatial_filter(self.ptr, None)
|
||||||
|
else:
|
||||||
|
raise TypeError('Spatial filter must be either an OGRGeometry instance, a 4-tuple, or None.')
|
||||||
|
|
||||||
|
spatial_filter = property(_get_spatial_filter, _set_spatial_filter)
|
||||||
|
|
||||||
#### Layer Methods ####
|
#### Layer Methods ####
|
||||||
def get_fields(self, field_name):
|
def get_fields(self, field_name):
|
||||||
"""
|
"""
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
related data structures. OGR_Dr_*, OGR_DS_*, OGR_L_*, OGR_F_*,
|
related data structures. OGR_Dr_*, OGR_DS_*, OGR_L_*, OGR_F_*,
|
||||||
OGR_Fld_* routines are relevant here.
|
OGR_Fld_* routines are relevant here.
|
||||||
"""
|
"""
|
||||||
from ctypes import c_char_p, c_int, c_long, c_void_p, POINTER
|
from ctypes import c_char_p, c_double, c_int, c_long, c_void_p, POINTER
|
||||||
from django.contrib.gis.gdal.envelope import OGREnvelope
|
from django.contrib.gis.gdal.envelope import OGREnvelope
|
||||||
from django.contrib.gis.gdal.libgdal import lgdal
|
from django.contrib.gis.gdal.libgdal import lgdal
|
||||||
from django.contrib.gis.gdal.prototypes.generation import \
|
from django.contrib.gis.gdal.prototypes.generation import \
|
||||||
@ -38,6 +38,9 @@ get_layer_srs = srs_output(lgdal.OGR_L_GetSpatialRef, [c_void_p])
|
|||||||
get_next_feature = voidptr_output(lgdal.OGR_L_GetNextFeature, [c_void_p])
|
get_next_feature = voidptr_output(lgdal.OGR_L_GetNextFeature, [c_void_p])
|
||||||
reset_reading = void_output(lgdal.OGR_L_ResetReading, [c_void_p], errcheck=False)
|
reset_reading = void_output(lgdal.OGR_L_ResetReading, [c_void_p], errcheck=False)
|
||||||
test_capability = int_output(lgdal.OGR_L_TestCapability, [c_void_p, c_char_p])
|
test_capability = int_output(lgdal.OGR_L_TestCapability, [c_void_p, c_char_p])
|
||||||
|
get_spatial_filter = geom_output(lgdal.OGR_L_GetSpatialFilter, [c_void_p])
|
||||||
|
set_spatial_filter = void_output(lgdal.OGR_L_SetSpatialFilter, [c_void_p, c_void_p], errcheck=False)
|
||||||
|
set_spatial_filter_rect = void_output(lgdal.OGR_L_SetSpatialFilterRect, [c_void_p, c_double, c_double, c_double, c_double], errcheck=False)
|
||||||
|
|
||||||
### Feature Definition Routines ###
|
### Feature Definition Routines ###
|
||||||
get_fd_geom_type = int_output(lgdal.OGR_FD_GetGeomType, [c_void_p])
|
get_fd_geom_type = int_output(lgdal.OGR_FD_GetGeomType, [c_void_p])
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
import os, os.path, unittest
|
import os, os.path, unittest
|
||||||
from django.contrib.gis.gdal import DataSource, Envelope, OGRException, OGRIndexError
|
from django.contrib.gis.gdal import DataSource, Envelope, OGRGeometry, OGRException, OGRIndexError
|
||||||
from django.contrib.gis.gdal.field import OFTReal, OFTInteger, OFTString
|
from django.contrib.gis.gdal.field import OFTReal, OFTInteger, OFTString
|
||||||
from django.contrib import gis
|
from django.contrib import gis
|
||||||
|
|
||||||
# Path for SHP files
|
# Path for SHP files
|
||||||
data_path = os.path.join(os.path.dirname(gis.__file__), 'tests' + os.sep + 'data')
|
data_path = os.path.join(os.path.dirname(gis.__file__), 'tests' + os.sep + 'data')
|
||||||
def get_ds_file(name, ext):
|
def get_ds_file(name, ext):
|
||||||
|
|
||||||
|
|
||||||
return os.sep.join([data_path, name, name + '.%s' % ext])
|
return os.sep.join([data_path, name, name + '.%s' % ext])
|
||||||
|
|
||||||
# Test SHP data source object
|
# Test SHP data source object
|
||||||
@ -25,7 +23,7 @@ ds_list = (TestDS('test_point', nfeat=5, nfld=3, geom='POINT', gtype=1, driver='
|
|||||||
srs_wkt='GEOGCS["GCS_WGS_1984",DATUM["WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]',
|
srs_wkt='GEOGCS["GCS_WGS_1984",DATUM["WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]',
|
||||||
field_values={'dbl' : [float(i) for i in range(1, 6)], 'int' : range(1, 6), 'str' : [str(i) for i in range(1, 6)]},
|
field_values={'dbl' : [float(i) for i in range(1, 6)], 'int' : range(1, 6), 'str' : [str(i) for i in range(1, 6)]},
|
||||||
fids=range(5)),
|
fids=range(5)),
|
||||||
TestDS('test_vrt', ext='vrt', nfeat=3, nfld=3, geom='POINT', gtype=1, driver='VRT',
|
TestDS('test_vrt', ext='vrt', nfeat=3, nfld=3, geom='POINT', gtype='Point25D', driver='VRT',
|
||||||
fields={'POINT_X' : OFTString, 'POINT_Y' : OFTString, 'NUM' : OFTString}, # VRT uses CSV, which all types are OFTString.
|
fields={'POINT_X' : OFTString, 'POINT_Y' : OFTString, 'NUM' : OFTString}, # VRT uses CSV, which all types are OFTString.
|
||||||
extent=(1.0, 2.0, 100.0, 523.5), # Min/Max from CSV
|
extent=(1.0, 2.0, 100.0, 523.5), # Min/Max from CSV
|
||||||
field_values={'POINT_X' : ['1.0', '5.0', '100.0'], 'POINT_Y' : ['2.0', '23.0', '523.5'], 'NUM' : ['5', '17', '23']},
|
field_values={'POINT_X' : ['1.0', '5.0', '100.0'], 'POINT_Y' : ['2.0', '23.0', '523.5'], 'NUM' : ['5', '17', '23']},
|
||||||
@ -191,6 +189,40 @@ class DataSourceTest(unittest.TestCase):
|
|||||||
if hasattr(source, 'srs_wkt'):
|
if hasattr(source, 'srs_wkt'):
|
||||||
self.assertEqual(source.srs_wkt, g.srs.wkt)
|
self.assertEqual(source.srs_wkt, g.srs.wkt)
|
||||||
|
|
||||||
|
def test06_spatial_filter(self):
|
||||||
|
"Testing the Layer.spatial_filter property."
|
||||||
|
ds = DataSource(get_ds_file('cities', 'shp'))
|
||||||
|
lyr = ds[0]
|
||||||
|
|
||||||
|
# When not set, it should be None.
|
||||||
|
self.assertEqual(None, lyr.spatial_filter)
|
||||||
|
|
||||||
|
# Must be set a/an OGRGeometry or 4-tuple.
|
||||||
|
self.assertRaises(TypeError, lyr._set_spatial_filter, 'foo')
|
||||||
|
|
||||||
|
# Setting the spatial filter with a tuple/list with the extent of
|
||||||
|
# a buffer centering around Pueblo.
|
||||||
|
self.assertRaises(ValueError, lyr._set_spatial_filter, range(5))
|
||||||
|
filter_extent = (-105.609252, 37.255001, -103.609252, 39.255001)
|
||||||
|
lyr.spatial_filter = (-105.609252, 37.255001, -103.609252, 39.255001)
|
||||||
|
self.assertEqual(OGRGeometry.from_bbox(filter_extent), lyr.spatial_filter)
|
||||||
|
feats = [feat for feat in lyr]
|
||||||
|
self.assertEqual(1, len(feats))
|
||||||
|
self.assertEqual('Pueblo', feats[0].get('Name'))
|
||||||
|
|
||||||
|
# Setting the spatial filter with an OGRGeometry for buffer centering
|
||||||
|
# around Houston.
|
||||||
|
filter_geom = OGRGeometry('POLYGON((-96.363151 28.763374,-94.363151 28.763374,-94.363151 30.763374,-96.363151 30.763374,-96.363151 28.763374))')
|
||||||
|
lyr.spatial_filter = filter_geom
|
||||||
|
self.assertEqual(filter_geom, lyr.spatial_filter)
|
||||||
|
feats = [feat for feat in lyr]
|
||||||
|
self.assertEqual(1, len(feats))
|
||||||
|
self.assertEqual('Houston', feats[0].get('Name'))
|
||||||
|
|
||||||
|
# Clearing the spatial filter by setting it to None. Now
|
||||||
|
# should indicate that there are 3 features in the Layer.
|
||||||
|
lyr.spatial_filter = None
|
||||||
|
self.assertEqual(3, len(lyr))
|
||||||
|
|
||||||
def suite():
|
def suite():
|
||||||
s = unittest.TestSuite()
|
s = unittest.TestSuite()
|
||||||
|
@ -46,6 +46,13 @@ class OGRGeomTest(unittest.TestCase):
|
|||||||
self.assertEqual(0, gt.num)
|
self.assertEqual(0, gt.num)
|
||||||
self.assertEqual('Unknown', gt.name)
|
self.assertEqual('Unknown', gt.name)
|
||||||
|
|
||||||
|
def test00b_geomtype_25d(self):
|
||||||
|
"Testing OGRGeomType object with 25D types."
|
||||||
|
wkb25bit = OGRGeomType.wkb25bit
|
||||||
|
self.failUnless(OGRGeomType(wkb25bit + 1) == 'Point25D')
|
||||||
|
self.failUnless(OGRGeomType('MultiLineString25D') == (5 + wkb25bit))
|
||||||
|
self.assertEqual('GeometryCollectionField', OGRGeomType('GeometryCollection25D').django)
|
||||||
|
|
||||||
def test01a_wkt(self):
|
def test01a_wkt(self):
|
||||||
"Testing WKT output."
|
"Testing WKT output."
|
||||||
for g in wkt_out:
|
for g in wkt_out:
|
||||||
@ -418,6 +425,17 @@ class OGRGeomTest(unittest.TestCase):
|
|||||||
xmax, ymax = max(x), max(y)
|
xmax, ymax = max(x), max(y)
|
||||||
self.assertEqual((xmin, ymin, xmax, ymax), poly.extent)
|
self.assertEqual((xmin, ymin, xmax, ymax), poly.extent)
|
||||||
|
|
||||||
|
def test16_25D(self):
|
||||||
|
"Testing 2.5D geometries."
|
||||||
|
pnt_25d = OGRGeometry('POINT(1 2 3)')
|
||||||
|
self.assertEqual('Point25D', pnt_25d.geom_type.name)
|
||||||
|
self.assertEqual(3.0, pnt_25d.z)
|
||||||
|
self.assertEqual(3, pnt_25d.coord_dim)
|
||||||
|
ls_25d = OGRGeometry('LINESTRING(1 1 1,2 2 2,3 3 3)')
|
||||||
|
self.assertEqual('LineString25D', ls_25d.geom_type.name)
|
||||||
|
self.assertEqual([1.0, 2.0, 3.0], ls_25d.z)
|
||||||
|
self.assertEqual(3, ls_25d.coord_dim)
|
||||||
|
|
||||||
def suite():
|
def suite():
|
||||||
s = unittest.TestSuite()
|
s = unittest.TestSuite()
|
||||||
s.addTest(unittest.makeSuite(OGRGeomTest))
|
s.addTest(unittest.makeSuite(OGRGeomTest))
|
||||||
|
@ -357,26 +357,46 @@ class GEOSGeometry(GEOSBase, ListMixin):
|
|||||||
#### Output Routines ####
|
#### Output Routines ####
|
||||||
@property
|
@property
|
||||||
def ewkt(self):
|
def ewkt(self):
|
||||||
"Returns the EWKT (WKT + SRID) of the Geometry."
|
"""
|
||||||
|
Returns the EWKT (WKT + SRID) of the Geometry. Note that Z values
|
||||||
|
are *not* included in this representation because GEOS does not yet
|
||||||
|
support serializing them.
|
||||||
|
"""
|
||||||
if self.get_srid(): return 'SRID=%s;%s' % (self.srid, self.wkt)
|
if self.get_srid(): return 'SRID=%s;%s' % (self.srid, self.wkt)
|
||||||
else: return self.wkt
|
else: return self.wkt
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def wkt(self):
|
def wkt(self):
|
||||||
"Returns the WKT (Well-Known Text) of the Geometry."
|
"Returns the WKT (Well-Known Text) representation of this Geometry."
|
||||||
return wkt_w.write(self)
|
return wkt_w.write(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hex(self):
|
def hex(self):
|
||||||
"""
|
"""
|
||||||
Returns the HEX of the Geometry -- please note that the SRID is not
|
Returns the WKB of this Geometry in hexadecimal form. Please note
|
||||||
included in this representation, because the GEOS C library uses
|
that the SRID and Z values are not included in this representation
|
||||||
-1 by default, even if the SRID is set.
|
because it is not a part of the OGC specification (use the `hexewkb`
|
||||||
|
property instead).
|
||||||
"""
|
"""
|
||||||
# A possible faster, all-python, implementation:
|
# A possible faster, all-python, implementation:
|
||||||
# str(self.wkb).encode('hex')
|
# str(self.wkb).encode('hex')
|
||||||
return wkb_w.write_hex(self)
|
return wkb_w.write_hex(self)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hexewkb(self):
|
||||||
|
"""
|
||||||
|
Returns the EWKB of this Geometry in hexadecimal form. This is an
|
||||||
|
extension of the WKB specification that includes SRID and Z values
|
||||||
|
that are a part of this geometry.
|
||||||
|
"""
|
||||||
|
if self.hasz:
|
||||||
|
if not GEOS_PREPARE:
|
||||||
|
# See: http://trac.osgeo.org/geos/ticket/216
|
||||||
|
raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D HEXEWKB.')
|
||||||
|
return ewkb_w3d.write_hex(self)
|
||||||
|
else:
|
||||||
|
return ewkb_w.write_hex(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def json(self):
|
def json(self):
|
||||||
"""
|
"""
|
||||||
@ -391,9 +411,28 @@ class GEOSGeometry(GEOSBase, ListMixin):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def wkb(self):
|
def wkb(self):
|
||||||
"Returns the WKB of the Geometry as a buffer."
|
"""
|
||||||
|
Returns the WKB (Well-Known Binary) representation of this Geometry
|
||||||
|
as a Python buffer. SRID and Z values are not included, use the
|
||||||
|
`ewkb` property instead.
|
||||||
|
"""
|
||||||
return wkb_w.write(self)
|
return wkb_w.write(self)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ewkb(self):
|
||||||
|
"""
|
||||||
|
Return the EWKB representation of this Geometry as a Python buffer.
|
||||||
|
This is an extension of the WKB specification that includes any SRID
|
||||||
|
and Z values that are a part of this geometry.
|
||||||
|
"""
|
||||||
|
if self.hasz:
|
||||||
|
if not GEOS_PREPARE:
|
||||||
|
# See: http://trac.osgeo.org/geos/ticket/216
|
||||||
|
raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D EWKB.')
|
||||||
|
return ewkb_w3d.write(self)
|
||||||
|
else:
|
||||||
|
return ewkb_w.write(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def kml(self):
|
def kml(self):
|
||||||
"Returns the KML representation of this Geometry."
|
"Returns the KML representation of this Geometry."
|
||||||
@ -617,7 +656,7 @@ GEOS_CLASSES = {0 : Point,
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Similarly, import the GEOS I/O instances here to avoid conflicts.
|
# Similarly, import the GEOS I/O instances here to avoid conflicts.
|
||||||
from django.contrib.gis.geos.io import wkt_r, wkt_w, wkb_r, wkb_w
|
from django.contrib.gis.geos.io import wkt_r, wkt_w, wkb_r, wkb_w, ewkb_w, ewkb_w3d
|
||||||
|
|
||||||
# If supported, import the PreparedGeometry class.
|
# If supported, import the PreparedGeometry class.
|
||||||
if GEOS_PREPARE:
|
if GEOS_PREPARE:
|
||||||
|
@ -14,19 +14,19 @@ class IOBase(GEOSBase):
|
|||||||
"Base class for GEOS I/O objects."
|
"Base class for GEOS I/O objects."
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# Getting the pointer with the constructor.
|
# Getting the pointer with the constructor.
|
||||||
self.ptr = self.constructor()
|
self.ptr = self._constructor()
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
# Cleaning up with the appropriate destructor.
|
# Cleaning up with the appropriate destructor.
|
||||||
if self._ptr: self.destructor(self._ptr)
|
if self._ptr: self._destructor(self._ptr)
|
||||||
|
|
||||||
### WKT Reading and Writing objects ###
|
### WKT Reading and Writing objects ###
|
||||||
|
|
||||||
# Non-public class for internal use because its `read` method returns
|
# Non-public class for internal use because its `read` method returns
|
||||||
# _pointers_ instead of a GEOSGeometry object.
|
# _pointers_ instead of a GEOSGeometry object.
|
||||||
class _WKTReader(IOBase):
|
class _WKTReader(IOBase):
|
||||||
constructor = capi.wkt_reader_create
|
_constructor = capi.wkt_reader_create
|
||||||
destructor = capi.wkt_reader_destroy
|
_destructor = capi.wkt_reader_destroy
|
||||||
ptr_type = capi.WKT_READ_PTR
|
ptr_type = capi.WKT_READ_PTR
|
||||||
|
|
||||||
def read(self, wkt):
|
def read(self, wkt):
|
||||||
@ -39,8 +39,8 @@ class WKTReader(_WKTReader):
|
|||||||
return GEOSGeometry(super(WKTReader, self).read(wkt))
|
return GEOSGeometry(super(WKTReader, self).read(wkt))
|
||||||
|
|
||||||
class WKTWriter(IOBase):
|
class WKTWriter(IOBase):
|
||||||
constructor = capi.wkt_writer_create
|
_constructor = capi.wkt_writer_create
|
||||||
destructor = capi.wkt_writer_destroy
|
_destructor = capi.wkt_writer_destroy
|
||||||
ptr_type = capi.WKT_WRITE_PTR
|
ptr_type = capi.WKT_WRITE_PTR
|
||||||
|
|
||||||
def write(self, geom):
|
def write(self, geom):
|
||||||
@ -51,8 +51,8 @@ class WKTWriter(IOBase):
|
|||||||
|
|
||||||
# Non-public class for the same reason as _WKTReader above.
|
# Non-public class for the same reason as _WKTReader above.
|
||||||
class _WKBReader(IOBase):
|
class _WKBReader(IOBase):
|
||||||
constructor = capi.wkb_reader_create
|
_constructor = capi.wkb_reader_create
|
||||||
destructor = capi.wkb_reader_destroy
|
_destructor = capi.wkb_reader_destroy
|
||||||
ptr_type = capi.WKB_READ_PTR
|
ptr_type = capi.WKB_READ_PTR
|
||||||
|
|
||||||
def read(self, wkb):
|
def read(self, wkb):
|
||||||
@ -71,8 +71,8 @@ class WKBReader(_WKBReader):
|
|||||||
return GEOSGeometry(super(WKBReader, self).read(wkb))
|
return GEOSGeometry(super(WKBReader, self).read(wkb))
|
||||||
|
|
||||||
class WKBWriter(IOBase):
|
class WKBWriter(IOBase):
|
||||||
constructor = capi.wkb_writer_create
|
_constructor = capi.wkb_writer_create
|
||||||
destructor = capi.wkb_writer_destroy
|
_destructor = capi.wkb_writer_destroy
|
||||||
ptr_type = capi.WKB_WRITE_PTR
|
ptr_type = capi.WKB_WRITE_PTR
|
||||||
|
|
||||||
def write(self, geom):
|
def write(self, geom):
|
||||||
@ -121,3 +121,10 @@ wkt_r = _WKTReader()
|
|||||||
wkt_w = WKTWriter()
|
wkt_w = WKTWriter()
|
||||||
wkb_r = _WKBReader()
|
wkb_r = _WKBReader()
|
||||||
wkb_w = WKBWriter()
|
wkb_w = WKBWriter()
|
||||||
|
|
||||||
|
# These instances are for writing EWKB in 2D and 3D.
|
||||||
|
ewkb_w = WKBWriter()
|
||||||
|
ewkb_w.srid = True
|
||||||
|
ewkb_w3d = WKBWriter()
|
||||||
|
ewkb_w3d.srid = True
|
||||||
|
ewkb_w3d.outdim = 3
|
||||||
|
@ -62,17 +62,16 @@ def string_from_geom(func):
|
|||||||
|
|
||||||
### ctypes prototypes ###
|
### ctypes prototypes ###
|
||||||
|
|
||||||
# Deprecated creation routines from WKB, HEX, WKT
|
# Deprecated creation and output routines from WKB, HEX, WKT
|
||||||
from_hex = bin_constructor(lgeos.GEOSGeomFromHEX_buf)
|
from_hex = bin_constructor(lgeos.GEOSGeomFromHEX_buf)
|
||||||
from_wkb = bin_constructor(lgeos.GEOSGeomFromWKB_buf)
|
from_wkb = bin_constructor(lgeos.GEOSGeomFromWKB_buf)
|
||||||
from_wkt = geom_output(lgeos.GEOSGeomFromWKT, [c_char_p])
|
from_wkt = geom_output(lgeos.GEOSGeomFromWKT, [c_char_p])
|
||||||
|
|
||||||
# Output routines
|
|
||||||
to_hex = bin_output(lgeos.GEOSGeomToHEX_buf)
|
to_hex = bin_output(lgeos.GEOSGeomToHEX_buf)
|
||||||
to_wkb = bin_output(lgeos.GEOSGeomToWKB_buf)
|
to_wkb = bin_output(lgeos.GEOSGeomToWKB_buf)
|
||||||
to_wkt = string_from_geom(lgeos.GEOSGeomToWKT)
|
to_wkt = string_from_geom(lgeos.GEOSGeomToWKT)
|
||||||
|
|
||||||
# The GEOS geometry type, typeid, num_coordites and number of geometries
|
# The GEOS geometry type, typeid, num_coordinates and number of geometries
|
||||||
geos_normalize = int_from_geom(lgeos.GEOSNormalize)
|
geos_normalize = int_from_geom(lgeos.GEOSNormalize)
|
||||||
geos_type = string_from_geom(lgeos.GEOSGeomType)
|
geos_type = string_from_geom(lgeos.GEOSGeomType)
|
||||||
geos_typeid = int_from_geom(lgeos.GEOSGeomTypeId)
|
geos_typeid = int_from_geom(lgeos.GEOSGeomTypeId)
|
||||||
|
@ -71,6 +71,49 @@ class GEOSTest(unittest.TestCase):
|
|||||||
geom = fromstr(g.wkt)
|
geom = fromstr(g.wkt)
|
||||||
self.assertEqual(g.hex, geom.hex)
|
self.assertEqual(g.hex, geom.hex)
|
||||||
|
|
||||||
|
def test01b_hexewkb(self):
|
||||||
|
"Testing (HEX)EWKB output."
|
||||||
|
from binascii import a2b_hex
|
||||||
|
|
||||||
|
pnt_2d = Point(0, 1, srid=4326)
|
||||||
|
pnt_3d = Point(0, 1, 2, srid=4326)
|
||||||
|
|
||||||
|
# OGC-compliant HEX will not have SRID nor Z value.
|
||||||
|
self.assertEqual(ogc_hex, pnt_2d.hex)
|
||||||
|
self.assertEqual(ogc_hex, pnt_3d.hex)
|
||||||
|
|
||||||
|
# HEXEWKB should be appropriate for its dimension -- have to use an
|
||||||
|
# a WKBWriter w/dimension set accordingly, else GEOS will insert
|
||||||
|
# garbage into 3D coordinate if there is none. Also, GEOS has a
|
||||||
|
# a bug in versions prior to 3.1 that puts the X coordinate in
|
||||||
|
# place of Z; an exception should be raised on those versions.
|
||||||
|
self.assertEqual(hexewkb_2d, pnt_2d.hexewkb)
|
||||||
|
if GEOS_PREPARE:
|
||||||
|
self.assertEqual(hexewkb_3d, pnt_3d.hexewkb)
|
||||||
|
self.assertEqual(True, GEOSGeometry(hexewkb_3d).hasz)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
hexewkb = pnt_3d.hexewkb
|
||||||
|
except GEOSException:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.fail('Should have raised GEOSException.')
|
||||||
|
|
||||||
|
# Same for EWKB.
|
||||||
|
self.assertEqual(buffer(a2b_hex(hexewkb_2d)), pnt_2d.ewkb)
|
||||||
|
if GEOS_PREPARE:
|
||||||
|
self.assertEqual(buffer(a2b_hex(hexewkb_3d)), pnt_3d.ewkb)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
ewkb = pnt_3d.ewkb
|
||||||
|
except GEOSException:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.fail('Should have raised GEOSException')
|
||||||
|
|
||||||
|
# Redundant sanity check.
|
||||||
|
self.assertEqual(4326, GEOSGeometry(hexewkb_2d).srid)
|
||||||
|
|
||||||
def test01c_kml(self):
|
def test01c_kml(self):
|
||||||
"Testing KML output."
|
"Testing KML output."
|
||||||
for tg in wkt_out:
|
for tg in wkt_out:
|
||||||
|
@ -9,9 +9,10 @@ def geo_suite():
|
|||||||
some backends).
|
some backends).
|
||||||
"""
|
"""
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.contrib.gis.geos import GEOS_PREPARE
|
||||||
from django.contrib.gis.gdal import HAS_GDAL
|
from django.contrib.gis.gdal import HAS_GDAL
|
||||||
from django.contrib.gis.utils import HAS_GEOIP
|
from django.contrib.gis.utils import HAS_GEOIP
|
||||||
from django.contrib.gis.tests.utils import mysql
|
from django.contrib.gis.tests.utils import postgis, mysql
|
||||||
|
|
||||||
# The test suite.
|
# The test suite.
|
||||||
s = unittest.TestSuite()
|
s = unittest.TestSuite()
|
||||||
@ -32,6 +33,10 @@ def geo_suite():
|
|||||||
if not mysql:
|
if not mysql:
|
||||||
test_apps.append('distapp')
|
test_apps.append('distapp')
|
||||||
|
|
||||||
|
# Only PostGIS using GEOS 3.1+ can support 3D so far.
|
||||||
|
if postgis and GEOS_PREPARE:
|
||||||
|
test_apps.append('geo3d')
|
||||||
|
|
||||||
if HAS_GDAL:
|
if HAS_GDAL:
|
||||||
# These tests require GDAL.
|
# These tests require GDAL.
|
||||||
test_suite_names.extend(['test_spatialrefsys', 'test_geoforms'])
|
test_suite_names.extend(['test_spatialrefsys', 'test_geoforms'])
|
||||||
@ -164,20 +169,3 @@ def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[], suite=
|
|||||||
|
|
||||||
# Returning the total failures and errors
|
# Returning the total failures and errors
|
||||||
return len(result.failures) + len(result.errors)
|
return len(result.failures) + len(result.errors)
|
||||||
|
|
||||||
# Class for creating a fake module with a run method. This is for the
|
|
||||||
# GEOS and GDAL tests that were moved to their respective modules.
|
|
||||||
class _DeprecatedTestModule(object):
|
|
||||||
def __init__(self, mod_name):
|
|
||||||
self.mod_name = mod_name
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
from warnings import warn
|
|
||||||
warn('This test module is deprecated because it has moved to ' \
|
|
||||||
'`django.contrib.gis.%s.tests` and will disappear in 1.2.' %
|
|
||||||
self.mod_name, DeprecationWarning)
|
|
||||||
tests = import_module('django.contrib.gis.%s.tests' % self.mod_name)
|
|
||||||
tests.run()
|
|
||||||
|
|
||||||
test_geos = _DeprecatedTestModule('geos')
|
|
||||||
test_gdal = _DeprecatedTestModule('gdal')
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<OGRVRTDataSource>
|
<OGRVRTDataSource>
|
||||||
<OGRVRTLayer name="test_vrt">
|
<OGRVRTLayer name="test_vrt">
|
||||||
<SrcDataSource relativeToVRT="1">test_vrt.csv</SrcDataSource>
|
<SrcDataSource relativeToVRT="1">test_vrt.csv</SrcDataSource>
|
||||||
<GeometryType>wkbPoint</GeometryType>
|
<GeometryType>wkbPoint25D</GeometryType>
|
||||||
<GeometryField encoding="PointFromColumns" x="POINT_X" y="POINT_Y" z="NUM"/>
|
<GeometryField encoding="PointFromColumns" x="POINT_X" y="POINT_Y" z="NUM"/>
|
||||||
</OGRVRTLayer>
|
</OGRVRTLayer>
|
||||||
</OGRVRTDataSource>
|
</OGRVRTDataSource>
|
0
django/contrib/gis/tests/geo3d/__init__.py
Normal file
0
django/contrib/gis/tests/geo3d/__init__.py
Normal file
69
django/contrib/gis/tests/geo3d/models.py
Normal file
69
django/contrib/gis/tests/geo3d/models.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
from django.contrib.gis.db import models
|
||||||
|
|
||||||
|
class City3D(models.Model):
|
||||||
|
name = models.CharField(max_length=30)
|
||||||
|
point = models.PointField(dim=3)
|
||||||
|
objects = models.GeoManager()
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Interstate2D(models.Model):
|
||||||
|
name = models.CharField(max_length=30)
|
||||||
|
line = models.LineStringField(srid=4269)
|
||||||
|
objects = models.GeoManager()
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Interstate3D(models.Model):
|
||||||
|
name = models.CharField(max_length=30)
|
||||||
|
line = models.LineStringField(dim=3, srid=4269)
|
||||||
|
objects = models.GeoManager()
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class InterstateProj2D(models.Model):
|
||||||
|
name = models.CharField(max_length=30)
|
||||||
|
line = models.LineStringField(srid=32140)
|
||||||
|
objects = models.GeoManager()
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class InterstateProj3D(models.Model):
|
||||||
|
name = models.CharField(max_length=30)
|
||||||
|
line = models.LineStringField(dim=3, srid=32140)
|
||||||
|
objects = models.GeoManager()
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Polygon2D(models.Model):
|
||||||
|
name = models.CharField(max_length=30)
|
||||||
|
poly = models.PolygonField(srid=32140)
|
||||||
|
objects = models.GeoManager()
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Polygon3D(models.Model):
|
||||||
|
name = models.CharField(max_length=30)
|
||||||
|
poly = models.PolygonField(dim=3, srid=32140)
|
||||||
|
objects = models.GeoManager()
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Point2D(models.Model):
|
||||||
|
point = models.PointField()
|
||||||
|
objects = models.GeoManager()
|
||||||
|
|
||||||
|
class Point3D(models.Model):
|
||||||
|
point = models.PointField(dim=3)
|
||||||
|
objects = models.GeoManager()
|
||||||
|
|
||||||
|
class MultiPoint3D(models.Model):
|
||||||
|
mpoint = models.MultiPointField(dim=3)
|
||||||
|
objects = models.GeoManager()
|
234
django/contrib/gis/tests/geo3d/tests.py
Normal file
234
django/contrib/gis/tests/geo3d/tests.py
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
import os, re, unittest
|
||||||
|
from django.contrib.gis.db.models import Union, Extent3D
|
||||||
|
from django.contrib.gis.geos import GEOSGeometry, Point, Polygon
|
||||||
|
from django.contrib.gis.utils import LayerMapping, LayerMapError
|
||||||
|
|
||||||
|
from models import City3D, Interstate2D, Interstate3D, \
|
||||||
|
InterstateProj2D, InterstateProj3D, \
|
||||||
|
Point2D, Point3D, MultiPoint3D, Polygon2D, Polygon3D
|
||||||
|
|
||||||
|
data_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'data'))
|
||||||
|
city_file = os.path.join(data_path, 'cities', 'cities.shp')
|
||||||
|
vrt_file = os.path.join(data_path, 'test_vrt', 'test_vrt.vrt')
|
||||||
|
|
||||||
|
# The coordinates of each city, with Z values corresponding to their
|
||||||
|
# altitude in meters.
|
||||||
|
city_data = (
|
||||||
|
('Houston', (-95.363151, 29.763374, 18)),
|
||||||
|
('Dallas', (-96.801611, 32.782057, 147)),
|
||||||
|
('Oklahoma City', (-97.521157, 34.464642, 380)),
|
||||||
|
('Wellington', (174.783117, -41.315268, 14)),
|
||||||
|
('Pueblo', (-104.609252, 38.255001, 1433)),
|
||||||
|
('Lawrence', (-95.235060, 38.971823, 251)),
|
||||||
|
('Chicago', (-87.650175, 41.850385, 181)),
|
||||||
|
('Victoria', (-123.305196, 48.462611, 15)),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Reference mapping of city name to its altitude (Z value).
|
||||||
|
city_dict = dict((name, coords) for name, coords in city_data)
|
||||||
|
|
||||||
|
# 3D freeway data derived from the National Elevation Dataset:
|
||||||
|
# http://seamless.usgs.gov/products/9arc.php
|
||||||
|
interstate_data = (
|
||||||
|
('I-45',
|
||||||
|
'LINESTRING(-95.3708481 29.7765870 11.339,-95.3694580 29.7787980 4.536,-95.3690305 29.7797359 9.762,-95.3691886 29.7812450 12.448,-95.3696447 29.7850144 10.457,-95.3702511 29.7868518 9.418,-95.3706724 29.7881286 14.858,-95.3711632 29.7896157 15.386,-95.3714525 29.7936267 13.168,-95.3717848 29.7955007 15.104,-95.3717719 29.7969804 16.516,-95.3717305 29.7982117 13.923,-95.3717254 29.8000778 14.385,-95.3719875 29.8013539 15.160,-95.3720575 29.8026785 15.544,-95.3721321 29.8040912 14.975,-95.3722074 29.8050998 15.688,-95.3722779 29.8060430 16.099,-95.3733818 29.8076750 15.197,-95.3741563 29.8103686 17.268,-95.3749458 29.8129927 19.857,-95.3763564 29.8144557 15.435)',
|
||||||
|
( 11.339, 4.536, 9.762, 12.448, 10.457, 9.418, 14.858,
|
||||||
|
15.386, 13.168, 15.104, 16.516, 13.923, 14.385, 15.16 ,
|
||||||
|
15.544, 14.975, 15.688, 16.099, 15.197, 17.268, 19.857,
|
||||||
|
15.435),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Bounding box polygon for inner-loop of Houston (in projected coordinate
|
||||||
|
# system 32140), with elevation values from the National Elevation Dataset
|
||||||
|
# (see above).
|
||||||
|
bbox_wkt = 'POLYGON((941527.97 4225693.20,962596.48 4226349.75,963152.57 4209023.95,942051.75 4208366.38,941527.97 4225693.20))'
|
||||||
|
bbox_z = (21.71, 13.21, 9.12, 16.40, 21.71)
|
||||||
|
def gen_bbox():
|
||||||
|
bbox_2d = GEOSGeometry(bbox_wkt, srid=32140)
|
||||||
|
bbox_3d = Polygon(tuple((x, y, z) for (x, y), z in zip(bbox_2d[0].coords, bbox_z)), srid=32140)
|
||||||
|
return bbox_2d, bbox_3d
|
||||||
|
|
||||||
|
class Geo3DTest(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
Only a subset of the PostGIS routines are 3D-enabled, and this TestCase
|
||||||
|
tries to test the features that can handle 3D and that are also
|
||||||
|
available within GeoDjango. For more information, see the PostGIS docs
|
||||||
|
on the routines that support 3D:
|
||||||
|
|
||||||
|
http://postgis.refractions.net/documentation/manual-1.4/ch08.html#PostGIS_3D_Functions
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test01_3d(self):
|
||||||
|
"Test the creation of 3D models."
|
||||||
|
# 3D models for the rest of the tests will be populated in here.
|
||||||
|
# For each 3D data set create model (and 2D version if necessary),
|
||||||
|
# retrieve, and assert geometry is in 3D and contains the expected
|
||||||
|
# 3D values.
|
||||||
|
for name, pnt_data in city_data:
|
||||||
|
x, y, z = pnt_data
|
||||||
|
pnt = Point(x, y, z, srid=4326)
|
||||||
|
City3D.objects.create(name=name, point=pnt)
|
||||||
|
city = City3D.objects.get(name=name)
|
||||||
|
self.failUnless(city.point.hasz)
|
||||||
|
self.assertEqual(z, city.point.z)
|
||||||
|
|
||||||
|
# Interstate (2D / 3D and Geographic/Projected variants)
|
||||||
|
for name, line, exp_z in interstate_data:
|
||||||
|
line_3d = GEOSGeometry(line, srid=4269)
|
||||||
|
# Using `hex` attribute because it omits 3D.
|
||||||
|
line_2d = GEOSGeometry(line_3d.hex, srid=4269)
|
||||||
|
|
||||||
|
# Creating a geographic and projected version of the
|
||||||
|
# interstate in both 2D and 3D.
|
||||||
|
Interstate3D.objects.create(name=name, line=line_3d)
|
||||||
|
InterstateProj3D.objects.create(name=name, line=line_3d)
|
||||||
|
Interstate2D.objects.create(name=name, line=line_2d)
|
||||||
|
InterstateProj2D.objects.create(name=name, line=line_2d)
|
||||||
|
|
||||||
|
# Retrieving and making sure it's 3D and has expected
|
||||||
|
# Z values -- shouldn't change because of coordinate system.
|
||||||
|
interstate = Interstate3D.objects.get(name=name)
|
||||||
|
interstate_proj = InterstateProj3D.objects.get(name=name)
|
||||||
|
for i in [interstate, interstate_proj]:
|
||||||
|
self.failUnless(i.line.hasz)
|
||||||
|
self.assertEqual(exp_z, tuple(i.line.z))
|
||||||
|
|
||||||
|
# Creating 3D Polygon.
|
||||||
|
bbox2d, bbox3d = gen_bbox()
|
||||||
|
Polygon2D.objects.create(name='2D BBox', poly=bbox2d)
|
||||||
|
Polygon3D.objects.create(name='3D BBox', poly=bbox3d)
|
||||||
|
p3d = Polygon3D.objects.get(name='3D BBox')
|
||||||
|
self.failUnless(p3d.poly.hasz)
|
||||||
|
self.assertEqual(bbox3d, p3d.poly)
|
||||||
|
|
||||||
|
def test01a_3d_layermapping(self):
|
||||||
|
"Testing LayerMapping on 3D models."
|
||||||
|
from models import Point2D, Point3D
|
||||||
|
|
||||||
|
point_mapping = {'point' : 'POINT'}
|
||||||
|
mpoint_mapping = {'mpoint' : 'MULTIPOINT'}
|
||||||
|
|
||||||
|
# The VRT is 3D, but should still be able to map sans the Z.
|
||||||
|
lm = LayerMapping(Point2D, vrt_file, point_mapping, transform=False)
|
||||||
|
lm.save()
|
||||||
|
self.assertEqual(3, Point2D.objects.count())
|
||||||
|
|
||||||
|
# The city shapefile is 2D, and won't be able to fill the coordinates
|
||||||
|
# in the 3D model -- thus, a LayerMapError is raised.
|
||||||
|
self.assertRaises(LayerMapError, LayerMapping,
|
||||||
|
Point3D, city_file, point_mapping, transform=False)
|
||||||
|
|
||||||
|
# 3D model should take 3D data just fine.
|
||||||
|
lm = LayerMapping(Point3D, vrt_file, point_mapping, transform=False)
|
||||||
|
lm.save()
|
||||||
|
self.assertEqual(3, Point3D.objects.count())
|
||||||
|
|
||||||
|
# Making sure LayerMapping.make_multi works right, by converting
|
||||||
|
# a Point25D into a MultiPoint25D.
|
||||||
|
lm = LayerMapping(MultiPoint3D, vrt_file, mpoint_mapping, transform=False)
|
||||||
|
lm.save()
|
||||||
|
self.assertEqual(3, MultiPoint3D.objects.count())
|
||||||
|
|
||||||
|
def test02a_kml(self):
|
||||||
|
"Test GeoQuerySet.kml() with Z values."
|
||||||
|
h = City3D.objects.kml(precision=6).get(name='Houston')
|
||||||
|
# KML should be 3D.
|
||||||
|
# `SELECT ST_AsKML(point, 6) FROM geo3d_city3d WHERE name = 'Houston';`
|
||||||
|
ref_kml_regex = re.compile(r'^<Point><coordinates>-95.363\d+,29.763\d+,18</coordinates></Point>$')
|
||||||
|
self.failUnless(ref_kml_regex.match(h.kml))
|
||||||
|
|
||||||
|
def test02b_geojson(self):
|
||||||
|
"Test GeoQuerySet.geojson() with Z values."
|
||||||
|
h = City3D.objects.geojson(precision=6).get(name='Houston')
|
||||||
|
# GeoJSON should be 3D
|
||||||
|
# `SELECT ST_AsGeoJSON(point, 6) FROM geo3d_city3d WHERE name='Houston';`
|
||||||
|
ref_json_regex = re.compile(r'^{"type":"Point","coordinates":\[-95.363151,29.763374,18(\.0+)?\]}$')
|
||||||
|
self.failUnless(ref_json_regex.match(h.geojson))
|
||||||
|
|
||||||
|
def test03a_union(self):
|
||||||
|
"Testing the Union aggregate of 3D models."
|
||||||
|
# PostGIS query that returned the reference EWKT for this test:
|
||||||
|
# `SELECT ST_AsText(ST_Union(point)) FROM geo3d_city3d;`
|
||||||
|
ref_ewkt = 'SRID=4326;MULTIPOINT(-123.305196 48.462611 15,-104.609252 38.255001 1433,-97.521157 34.464642 380,-96.801611 32.782057 147,-95.363151 29.763374 18,-95.23506 38.971823 251,-87.650175 41.850385 181,174.783117 -41.315268 14)'
|
||||||
|
ref_union = GEOSGeometry(ref_ewkt)
|
||||||
|
union = City3D.objects.aggregate(Union('point'))['point__union']
|
||||||
|
self.failUnless(union.hasz)
|
||||||
|
self.assertEqual(ref_union, union)
|
||||||
|
|
||||||
|
def test03b_extent(self):
|
||||||
|
"Testing the Extent3D aggregate for 3D models."
|
||||||
|
# `SELECT ST_Extent3D(point) FROM geo3d_city3d;`
|
||||||
|
ref_extent3d = (-123.305196, -41.315268, 14,174.783117, 48.462611, 1433)
|
||||||
|
extent1 = City3D.objects.aggregate(Extent3D('point'))['point__extent3d']
|
||||||
|
extent2 = City3D.objects.extent3d()
|
||||||
|
|
||||||
|
def check_extent3d(extent3d, tol=6):
|
||||||
|
for ref_val, ext_val in zip(ref_extent3d, extent3d):
|
||||||
|
self.assertAlmostEqual(ref_val, ext_val, tol)
|
||||||
|
|
||||||
|
for e3d in [extent1, extent2]:
|
||||||
|
check_extent3d(e3d)
|
||||||
|
|
||||||
|
def test04_perimeter(self):
|
||||||
|
"Testing GeoQuerySet.perimeter() on 3D fields."
|
||||||
|
# Reference query for values below:
|
||||||
|
# `SELECT ST_Perimeter3D(poly), ST_Perimeter2D(poly) FROM geo3d_polygon3d;`
|
||||||
|
ref_perim_3d = 76859.2620451
|
||||||
|
ref_perim_2d = 76859.2577803
|
||||||
|
tol = 6
|
||||||
|
self.assertAlmostEqual(ref_perim_2d,
|
||||||
|
Polygon2D.objects.perimeter().get(name='2D BBox').perimeter.m,
|
||||||
|
tol)
|
||||||
|
self.assertAlmostEqual(ref_perim_3d,
|
||||||
|
Polygon3D.objects.perimeter().get(name='3D BBox').perimeter.m,
|
||||||
|
tol)
|
||||||
|
|
||||||
|
def test05_length(self):
|
||||||
|
"Testing GeoQuerySet.length() on 3D fields."
|
||||||
|
# ST_Length_Spheroid Z-aware, and thus does not need to use
|
||||||
|
# a separate function internally.
|
||||||
|
# `SELECT ST_Length_Spheroid(line, 'SPHEROID["GRS 1980",6378137,298.257222101]')
|
||||||
|
# FROM geo3d_interstate[2d|3d];`
|
||||||
|
tol = 3
|
||||||
|
ref_length_2d = 4368.1721949481
|
||||||
|
ref_length_3d = 4368.62547052088
|
||||||
|
self.assertAlmostEqual(ref_length_2d,
|
||||||
|
Interstate2D.objects.length().get(name='I-45').length.m,
|
||||||
|
tol)
|
||||||
|
self.assertAlmostEqual(ref_length_3d,
|
||||||
|
Interstate3D.objects.length().get(name='I-45').length.m,
|
||||||
|
tol)
|
||||||
|
|
||||||
|
# Making sure `ST_Length3D` is used on for a projected
|
||||||
|
# and 3D model rather than `ST_Length`.
|
||||||
|
# `SELECT ST_Length(line) FROM geo3d_interstateproj2d;`
|
||||||
|
ref_length_2d = 4367.71564892392
|
||||||
|
# `SELECT ST_Length3D(line) FROM geo3d_interstateproj3d;`
|
||||||
|
ref_length_3d = 4368.16897234101
|
||||||
|
self.assertAlmostEqual(ref_length_2d,
|
||||||
|
InterstateProj2D.objects.length().get(name='I-45').length.m,
|
||||||
|
tol)
|
||||||
|
self.assertAlmostEqual(ref_length_3d,
|
||||||
|
InterstateProj3D.objects.length().get(name='I-45').length.m,
|
||||||
|
tol)
|
||||||
|
|
||||||
|
def test06_scale(self):
|
||||||
|
"Testing GeoQuerySet.scale() on Z values."
|
||||||
|
# Mapping of City name to reference Z values.
|
||||||
|
zscales = (-3, 4, 23)
|
||||||
|
for zscale in zscales:
|
||||||
|
for city in City3D.objects.scale(1.0, 1.0, zscale):
|
||||||
|
self.assertEqual(city_dict[city.name][2] * zscale, city.scale.z)
|
||||||
|
|
||||||
|
def test07_translate(self):
|
||||||
|
"Testing GeoQuerySet.translate() on Z values."
|
||||||
|
ztranslations = (5.23, 23, -17)
|
||||||
|
for ztrans in ztranslations:
|
||||||
|
for city in City3D.objects.translate(0, 0, ztrans):
|
||||||
|
self.assertEqual(city_dict[city.name][2] + ztrans, city.translate.z)
|
||||||
|
|
||||||
|
def suite():
|
||||||
|
s = unittest.TestSuite()
|
||||||
|
s.addTest(unittest.makeSuite(Geo3DTest))
|
||||||
|
return s
|
1
django/contrib/gis/tests/geo3d/views.py
Normal file
1
django/contrib/gis/tests/geo3d/views.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Create your views here.
|
@ -33,4 +33,6 @@ class GeoRegressionTests(unittest.TestCase):
|
|||||||
"Testing `extent` on a table with a single point, see #11827."
|
"Testing `extent` on a table with a single point, see #11827."
|
||||||
pnt = City.objects.get(name='Pueblo').point
|
pnt = City.objects.get(name='Pueblo').point
|
||||||
ref_ext = (pnt.x, pnt.y, pnt.x, pnt.y)
|
ref_ext = (pnt.x, pnt.y, pnt.x, pnt.y)
|
||||||
self.assertEqual(ref_ext, City.objects.filter(name='Pueblo').extent())
|
extent = City.objects.filter(name='Pueblo').extent()
|
||||||
|
for ref_val, val in zip(ref_ext, extent):
|
||||||
|
self.assertAlmostEqual(ref_val, val, 4)
|
||||||
|
@ -171,3 +171,10 @@ json_geoms = (TestGeom('POINT(100 0)', json='{ "type": "Point", "coordinates": [
|
|||||||
not_equal=True,
|
not_equal=True,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# For testing HEX(EWKB).
|
||||||
|
ogc_hex = '01010000000000000000000000000000000000F03F'
|
||||||
|
# `SELECT ST_AsHEXEWKB(ST_GeomFromText('POINT(0 1)', 4326));`
|
||||||
|
hexewkb_2d = '0101000020E61000000000000000000000000000000000F03F'
|
||||||
|
# `SELECT ST_AsHEXEWKB(ST_GeomFromEWKT('SRID=4326;POINT(0 1 2)'));`
|
||||||
|
hexewkb_3d = '01010000A0E61000000000000000000000000000000000F03F0000000000000040'
|
||||||
|
@ -10,7 +10,7 @@ if HAS_GDAL:
|
|||||||
try:
|
try:
|
||||||
# LayerMapping requires DJANGO_SETTINGS_MODULE to be set,
|
# LayerMapping requires DJANGO_SETTINGS_MODULE to be set,
|
||||||
# so this needs to be in try/except.
|
# so this needs to be in try/except.
|
||||||
from django.contrib.gis.utils.layermapping import LayerMapping
|
from django.contrib.gis.utils.layermapping import LayerMapping, LayerMapError
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -133,6 +133,9 @@ class LayerMapping(object):
|
|||||||
MULTI_TYPES = {1 : OGRGeomType('MultiPoint'),
|
MULTI_TYPES = {1 : OGRGeomType('MultiPoint'),
|
||||||
2 : OGRGeomType('MultiLineString'),
|
2 : OGRGeomType('MultiLineString'),
|
||||||
3 : OGRGeomType('MultiPolygon'),
|
3 : OGRGeomType('MultiPolygon'),
|
||||||
|
OGRGeomType('Point25D').num : OGRGeomType('MultiPoint25D'),
|
||||||
|
OGRGeomType('LineString25D').num : OGRGeomType('MultiLineString25D'),
|
||||||
|
OGRGeomType('Polygon25D').num : OGRGeomType('MultiPolygon25D'),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Acceptable Django field types and corresponding acceptable OGR
|
# Acceptable Django field types and corresponding acceptable OGR
|
||||||
@ -282,19 +285,28 @@ class LayerMapping(object):
|
|||||||
if self.geom_field:
|
if self.geom_field:
|
||||||
raise LayerMapError('LayerMapping does not support more than one GeometryField per model.')
|
raise LayerMapError('LayerMapping does not support more than one GeometryField per model.')
|
||||||
|
|
||||||
|
# Getting the coordinate dimension of the geometry field.
|
||||||
|
coord_dim = model_field.dim
|
||||||
|
|
||||||
try:
|
try:
|
||||||
gtype = OGRGeomType(ogr_name)
|
if coord_dim == 3:
|
||||||
|
gtype = OGRGeomType(ogr_name + '25D')
|
||||||
|
else:
|
||||||
|
gtype = OGRGeomType(ogr_name)
|
||||||
except OGRException:
|
except OGRException:
|
||||||
raise LayerMapError('Invalid mapping for GeometryField "%s".' % field_name)
|
raise LayerMapError('Invalid mapping for GeometryField "%s".' % field_name)
|
||||||
|
|
||||||
# Making sure that the OGR Layer's Geometry is compatible.
|
# Making sure that the OGR Layer's Geometry is compatible.
|
||||||
ltype = self.layer.geom_type
|
ltype = self.layer.geom_type
|
||||||
if not (gtype == ltype or self.make_multi(ltype, model_field)):
|
if not (ltype.name.startswith(gtype.name) or self.make_multi(ltype, model_field)):
|
||||||
raise LayerMapError('Invalid mapping geometry; model has %s, feature has %s.' % (fld_name, gtype))
|
raise LayerMapError('Invalid mapping geometry; model has %s%s, layer is %s.' %
|
||||||
|
(fld_name, (coord_dim == 3 and '(dim=3)') or '', ltype))
|
||||||
|
|
||||||
# Setting the `geom_field` attribute w/the name of the model field
|
# Setting the `geom_field` attribute w/the name of the model field
|
||||||
# that is a Geometry.
|
# that is a Geometry. Also setting the coordinate dimension
|
||||||
|
# attribute.
|
||||||
self.geom_field = field_name
|
self.geom_field = field_name
|
||||||
|
self.coord_dim = coord_dim
|
||||||
fields_val = model_field
|
fields_val = model_field
|
||||||
elif isinstance(model_field, models.ForeignKey):
|
elif isinstance(model_field, models.ForeignKey):
|
||||||
if isinstance(ogr_name, dict):
|
if isinstance(ogr_name, dict):
|
||||||
@ -482,6 +494,10 @@ class LayerMapping(object):
|
|||||||
if necessary (for example if the model field is MultiPolygonField while
|
if necessary (for example if the model field is MultiPolygonField while
|
||||||
the mapped shapefile only contains Polygons).
|
the mapped shapefile only contains Polygons).
|
||||||
"""
|
"""
|
||||||
|
# Downgrade a 3D geom to a 2D one, if necessary.
|
||||||
|
if self.coord_dim != geom.coord_dim:
|
||||||
|
geom.coord_dim = self.coord_dim
|
||||||
|
|
||||||
if self.make_multi(geom.geom_type, model_field):
|
if self.make_multi(geom.geom_type, model_field):
|
||||||
# Constructing a multi-geometry type to contain the single geometry
|
# Constructing a multi-geometry type to contain the single geometry
|
||||||
multi_type = self.MULTI_TYPES[geom.geom_type.num]
|
multi_type = self.MULTI_TYPES[geom.geom_type.num]
|
||||||
|
@ -68,6 +68,9 @@ class BaseHandler(object):
|
|||||||
from django.core import exceptions, urlresolvers
|
from django.core import exceptions, urlresolvers
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
|
# Reset the urlconf for this thread.
|
||||||
|
urlresolvers.set_urlconf(None)
|
||||||
|
|
||||||
# Apply request middleware
|
# Apply request middleware
|
||||||
for middleware_method in self._request_middleware:
|
for middleware_method in self._request_middleware:
|
||||||
response = middleware_method(request)
|
response = middleware_method(request)
|
||||||
@ -77,61 +80,69 @@ class BaseHandler(object):
|
|||||||
# Get urlconf from request object, if available. Otherwise use default.
|
# Get urlconf from request object, if available. Otherwise use default.
|
||||||
urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF)
|
urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF)
|
||||||
|
|
||||||
|
# Set the urlconf for this thread to the one specified above.
|
||||||
|
urlresolvers.set_urlconf(urlconf)
|
||||||
|
|
||||||
resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
|
resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
|
||||||
try:
|
try:
|
||||||
callback, callback_args, callback_kwargs = resolver.resolve(
|
|
||||||
request.path_info)
|
|
||||||
|
|
||||||
# Apply view middleware
|
|
||||||
for middleware_method in self._view_middleware:
|
|
||||||
response = middleware_method(request, callback, callback_args, callback_kwargs)
|
|
||||||
if response:
|
|
||||||
return response
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = callback(request, *callback_args, **callback_kwargs)
|
callback, callback_args, callback_kwargs = resolver.resolve(
|
||||||
except Exception, e:
|
request.path_info)
|
||||||
# If the view raised an exception, run it through exception
|
|
||||||
# middleware, and if the exception middleware returns a
|
# Apply view middleware
|
||||||
# response, use that. Otherwise, reraise the exception.
|
for middleware_method in self._view_middleware:
|
||||||
for middleware_method in self._exception_middleware:
|
response = middleware_method(request, callback, callback_args, callback_kwargs)
|
||||||
response = middleware_method(request, e)
|
|
||||||
if response:
|
if response:
|
||||||
return response
|
return response
|
||||||
raise
|
|
||||||
|
|
||||||
# Complain if the view returned None (a common error).
|
|
||||||
if response is None:
|
|
||||||
try:
|
try:
|
||||||
view_name = callback.func_name # If it's a function
|
response = callback(request, *callback_args, **callback_kwargs)
|
||||||
except AttributeError:
|
except Exception, e:
|
||||||
view_name = callback.__class__.__name__ + '.__call__' # If it's a class
|
# If the view raised an exception, run it through exception
|
||||||
raise ValueError, "The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name)
|
# middleware, and if the exception middleware returns a
|
||||||
|
# response, use that. Otherwise, reraise the exception.
|
||||||
|
for middleware_method in self._exception_middleware:
|
||||||
|
response = middleware_method(request, e)
|
||||||
|
if response:
|
||||||
|
return response
|
||||||
|
raise
|
||||||
|
|
||||||
return response
|
# Complain if the view returned None (a common error).
|
||||||
except http.Http404, e:
|
if response is None:
|
||||||
if settings.DEBUG:
|
|
||||||
from django.views import debug
|
|
||||||
return debug.technical_404_response(request, e)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
callback, param_dict = resolver.resolve404()
|
|
||||||
return callback(request, **param_dict)
|
|
||||||
except:
|
|
||||||
try:
|
try:
|
||||||
return self.handle_uncaught_exception(request, resolver, sys.exc_info())
|
view_name = callback.func_name # If it's a function
|
||||||
finally:
|
except AttributeError:
|
||||||
receivers = signals.got_request_exception.send(sender=self.__class__, request=request)
|
view_name = callback.__class__.__name__ + '.__call__' # If it's a class
|
||||||
except exceptions.PermissionDenied:
|
raise ValueError, "The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name)
|
||||||
return http.HttpResponseForbidden('<h1>Permission denied</h1>')
|
|
||||||
except SystemExit:
|
return response
|
||||||
# Allow sys.exit() to actually exit. See tickets #1023 and #4701
|
except http.Http404, e:
|
||||||
raise
|
if settings.DEBUG:
|
||||||
except: # Handle everything else, including SuspiciousOperation, etc.
|
from django.views import debug
|
||||||
# Get the exception info now, in case another exception is thrown later.
|
return debug.technical_404_response(request, e)
|
||||||
exc_info = sys.exc_info()
|
else:
|
||||||
receivers = signals.got_request_exception.send(sender=self.__class__, request=request)
|
try:
|
||||||
return self.handle_uncaught_exception(request, resolver, exc_info)
|
callback, param_dict = resolver.resolve404()
|
||||||
|
return callback(request, **param_dict)
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
return self.handle_uncaught_exception(request, resolver, sys.exc_info())
|
||||||
|
finally:
|
||||||
|
receivers = signals.got_request_exception.send(sender=self.__class__, request=request)
|
||||||
|
except exceptions.PermissionDenied:
|
||||||
|
return http.HttpResponseForbidden('<h1>Permission denied</h1>')
|
||||||
|
except SystemExit:
|
||||||
|
# Allow sys.exit() to actually exit. See tickets #1023 and #4701
|
||||||
|
raise
|
||||||
|
except: # Handle everything else, including SuspiciousOperation, etc.
|
||||||
|
# Get the exception info now, in case another exception is thrown later.
|
||||||
|
exc_info = sys.exc_info()
|
||||||
|
receivers = signals.got_request_exception.send(sender=self.__class__, request=request)
|
||||||
|
return self.handle_uncaught_exception(request, resolver, exc_info)
|
||||||
|
finally:
|
||||||
|
# Reset URLconf for this thread on the way out for complete
|
||||||
|
# isolation of request.urlconf
|
||||||
|
urlresolvers.set_urlconf(None)
|
||||||
|
|
||||||
def handle_uncaught_exception(self, request, resolver, exc_info):
|
def handle_uncaught_exception(self, request, resolver, exc_info):
|
||||||
"""
|
"""
|
||||||
|
@ -105,6 +105,6 @@ class SMTPConnection(_SMTPConnection):
|
|||||||
import warnings
|
import warnings
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
'mail.SMTPConnection is deprecated; use mail.get_connection() instead.',
|
'mail.SMTPConnection is deprecated; use mail.get_connection() instead.',
|
||||||
DeprecationWarning
|
PendingDeprecationWarning
|
||||||
)
|
)
|
||||||
super(SMTPConnection, self).__init__(*args, **kwds)
|
super(SMTPConnection, self).__init__(*args, **kwds)
|
||||||
|
@ -299,7 +299,7 @@ class ManagementUtility(object):
|
|||||||
|
|
||||||
# subcommand
|
# subcommand
|
||||||
if cword == 1:
|
if cword == 1:
|
||||||
print ' '.join(filter(lambda x: x.startswith(curr), subcommands))
|
print ' '.join(sorted(filter(lambda x: x.startswith(curr), subcommands)))
|
||||||
# subcommand options
|
# subcommand options
|
||||||
# special case: the 'help' subcommand has no options
|
# special case: the 'help' subcommand has no options
|
||||||
elif cwords[0] in subcommands and cwords[0] != 'help':
|
elif cwords[0] in subcommands and cwords[0] != 'help':
|
||||||
@ -328,7 +328,7 @@ class ManagementUtility(object):
|
|||||||
options = filter(lambda (x, v): x not in prev_opts, options)
|
options = filter(lambda (x, v): x not in prev_opts, options)
|
||||||
|
|
||||||
# filter options by current input
|
# filter options by current input
|
||||||
options = [(k, v) for k, v in options if k.startswith(curr)]
|
options = sorted([(k, v) for k, v in options if k.startswith(curr)])
|
||||||
for option in options:
|
for option in options:
|
||||||
opt_label = option[0]
|
opt_label = option[0]
|
||||||
# append '=' to options which require args
|
# append '=' to options which require args
|
||||||
|
@ -65,7 +65,7 @@ class Command(NoArgsCommand):
|
|||||||
opts = model._meta
|
opts = model._meta
|
||||||
if (connection.introspection.table_name_converter(opts.db_table) in tables or
|
if (connection.introspection.table_name_converter(opts.db_table) in tables or
|
||||||
(opts.auto_created and
|
(opts.auto_created and
|
||||||
connection.introspection.table_name_converter(opts.auto_created._meta.db_table in tables))):
|
connection.introspection.table_name_converter(opts.auto_created._meta.db_table) in tables)):
|
||||||
continue
|
continue
|
||||||
sql, references = connection.creation.sql_create_model(model, self.style, seen_models)
|
sql, references = connection.creation.sql_create_model(model, self.style, seen_models)
|
||||||
seen_models.add(model)
|
seen_models.add(model)
|
||||||
|
@ -10,6 +10,7 @@ a string) and returns a tuple in this format:
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
|
from django.conf import settings
|
||||||
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
||||||
from django.utils.datastructures import MultiValueDict
|
from django.utils.datastructures import MultiValueDict
|
||||||
from django.utils.encoding import iri_to_uri, force_unicode, smart_str
|
from django.utils.encoding import iri_to_uri, force_unicode, smart_str
|
||||||
@ -32,6 +33,9 @@ _callable_cache = {} # Maps view and url pattern names to their view functions.
|
|||||||
# be empty.
|
# be empty.
|
||||||
_prefixes = {}
|
_prefixes = {}
|
||||||
|
|
||||||
|
# Overridden URLconfs for each thread are stored here.
|
||||||
|
_urlconfs = {}
|
||||||
|
|
||||||
class Resolver404(Http404):
|
class Resolver404(Http404):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -300,9 +304,13 @@ class RegexURLResolver(object):
|
|||||||
"arguments '%s' not found." % (lookup_view_s, args, kwargs))
|
"arguments '%s' not found." % (lookup_view_s, args, kwargs))
|
||||||
|
|
||||||
def resolve(path, urlconf=None):
|
def resolve(path, urlconf=None):
|
||||||
|
if urlconf is None:
|
||||||
|
urlconf = get_urlconf()
|
||||||
return get_resolver(urlconf).resolve(path)
|
return get_resolver(urlconf).resolve(path)
|
||||||
|
|
||||||
def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, current_app=None):
|
def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, current_app=None):
|
||||||
|
if urlconf is None:
|
||||||
|
urlconf = get_urlconf()
|
||||||
resolver = get_resolver(urlconf)
|
resolver = get_resolver(urlconf)
|
||||||
args = args or []
|
args = args or []
|
||||||
kwargs = kwargs or {}
|
kwargs = kwargs or {}
|
||||||
@ -371,3 +379,25 @@ def get_script_prefix():
|
|||||||
"""
|
"""
|
||||||
return _prefixes.get(currentThread(), u'/')
|
return _prefixes.get(currentThread(), u'/')
|
||||||
|
|
||||||
|
def set_urlconf(urlconf_name):
|
||||||
|
"""
|
||||||
|
Sets the URLconf for the current thread (overriding the default one in
|
||||||
|
settings). Set to None to revert back to the default.
|
||||||
|
"""
|
||||||
|
thread = currentThread()
|
||||||
|
if urlconf_name:
|
||||||
|
_urlconfs[thread] = urlconf_name
|
||||||
|
else:
|
||||||
|
# faster than wrapping in a try/except
|
||||||
|
if thread in _urlconfs:
|
||||||
|
del _urlconfs[thread]
|
||||||
|
|
||||||
|
def get_urlconf(default=None):
|
||||||
|
"""
|
||||||
|
Returns the root URLconf to use for the current thread if it has been
|
||||||
|
changed from the default one.
|
||||||
|
"""
|
||||||
|
thread = currentThread()
|
||||||
|
if thread in _urlconfs:
|
||||||
|
return _urlconfs[thread]
|
||||||
|
return default
|
||||||
|
@ -364,6 +364,8 @@ class Model(object):
|
|||||||
defers = []
|
defers = []
|
||||||
pk_val = None
|
pk_val = None
|
||||||
if self._deferred:
|
if self._deferred:
|
||||||
|
from django.db.models.query_utils import deferred_class_factory
|
||||||
|
factory = deferred_class_factory
|
||||||
for field in self._meta.fields:
|
for field in self._meta.fields:
|
||||||
if isinstance(self.__class__.__dict__.get(field.attname),
|
if isinstance(self.__class__.__dict__.get(field.attname),
|
||||||
DeferredAttribute):
|
DeferredAttribute):
|
||||||
@ -374,8 +376,9 @@ class Model(object):
|
|||||||
# once.
|
# once.
|
||||||
obj = self.__class__.__dict__[field.attname]
|
obj = self.__class__.__dict__[field.attname]
|
||||||
model = obj.model_ref()
|
model = obj.model_ref()
|
||||||
|
else:
|
||||||
return (model_unpickle, (model, defers), data)
|
factory = simple_class_factory
|
||||||
|
return (model_unpickle, (model, defers, factory), data)
|
||||||
|
|
||||||
def _get_pk_val(self, meta=None):
|
def _get_pk_val(self, meta=None):
|
||||||
if not meta:
|
if not meta:
|
||||||
@ -849,12 +852,20 @@ def get_absolute_url(opts, func, self, *args, **kwargs):
|
|||||||
class Empty(object):
|
class Empty(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def model_unpickle(model, attrs):
|
def simple_class_factory(model, attrs):
|
||||||
|
"""Used to unpickle Models without deferred fields.
|
||||||
|
|
||||||
|
We need to do this the hard way, rather than just using
|
||||||
|
the default __reduce__ implementation, because of a
|
||||||
|
__deepcopy__ problem in Python 2.4
|
||||||
|
"""
|
||||||
|
return model
|
||||||
|
|
||||||
|
def model_unpickle(model, attrs, factory):
|
||||||
"""
|
"""
|
||||||
Used to unpickle Model subclasses with deferred fields.
|
Used to unpickle Model subclasses with deferred fields.
|
||||||
"""
|
"""
|
||||||
from django.db.models.query_utils import deferred_class_factory
|
cls = factory(model, attrs)
|
||||||
cls = deferred_class_factory(model, attrs)
|
|
||||||
return cls.__new__(cls)
|
return cls.__new__(cls)
|
||||||
model_unpickle.__safe_for_unpickle__ = True
|
model_unpickle.__safe_for_unpickle__ = True
|
||||||
|
|
||||||
|
@ -586,9 +586,13 @@ class ReverseManyRelatedObjectsDescriptor(object):
|
|||||||
# ReverseManyRelatedObjectsDescriptor instance.
|
# ReverseManyRelatedObjectsDescriptor instance.
|
||||||
def __init__(self, m2m_field):
|
def __init__(self, m2m_field):
|
||||||
self.field = m2m_field
|
self.field = m2m_field
|
||||||
|
|
||||||
|
def _through(self):
|
||||||
# through is provided so that you have easy access to the through
|
# through is provided so that you have easy access to the through
|
||||||
# model (Book.authors.through) for inlines, etc.
|
# model (Book.authors.through) for inlines, etc. This is done as
|
||||||
self.through = m2m_field.rel.through
|
# a property to ensure that the fully resolved value is returned.
|
||||||
|
return self.field.rel.through
|
||||||
|
through = property(_through)
|
||||||
|
|
||||||
def __get__(self, instance, instance_type=None):
|
def __get__(self, instance, instance_type=None):
|
||||||
if instance is None:
|
if instance is None:
|
||||||
@ -698,6 +702,10 @@ class ForeignKey(RelatedField, Field):
|
|||||||
assert isinstance(to, basestring), "%s(%r) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string %r" % (self.__class__.__name__, to, RECURSIVE_RELATIONSHIP_CONSTANT)
|
assert isinstance(to, basestring), "%s(%r) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string %r" % (self.__class__.__name__, to, RECURSIVE_RELATIONSHIP_CONSTANT)
|
||||||
else:
|
else:
|
||||||
assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name)
|
assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name)
|
||||||
|
# For backwards compatibility purposes, we need to *try* and set
|
||||||
|
# the to_field during FK construction. It won't be guaranteed to
|
||||||
|
# be correct until contribute_to_class is called. Refs #12190.
|
||||||
|
to_field = to_field or (to._meta.pk and to._meta.pk.name)
|
||||||
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
|
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
|
||||||
|
|
||||||
kwargs['rel'] = rel_class(to, to_field,
|
kwargs['rel'] = rel_class(to, to_field,
|
||||||
@ -849,20 +857,13 @@ def create_many_to_many_intermediary_model(field, klass):
|
|||||||
'db_table': field._get_m2m_db_table(klass._meta),
|
'db_table': field._get_m2m_db_table(klass._meta),
|
||||||
'managed': managed,
|
'managed': managed,
|
||||||
'auto_created': klass,
|
'auto_created': klass,
|
||||||
|
'app_label': klass._meta.app_label,
|
||||||
'unique_together': (from_, to)
|
'unique_together': (from_, to)
|
||||||
})
|
})
|
||||||
# If the models have been split into subpackages, klass.__module__
|
|
||||||
# will be the subpackge, not the models module for the app. (See #12168)
|
|
||||||
# Compose the actual models module name by stripping the trailing parts
|
|
||||||
# of the namespace until we find .models
|
|
||||||
parts = klass.__module__.split('.')
|
|
||||||
while parts[-1] != 'models':
|
|
||||||
parts.pop()
|
|
||||||
module = '.'.join(parts)
|
|
||||||
# Construct and return the new class.
|
# Construct and return the new class.
|
||||||
return type(name, (models.Model,), {
|
return type(name, (models.Model,), {
|
||||||
'Meta': meta,
|
'Meta': meta,
|
||||||
'__module__': module,
|
'__module__': klass.__module__,
|
||||||
from_: models.ForeignKey(klass, related_name='%s+' % name),
|
from_: models.ForeignKey(klass, related_name='%s+' % name),
|
||||||
to: models.ForeignKey(to_model, related_name='%s+' % name)
|
to: models.ForeignKey(to_model, related_name='%s+' % name)
|
||||||
})
|
})
|
||||||
|
@ -409,7 +409,7 @@ class DateQuery(Query):
|
|||||||
self.select = [select]
|
self.select = [select]
|
||||||
self.select_fields = [None]
|
self.select_fields = [None]
|
||||||
self.select_related = False # See #7097.
|
self.select_related = False # See #7097.
|
||||||
self.extra = {}
|
self.set_extra_mask([])
|
||||||
self.distinct = True
|
self.distinct = True
|
||||||
self.order_by = order == 'ASC' and [1] or [-1]
|
self.order_by = order == 'ASC' and [1] or [-1]
|
||||||
|
|
||||||
|
@ -201,7 +201,5 @@ The Django open-source project
|
|||||||
|
|
||||||
* **Django over time:**
|
* **Django over time:**
|
||||||
:ref:`API stability <misc-api-stability>` |
|
:ref:`API stability <misc-api-stability>` |
|
||||||
:ref:`Archive of release notes <releases-index>` | `Backwards-incompatible changes`_ |
|
:ref:`Release notes and upgrading instructions <releases-index>` |
|
||||||
:ref:`Deprecation Timeline <internals-deprecation>`
|
:ref:`Deprecation Timeline <internals-deprecation>`
|
||||||
|
|
||||||
.. _Backwards-incompatible changes: http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges
|
|
||||||
|
@ -200,6 +200,19 @@ Karen Tracey
|
|||||||
.. _Bauhaus-University Weimar: http://www.uni-weimar.de/
|
.. _Bauhaus-University Weimar: http://www.uni-weimar.de/
|
||||||
.. _pinax: http://pinaxproject.com/
|
.. _pinax: http://pinaxproject.com/
|
||||||
|
|
||||||
|
`James Tauber`_
|
||||||
|
James is the lead developer of Pinax_ and the CEO and founder of
|
||||||
|
Eldarion_. He has been doing open source software since 1993, Python
|
||||||
|
since 1998 and Django since 2006. He serves on the board of the Python
|
||||||
|
Software Foundation and is currently on a leave of absence from a PhD in
|
||||||
|
linguistics.
|
||||||
|
|
||||||
|
James currently lives in Boston, MA, USA but originally hails from
|
||||||
|
Perth, Western Australia where he attended the same high school as
|
||||||
|
Russell Keith-Magee.
|
||||||
|
|
||||||
|
.. _James Tauber: http://jtauber.com/
|
||||||
|
|
||||||
Specialists
|
Specialists
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ To enable CSRF protection for your views, follow these steps:
|
|||||||
``django.views.decorators.csrf.csrf_protect`` on particular views you
|
``django.views.decorators.csrf.csrf_protect`` on particular views you
|
||||||
want to protect (see below).
|
want to protect (see below).
|
||||||
|
|
||||||
2. In any template that uses a POST form, use the ``csrf_token`` tag inside
|
2. In any template that uses a POST form, use the :ttag:`csrf_token` tag inside
|
||||||
the ``<form>`` element if the form is for an internal URL, e.g.::
|
the ``<form>`` element if the form is for an internal URL, e.g.::
|
||||||
|
|
||||||
<form action="" method="POST">{% csrf_token %}
|
<form action="" method="POST">{% csrf_token %}
|
||||||
@ -130,7 +130,7 @@ as ``CsrfResponseMiddleware``, and it can be used by following these steps:
|
|||||||
Use of the ``CsrfResponseMiddleware`` is not recommended because of the
|
Use of the ``CsrfResponseMiddleware`` is not recommended because of the
|
||||||
performance hit it imposes, and because of a potential security problem (see
|
performance hit it imposes, and because of a potential security problem (see
|
||||||
below). It can be used as an interim measure until applications have been
|
below). It can be used as an interim measure until applications have been
|
||||||
updated to use the ``{% csrf_token %}`` tag. It is deprecated and will be
|
updated to use the :ttag:`csrf_token` tag. It is deprecated and will be
|
||||||
removed in Django 1.4.
|
removed in Django 1.4.
|
||||||
|
|
||||||
Django 1.1 and earlier provided a single ``CsrfMiddleware`` class. This is also
|
Django 1.1 and earlier provided a single ``CsrfMiddleware`` class. This is also
|
||||||
@ -153,6 +153,8 @@ launch a CSRF attack on your site against that user. The
|
|||||||
``@csrf_response_exempt`` decorator can be used to fix this, but only if the
|
``@csrf_response_exempt`` decorator can be used to fix this, but only if the
|
||||||
page doesn't also contain internal forms that require the token.
|
page doesn't also contain internal forms that require the token.
|
||||||
|
|
||||||
|
.. _ref-csrf-upgrading-notes:
|
||||||
|
|
||||||
Upgrading notes
|
Upgrading notes
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
@ -199,7 +201,7 @@ Note that contrib apps, such as the admin, have been updated to use the
|
|||||||
``CsrfViewMiddleware`` to your settings. However, if you have supplied
|
``CsrfViewMiddleware`` to your settings. However, if you have supplied
|
||||||
customised templates to any of the view functions of contrib apps (whether
|
customised templates to any of the view functions of contrib apps (whether
|
||||||
explicitly via a keyword argument, or by overriding built-in templates), **you
|
explicitly via a keyword argument, or by overriding built-in templates), **you
|
||||||
MUST update them** to include the ``csrf_token`` template tag as described
|
MUST update them** to include the :ttag:`csrf_token` template tag as described
|
||||||
above, or they will stop working. (If you cannot update these templates for
|
above, or they will stop working. (If you cannot update these templates for
|
||||||
some reason, you will be forced to use ``CsrfResponseMiddleware`` for these
|
some reason, you will be forced to use ``CsrfResponseMiddleware`` for these
|
||||||
views to continue working).
|
views to continue working).
|
||||||
@ -364,7 +366,7 @@ exactly that.
|
|||||||
Caching
|
Caching
|
||||||
=======
|
=======
|
||||||
|
|
||||||
If the ``csrf_token`` template tag is used by a template (or the ``get_token``
|
If the :ttag:`csrf_token` template tag is used by a template (or the ``get_token``
|
||||||
function is called some other way), ``CsrfViewMiddleware`` will add a cookie and
|
function is called some other way), ``CsrfViewMiddleware`` will add a cookie and
|
||||||
a ``Vary: Cookie`` header to the response. Similarly,
|
a ``Vary: Cookie`` header to the response. Similarly,
|
||||||
``CsrfResponseMiddleware`` will send the ``Vary: Cookie`` header if it inserted
|
``CsrfResponseMiddleware`` will send the ``Vary: Cookie`` header if it inserted
|
||||||
|
@ -78,11 +78,9 @@ Examples of output::
|
|||||||
Displaying debug output
|
Displaying debug output
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
.. django-admin-option:: --verbosity <amount>
|
Use :djadminopt:`--verbosity` to specify the amount of notification and debug information
|
||||||
|
|
||||||
Use ``--verbosity`` to specify the amount of notification and debug information
|
|
||||||
that ``django-admin.py`` should print to the console. For more details, see the
|
that ``django-admin.py`` should print to the console. For more details, see the
|
||||||
documentation for the :ref:`default options for django-admin.py <django-admin-verbosity>`.
|
documentation for the :djadminopt:`--verbosity` option.
|
||||||
|
|
||||||
Available subcommands
|
Available subcommands
|
||||||
=====================
|
=====================
|
||||||
@ -90,6 +88,8 @@ Available subcommands
|
|||||||
cleanup
|
cleanup
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
.. django-admin:: cleanup
|
||||||
|
|
||||||
.. versionadded:: 1.0
|
.. versionadded:: 1.0
|
||||||
|
|
||||||
Can be run as a cronjob or directly to clean out old data from the database
|
Can be run as a cronjob or directly to clean out old data from the database
|
||||||
@ -98,17 +98,16 @@ Can be run as a cronjob or directly to clean out old data from the database
|
|||||||
compilemessages
|
compilemessages
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
.. django-admin:: compilemessages
|
||||||
|
|
||||||
.. versionchanged:: 1.0
|
.. versionchanged:: 1.0
|
||||||
Before 1.0 this was the "bin/compile-messages.py" command.
|
Before 1.0 this was the "bin/compile-messages.py" command.
|
||||||
|
|
||||||
Compiles .po files created with ``makemessages`` to .mo files for use with
|
Compiles .po files created with ``makemessages`` to .mo files for use with
|
||||||
the builtin gettext support. See :ref:`topics-i18n`.
|
the builtin gettext support. See :ref:`topics-i18n`.
|
||||||
|
|
||||||
--locale
|
Use the :djadminopt:`--locale`` option to specify the locale to process.
|
||||||
~~~~~~~~
|
If not provided, all locales are processed.
|
||||||
|
|
||||||
Use the ``--locale`` or ``-l`` option to specify the locale to process.
|
|
||||||
If not provided all locales are processed.
|
|
||||||
|
|
||||||
Example usage::
|
Example usage::
|
||||||
|
|
||||||
@ -117,7 +116,7 @@ Example usage::
|
|||||||
createcachetable
|
createcachetable
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
.. django-admin:: createcachetable <tablename>
|
.. django-admin:: createcachetable
|
||||||
|
|
||||||
Creates a cache table named ``tablename`` for use with the database cache
|
Creates a cache table named ``tablename`` for use with the database cache
|
||||||
backend. See :ref:`topics-cache` for more information.
|
backend. See :ref:`topics-cache` for more information.
|
||||||
@ -183,10 +182,10 @@ example, the default settings don't define ``ROOT_URLCONF``, so
|
|||||||
Note that Django's default settings live in ``django/conf/global_settings.py``,
|
Note that Django's default settings live in ``django/conf/global_settings.py``,
|
||||||
if you're ever curious to see the full list of defaults.
|
if you're ever curious to see the full list of defaults.
|
||||||
|
|
||||||
dumpdata
|
dumpdata <appname appname appname.Model ...>
|
||||||
--------
|
--------------------------------------------
|
||||||
|
|
||||||
.. django-admin:: dumpdata <appname appname appname.Model ...>
|
.. django-admin:: dumpdata
|
||||||
|
|
||||||
Outputs to standard output all data in the database associated with the named
|
Outputs to standard output all data in the database associated with the named
|
||||||
application(s).
|
application(s).
|
||||||
@ -215,18 +214,17 @@ directives::
|
|||||||
|
|
||||||
django-admin.py dumpdata --exclude=auth --exclude=contenttypes
|
django-admin.py dumpdata --exclude=auth --exclude=contenttypes
|
||||||
|
|
||||||
|
|
||||||
.. django-admin-option:: --format <fmt>
|
.. django-admin-option:: --format <fmt>
|
||||||
|
|
||||||
By default, ``dumpdata`` will format its output in JSON, but you can use the
|
By default, ``dumpdata`` will format its output in JSON, but you can use the
|
||||||
``--format`` option to specify another format. Currently supported formats
|
``--format`` option to specify another format. Currently supported formats
|
||||||
are listed in :ref:`serialization-formats`.
|
are listed in :ref:`serialization-formats`.
|
||||||
|
|
||||||
.. django-admin-option:: --indent <num>
|
.. django-admin-option:: --indent <num>
|
||||||
|
|
||||||
By default, ``dumpdata`` will output all data on a single line. This isn't
|
By default, ``dumpdata`` will output all data on a single line. This isn't
|
||||||
easy for humans to read, so you can use the ``--indent`` option to
|
easy for humans to read, so you can use the ``--indent`` option to
|
||||||
pretty-print the output with a number of indentation spaces.
|
pretty-print the output with a number of indentation spaces.
|
||||||
|
|
||||||
.. versionadded:: 1.1
|
.. versionadded:: 1.1
|
||||||
|
|
||||||
@ -239,22 +237,21 @@ model names.
|
|||||||
flush
|
flush
|
||||||
-----
|
-----
|
||||||
|
|
||||||
.. django-admin: flush
|
.. django-admin:: flush
|
||||||
|
|
||||||
Returns the database to the state it was in immediately after syncdb was
|
Returns the database to the state it was in immediately after syncdb was
|
||||||
executed. This means that all data will be removed from the database, any
|
executed. This means that all data will be removed from the database, any
|
||||||
post-synchronization handlers will be re-executed, and the ``initial_data``
|
post-synchronization handlers will be re-executed, and the ``initial_data``
|
||||||
fixture will be re-installed.
|
fixture will be re-installed.
|
||||||
|
|
||||||
.. django-admin-option:: --noinput
|
The :djadminopt:`--noinput` option may be provided to suppress all user
|
||||||
|
prompts.
|
||||||
Use the ``--noinput`` option to suppress all user prompting, such as "Are
|
|
||||||
you sure?" confirmation messages. This is useful if ``django-admin.py`` is
|
|
||||||
being executed as an unattended, automated script.
|
|
||||||
|
|
||||||
inspectdb
|
inspectdb
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
.. django-admin:: inspectdb
|
||||||
|
|
||||||
Introspects the database tables in the database pointed-to by the
|
Introspects the database tables in the database pointed-to by the
|
||||||
``DATABASE_NAME`` setting and outputs a Django model module (a ``models.py``
|
``DATABASE_NAME`` setting and outputs a Django model module (a ``models.py``
|
||||||
file) to standard output.
|
file) to standard output.
|
||||||
@ -296,6 +293,8 @@ only works in PostgreSQL and with certain types of MySQL tables.
|
|||||||
loaddata <fixture fixture ...>
|
loaddata <fixture fixture ...>
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
|
.. django-admin:: loaddata
|
||||||
|
|
||||||
Searches for and loads the contents of the named fixture into the database.
|
Searches for and loads the contents of the named fixture into the database.
|
||||||
|
|
||||||
What's a "fixture"?
|
What's a "fixture"?
|
||||||
@ -382,6 +381,8 @@ installation will be aborted, and any data installed in the call to
|
|||||||
makemessages
|
makemessages
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
.. django-admin:: makemessages
|
||||||
|
|
||||||
.. versionchanged:: 1.0
|
.. versionchanged:: 1.0
|
||||||
Before 1.0 this was the ``bin/make-messages.py`` command.
|
Before 1.0 this was the ``bin/make-messages.py`` command.
|
||||||
|
|
||||||
@ -392,8 +393,7 @@ directory. After making changes to the messages files you need to compile them
|
|||||||
with ``compilemessages`` for use with the builtin gettext support. See the
|
with ``compilemessages`` for use with the builtin gettext support. See the
|
||||||
:ref:`i18n documentation <how-to-create-language-files>` for details.
|
:ref:`i18n documentation <how-to-create-language-files>` for details.
|
||||||
|
|
||||||
--all
|
.. django-admin-option:: --all
|
||||||
~~~~~
|
|
||||||
|
|
||||||
Use the ``--all`` or ``-a`` option to update the message files for all
|
Use the ``--all`` or ``-a`` option to update the message files for all
|
||||||
available languages.
|
available languages.
|
||||||
@ -402,8 +402,7 @@ Example usage::
|
|||||||
|
|
||||||
django-admin.py makemessages --all
|
django-admin.py makemessages --all
|
||||||
|
|
||||||
--extension
|
.. django-admin-option:: --extension
|
||||||
~~~~~~~~~~~
|
|
||||||
|
|
||||||
Use the ``--extension`` or ``-e`` option to specify a list of file extensions
|
Use the ``--extension`` or ``-e`` option to specify a list of file extensions
|
||||||
to examine (default: ".html").
|
to examine (default: ".html").
|
||||||
@ -416,17 +415,13 @@ Separate multiple extensions with commas or use -e or --extension multiple times
|
|||||||
|
|
||||||
django-admin.py makemessages --locale=de --extension=html,txt --extension xml
|
django-admin.py makemessages --locale=de --extension=html,txt --extension xml
|
||||||
|
|
||||||
--locale
|
Use the :djadminopt:`--locale` option to specify the locale to process.
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
Use the ``--locale`` or ``-l`` option to specify the locale to process.
|
|
||||||
|
|
||||||
Example usage::
|
Example usage::
|
||||||
|
|
||||||
django-admin.py makemessages --locale=br_PT
|
django-admin.py makemessages --locale=br_PT
|
||||||
|
|
||||||
--domain
|
.. django-admin-option:: --domain
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
Use the ``--domain`` or ``-d`` option to change the domain of the messages files.
|
Use the ``--domain`` or ``-d`` option to change the domain of the messages files.
|
||||||
Currently supported:
|
Currently supported:
|
||||||
@ -434,23 +429,21 @@ Currently supported:
|
|||||||
* ``django`` for all ``*.py`` and ``*.html`` files (default)
|
* ``django`` for all ``*.py`` and ``*.html`` files (default)
|
||||||
* ``djangojs`` for ``*.js`` files
|
* ``djangojs`` for ``*.js`` files
|
||||||
|
|
||||||
.. _django-admin-reset:
|
|
||||||
|
|
||||||
reset <appname appname ...>
|
reset <appname appname ...>
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
|
.. django-admin:: reset
|
||||||
|
|
||||||
Executes the equivalent of ``sqlreset`` for the given app name(s).
|
Executes the equivalent of ``sqlreset`` for the given app name(s).
|
||||||
|
|
||||||
--noinput
|
The :djadminopt:`--noinput` option may be provided to suppress all user
|
||||||
~~~~~~~~~
|
prompts.
|
||||||
|
|
||||||
Use the ``--noinput`` option to suppress all user prompting, such as
|
|
||||||
"Are you sure?" confirmation messages. This is useful if ``django-admin.py``
|
|
||||||
is being executed as an unattended, automated script.
|
|
||||||
|
|
||||||
runfcgi [options]
|
runfcgi [options]
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
.. django-admin:: runfcgi
|
||||||
|
|
||||||
Starts a set of FastCGI processes suitable for use with any Web server that
|
Starts a set of FastCGI processes suitable for use with any Web server that
|
||||||
supports the FastCGI protocol. See the :ref:`FastCGI deployment documentation
|
supports the FastCGI protocol. See the :ref:`FastCGI deployment documentation
|
||||||
<howto-deployment-fastcgi>` for details. Requires the Python FastCGI module from
|
<howto-deployment-fastcgi>` for details. Requires the Python FastCGI module from
|
||||||
@ -458,10 +451,10 @@ supports the FastCGI protocol. See the :ref:`FastCGI deployment documentation
|
|||||||
|
|
||||||
.. _flup: http://www.saddi.com/software/flup/
|
.. _flup: http://www.saddi.com/software/flup/
|
||||||
|
|
||||||
runserver
|
runserver [port or ipaddr:port]
|
||||||
---------
|
-------------------------------
|
||||||
|
|
||||||
.. django-admin:: runserver [port or ipaddr:port]
|
.. django-admin:: runserver
|
||||||
|
|
||||||
Starts a lightweight development Web server on the local machine. By default,
|
Starts a lightweight development Web server on the local machine. By default,
|
||||||
the server runs on port 8000 on the IP address 127.0.0.1. You can pass in an
|
the server runs on port 8000 on the IP address 127.0.0.1. You can pass in an
|
||||||
@ -544,6 +537,8 @@ you want to configure Django to serve static media, read :ref:`howto-static-file
|
|||||||
shell
|
shell
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
.. django-admin:: shell
|
||||||
|
|
||||||
Starts the Python interactive interpreter.
|
Starts the Python interactive interpreter.
|
||||||
|
|
||||||
Django will use IPython_, if it's installed. If you have IPython installed and
|
Django will use IPython_, if it's installed. If you have IPython installed and
|
||||||
@ -557,11 +552,15 @@ option, like so::
|
|||||||
sql <appname appname ...>
|
sql <appname appname ...>
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
.. django-admin:: sql
|
||||||
|
|
||||||
Prints the CREATE TABLE SQL statements for the given app name(s).
|
Prints the CREATE TABLE SQL statements for the given app name(s).
|
||||||
|
|
||||||
sqlall <appname appname ...>
|
sqlall <appname appname ...>
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
|
.. django-admin:: sqlall
|
||||||
|
|
||||||
Prints the CREATE TABLE and initial-data SQL statements for the given app name(s).
|
Prints the CREATE TABLE and initial-data SQL statements for the given app name(s).
|
||||||
|
|
||||||
Refer to the description of ``sqlcustom`` for an explanation of how to
|
Refer to the description of ``sqlcustom`` for an explanation of how to
|
||||||
@ -570,11 +569,15 @@ specify initial data.
|
|||||||
sqlclear <appname appname ...>
|
sqlclear <appname appname ...>
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
|
.. django-admin:: sqlclear
|
||||||
|
|
||||||
Prints the DROP TABLE SQL statements for the given app name(s).
|
Prints the DROP TABLE SQL statements for the given app name(s).
|
||||||
|
|
||||||
sqlcustom <appname appname ...>
|
sqlcustom <appname appname ...>
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
|
.. django-admin:: sqlcustom
|
||||||
|
|
||||||
Prints the custom SQL statements for the given app name(s).
|
Prints the custom SQL statements for the given app name(s).
|
||||||
|
|
||||||
For each model in each specified app, this command looks for the file
|
For each model in each specified app, this command looks for the file
|
||||||
@ -594,21 +597,30 @@ Note that the order in which the SQL files are processed is undefined.
|
|||||||
sqlflush
|
sqlflush
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Prints the SQL statements that would be executed for the `flush`_ command.
|
.. django-admin:: sqlflush
|
||||||
|
|
||||||
|
Prints the SQL statements that would be executed for the :djadmin:`flush`
|
||||||
|
command.
|
||||||
|
|
||||||
sqlindexes <appname appname ...>
|
sqlindexes <appname appname ...>
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
|
.. django-admin:: sqlindexes
|
||||||
|
|
||||||
Prints the CREATE INDEX SQL statements for the given app name(s).
|
Prints the CREATE INDEX SQL statements for the given app name(s).
|
||||||
|
|
||||||
sqlreset <appname appname ...>
|
sqlreset <appname appname ...>
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
|
.. django-admin:: sqlreset
|
||||||
|
|
||||||
Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given app name(s).
|
Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given app name(s).
|
||||||
|
|
||||||
sqlsequencereset <appname appname ...>
|
sqlsequencereset <appname appname ...>
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
|
||||||
|
.. django-admin:: sqlsequencereset
|
||||||
|
|
||||||
Prints the SQL statements for resetting sequences for the given app name(s).
|
Prints the SQL statements for resetting sequences for the given app name(s).
|
||||||
|
|
||||||
Sequences are indexes used by some database engines to track the next available
|
Sequences are indexes used by some database engines to track the next available
|
||||||
@ -620,12 +632,16 @@ of sync with its automatically incremented field data.
|
|||||||
startapp <appname>
|
startapp <appname>
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
.. django-admin:: startapp
|
||||||
|
|
||||||
Creates a Django app directory structure for the given app name in the current
|
Creates a Django app directory structure for the given app name in the current
|
||||||
directory.
|
directory.
|
||||||
|
|
||||||
startproject <projectname>
|
startproject <projectname>
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
.. django-admin:: startproject
|
||||||
|
|
||||||
Creates a Django project directory structure for the given project name in the
|
Creates a Django project directory structure for the given project name in the
|
||||||
current directory.
|
current directory.
|
||||||
|
|
||||||
@ -635,11 +651,11 @@ This command is disabled when the ``--settings`` option to
|
|||||||
situations, either omit the ``--settings`` option or unset
|
situations, either omit the ``--settings`` option or unset
|
||||||
``DJANGO_SETTINGS_MODULE``.
|
``DJANGO_SETTINGS_MODULE``.
|
||||||
|
|
||||||
.. _django-admin-syncdb:
|
|
||||||
|
|
||||||
syncdb
|
syncdb
|
||||||
------
|
------
|
||||||
|
|
||||||
|
.. django-admin:: syncdb
|
||||||
|
|
||||||
Creates the database tables for all apps in ``INSTALLED_APPS`` whose tables
|
Creates the database tables for all apps in ``INSTALLED_APPS`` whose tables
|
||||||
have not already been created.
|
have not already been created.
|
||||||
|
|
||||||
@ -669,29 +685,22 @@ with an appropriate extension (e.g. ``json`` or ``xml``). See the
|
|||||||
documentation for ``loaddata`` for details on the specification of fixture
|
documentation for ``loaddata`` for details on the specification of fixture
|
||||||
data files.
|
data files.
|
||||||
|
|
||||||
--noinput
|
The :djadminopt:`--noinput` option may be provided to suppress all user
|
||||||
~~~~~~~~~
|
prompts.
|
||||||
|
|
||||||
Use the ``--noinput`` option to suppress all user prompting, such as
|
test <app or test identifier>
|
||||||
"Are you sure?" confirmation messages. This is useful if ``django-admin.py``
|
-----------------------------
|
||||||
is being executed as an unattended, automated script.
|
|
||||||
|
|
||||||
test
|
.. django-admin:: test
|
||||||
----
|
|
||||||
|
|
||||||
Runs tests for all installed models. See :ref:`topics-testing` for more
|
Runs tests for all installed models. See :ref:`topics-testing` for more
|
||||||
information.
|
information.
|
||||||
|
|
||||||
--noinput
|
|
||||||
~~~~~~~~~
|
|
||||||
|
|
||||||
Use the ``--noinput`` option to suppress all user prompting, such as
|
|
||||||
"Are you sure?" confirmation messages. This is useful if ``django-admin.py``
|
|
||||||
is being executed as an unattended, automated script.
|
|
||||||
|
|
||||||
testserver <fixture fixture ...>
|
testserver <fixture fixture ...>
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
|
.. django-admin:: testserver
|
||||||
|
|
||||||
.. versionadded:: 1.0
|
.. versionadded:: 1.0
|
||||||
|
|
||||||
Runs a Django development server (as in ``runserver``) using data from the
|
Runs a Django development server (as in ``runserver``) using data from the
|
||||||
@ -727,8 +736,7 @@ Note that this server does *not* automatically detect changes to your Python
|
|||||||
source code (as ``runserver`` does). It does, however, detect changes to
|
source code (as ``runserver`` does). It does, however, detect changes to
|
||||||
templates.
|
templates.
|
||||||
|
|
||||||
--addrport [port number or ipaddr:port]
|
.. django-admin-option:: --addrport [port number or ipaddr:port]
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Use ``--addrport`` to specify a different port, or IP address and port, from
|
Use ``--addrport`` to specify a different port, or IP address and port, from
|
||||||
the default of 127.0.0.1:8000. This value follows exactly the same format and
|
the default of 127.0.0.1:8000. This value follows exactly the same format and
|
||||||
@ -752,6 +760,8 @@ To run on 1.2.3.4:7000 with a ``test`` fixture::
|
|||||||
validate
|
validate
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
.. django-admin:: validate
|
||||||
|
|
||||||
Validates all installed models (according to the ``INSTALLED_APPS`` setting)
|
Validates all installed models (according to the ``INSTALLED_APPS`` setting)
|
||||||
and prints validation errors to standard output.
|
and prints validation errors to standard output.
|
||||||
|
|
||||||
@ -761,8 +771,7 @@ Default options
|
|||||||
Although some subcommands may allow their own custom options, every subcommand
|
Although some subcommands may allow their own custom options, every subcommand
|
||||||
allows for the following options:
|
allows for the following options:
|
||||||
|
|
||||||
--pythonpath
|
.. django-admin-option:: --pythonpath
|
||||||
------------
|
|
||||||
|
|
||||||
Example usage::
|
Example usage::
|
||||||
|
|
||||||
@ -777,8 +786,7 @@ setting the Python path for you.
|
|||||||
|
|
||||||
.. _import search path: http://diveintopython.org/getting_to_know_python/everything_is_an_object.html
|
.. _import search path: http://diveintopython.org/getting_to_know_python/everything_is_an_object.html
|
||||||
|
|
||||||
--settings
|
.. django-admin-option:: --settings
|
||||||
----------
|
|
||||||
|
|
||||||
Example usage::
|
Example usage::
|
||||||
|
|
||||||
@ -792,8 +800,7 @@ variable.
|
|||||||
Note that this option is unnecessary in ``manage.py``, because it uses
|
Note that this option is unnecessary in ``manage.py``, because it uses
|
||||||
``settings.py`` from the current project by default.
|
``settings.py`` from the current project by default.
|
||||||
|
|
||||||
--traceback
|
.. django-admin-option:: --traceback
|
||||||
-----------
|
|
||||||
|
|
||||||
Example usage::
|
Example usage::
|
||||||
|
|
||||||
@ -803,10 +810,7 @@ By default, ``django-admin.py`` will show a simple error message whenever an
|
|||||||
error occurs. If you specify ``--traceback``, ``django-admin.py`` will
|
error occurs. If you specify ``--traceback``, ``django-admin.py`` will
|
||||||
output a full stack trace whenever an exception is raised.
|
output a full stack trace whenever an exception is raised.
|
||||||
|
|
||||||
.. _django-admin-verbosity:
|
.. django-admin-option:: --verbosity
|
||||||
|
|
||||||
--verbosity
|
|
||||||
-----------
|
|
||||||
|
|
||||||
Example usage::
|
Example usage::
|
||||||
|
|
||||||
@ -819,6 +823,23 @@ that ``django-admin.py`` should print to the console.
|
|||||||
* ``1`` means normal output (default).
|
* ``1`` means normal output (default).
|
||||||
* ``2`` means verbose output.
|
* ``2`` means verbose output.
|
||||||
|
|
||||||
|
Common options
|
||||||
|
==============
|
||||||
|
|
||||||
|
The following options are not available on every commands, but they are
|
||||||
|
common to a number of commands.
|
||||||
|
|
||||||
|
.. django-admin-option:: --locale
|
||||||
|
|
||||||
|
Use the ``--locale`` or ``-l`` option to specify the locale to process.
|
||||||
|
If not provided all locales are processed.
|
||||||
|
|
||||||
|
.. django-admin-option:: --noinput
|
||||||
|
|
||||||
|
Use the ``--noinput`` option to suppress all user prompting, such as "Are
|
||||||
|
you sure?" confirmation messages. This is useful if ``django-admin.py`` is
|
||||||
|
being executed as an unattended, automated script.
|
||||||
|
|
||||||
Extra niceties
|
Extra niceties
|
||||||
==============
|
==============
|
||||||
|
|
||||||
@ -844,5 +865,4 @@ distribution. It enables tab-completion of ``django-admin.py`` and
|
|||||||
with ``sql``.
|
with ``sql``.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
See :ref:`howto-custom-management-commands` for how to add customized actions.
|
See :ref:`howto-custom-management-commands` for how to add customized actions.
|
||||||
|
@ -94,9 +94,8 @@ See the docs for :meth:`~django.db.models.QuerySet.latest` for more.
|
|||||||
.. versionadded:: 1.1
|
.. versionadded:: 1.1
|
||||||
|
|
||||||
Defaults to ``True``, meaning Django will create the appropriate database
|
Defaults to ``True``, meaning Django will create the appropriate database
|
||||||
tables in :ref:`django-admin-syncdb` and remove them as part of a :ref:`reset
|
tables in :djadmin:`syncdb` and remove them as part of a :djadmin:`reset`
|
||||||
<django-admin-reset>` management command. That is, Django *manages* the
|
management command. That is, Django *manages* the database tables' lifecycles.
|
||||||
database tables' lifecycles.
|
|
||||||
|
|
||||||
If ``False``, no database table creation or deletion operations will be
|
If ``False``, no database table creation or deletion operations will be
|
||||||
performed for this model. This is useful if the model represents an existing
|
performed for this model. This is useful if the model represents an existing
|
||||||
|
@ -51,6 +51,18 @@ comment
|
|||||||
|
|
||||||
Ignore everything between ``{% comment %}`` and ``{% endcomment %}``
|
Ignore everything between ``{% comment %}`` and ``{% endcomment %}``
|
||||||
|
|
||||||
|
.. templatetag:: csrf_token
|
||||||
|
|
||||||
|
csrf_token
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
.. versionadded:: 1.1.2
|
||||||
|
|
||||||
|
In the Django 1.1.X series, this is a no-op tag that returns an empty string for
|
||||||
|
future compatibility purposes. In Django 1.2 and later, it is used for CSRF
|
||||||
|
protection, as described in the documentation for :ref:`Cross Site Request
|
||||||
|
Forgeries <ref-contrib-csrf>`.
|
||||||
|
|
||||||
.. templatetag:: cycle
|
.. templatetag:: cycle
|
||||||
|
|
||||||
csrf_token
|
csrf_token
|
||||||
|
36
docs/releases/1.1.2.txt
Normal file
36
docs/releases/1.1.2.txt
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
.. _releases-1.1.2:
|
||||||
|
|
||||||
|
==============================================
|
||||||
|
Django 1.1.2 release notes — UNDER DEVELOPMENT
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
This page documents release notes for the as-yet-unreleased Django
|
||||||
|
1.1.2. As such it is tentative and subject to change. It provides
|
||||||
|
up-to-date information for those who are following the 1.1.X branch.
|
||||||
|
|
||||||
|
This is the second "bugfix" release in the Django 1.1 series,
|
||||||
|
improving the stability and performance of the Django 1.1 codebase.
|
||||||
|
|
||||||
|
Django 1.1.2 maintains backwards compatibility with Django
|
||||||
|
1.1.0, but contain a number of fixes and other
|
||||||
|
improvements. Django 1.1.2 is a recommended upgrade for any
|
||||||
|
development or deployment currently using or targeting Django 1.1.
|
||||||
|
|
||||||
|
For full details on the new features, backwards incompatibilities, and
|
||||||
|
deprecated features in the 1.1 branch, see the :ref:`releases-1.1`.
|
||||||
|
|
||||||
|
One new feature
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Ordinarily, a point release would not include new features, but in the
|
||||||
|
case of Django 1.1.2, we have made an exception to this rule. Django
|
||||||
|
1.2 (the next major release of Django) will contain a feature that
|
||||||
|
will improve protection against Cross-Site Request Forgery (CSRF)
|
||||||
|
attacks. This feature requires the use of a new :ttag:`csrf_token`
|
||||||
|
template tag in all forms that Django renders.
|
||||||
|
|
||||||
|
To make it easier to support both 1.1.X and 1.2.X versions of Django with
|
||||||
|
the same templates, we have decided to introduce the :ttag:`csrf_token` template
|
||||||
|
tag to the 1.1.X branch. In the 1.1.X branch, :ttag:`csrf_token` does nothing -
|
||||||
|
it has no effect on templates or form processing. However, it means that the
|
||||||
|
same template will work with Django 1.2.
|
@ -14,8 +14,10 @@ fixes, and an easy upgrade path from Django 1.0.
|
|||||||
|
|
||||||
.. _new features: `What's new in Django 1.1`_
|
.. _new features: `What's new in Django 1.1`_
|
||||||
|
|
||||||
Backwards-incompatible changes
|
.. _backwards-incompatible-changes-1.1:
|
||||||
==============================
|
|
||||||
|
Backwards-incompatible changes in 1.1
|
||||||
|
=====================================
|
||||||
|
|
||||||
Django has a policy of :ref:`API stability <misc-api-stability>`. This means
|
Django has a policy of :ref:`API stability <misc-api-stability>`. This means
|
||||||
that, in general, code you develop against Django 1.0 should continue to work
|
that, in general, code you develop against Django 1.0 should continue to work
|
||||||
@ -150,6 +152,8 @@ Django 1.1 adds a ``permanent`` argument to the
|
|||||||
backwards-incompatible if you were using the ``redirect_to`` view with a
|
backwards-incompatible if you were using the ``redirect_to`` view with a
|
||||||
format-string key called 'permanent', which is highly unlikely.
|
format-string key called 'permanent', which is highly unlikely.
|
||||||
|
|
||||||
|
.. _deprecated-features-1.1:
|
||||||
|
|
||||||
Features deprecated in 1.1
|
Features deprecated in 1.1
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
157
docs/releases/1.2.txt
Normal file
157
docs/releases/1.2.txt
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
.. _releases-1.2:
|
||||||
|
|
||||||
|
============================================
|
||||||
|
Django 1.2 release notes — UNDER DEVELOPMENT
|
||||||
|
============================================
|
||||||
|
|
||||||
|
This page documents release notes for the as-yet-unreleased Django 1.2. As such
|
||||||
|
it is tentative and subject to change. It provides up-to-date information for
|
||||||
|
those who are following trunk.
|
||||||
|
|
||||||
|
Django 1.2 includes a number of nifty `new features`_, lots of bug
|
||||||
|
fixes, and an easy upgrade path from Django 1.1.
|
||||||
|
|
||||||
|
.. _new features: `What's new in Django 1.2`_
|
||||||
|
|
||||||
|
.. _backwards-incompatible-changes-1.2:
|
||||||
|
|
||||||
|
Backwards-incompatible changes in 1.2
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
CSRF Protection
|
||||||
|
---------------
|
||||||
|
|
||||||
|
There have been large changes to the way that CSRF protection works, detailed in
|
||||||
|
:ref:`the CSRF documentaton <ref-contrib-csrf>`. The following are the major
|
||||||
|
changes that developers must be aware of:
|
||||||
|
|
||||||
|
* ``CsrfResponseMiddleware`` and ``CsrfMiddleware`` have been deprecated, and
|
||||||
|
will be removed completely in Django 1.4, in favor of a template tag that
|
||||||
|
should be inserted into forms.
|
||||||
|
|
||||||
|
* All contrib apps use a ``csrf_protect`` decorator to protect the view. This
|
||||||
|
requires the use of the csrf_token template tag in the template, so if you
|
||||||
|
have used custom templates for contrib views, you MUST READ THE :ref:`UPGRADE
|
||||||
|
INSTRUCTIONS <ref-csrf-upgrading-notes>` to fix those templates.
|
||||||
|
|
||||||
|
* ``CsrfViewMiddleware`` is included in :setting:`MIDDLEWARE_CLASSES` by
|
||||||
|
default. This turns on CSRF protection by default, so that views that accept
|
||||||
|
POST requests need to be written to work with the middleware. Instructions
|
||||||
|
on how to do this are found in the CSRF docs.
|
||||||
|
|
||||||
|
* All of the CSRF has moved from contrib to core (with backwards compatible
|
||||||
|
imports in the old locations, which are deprecated).
|
||||||
|
|
||||||
|
``LazyObject``
|
||||||
|
--------------
|
||||||
|
|
||||||
|
``LazyObject`` is an undocumented utility class used for lazily wrapping other
|
||||||
|
objects of unknown type. In Django 1.1 and earlier, it handled introspection in
|
||||||
|
a non-standard way, depending on wrapped objects implementing a public method
|
||||||
|
``get_all_members()``. Since this could easily lead to name clashes, it has been
|
||||||
|
changed to use the standard method, involving ``__members__`` and ``__dir__()``.
|
||||||
|
If you used ``LazyObject`` in your own code, and implemented the
|
||||||
|
``get_all_members()`` method for wrapped objects, you need to make the following
|
||||||
|
changes:
|
||||||
|
|
||||||
|
* If your class does not have special requirements for introspection (i.e. you
|
||||||
|
have not implemented ``__getattr__()`` or other methods that allow for
|
||||||
|
attributes not discoverable by normal mechanisms), you can simply remove the
|
||||||
|
``get_all_members()`` method. The default implementation on ``LazyObject``
|
||||||
|
will do the right thing.
|
||||||
|
|
||||||
|
* If you have more complex requirements for introspection, first rename the
|
||||||
|
``get_all_members()`` method to ``__dir__()``. This is the standard method,
|
||||||
|
from Python 2.6 onwards, for supporting introspection. If you are require
|
||||||
|
support for Python < 2.6, add the following code to the class::
|
||||||
|
|
||||||
|
__members__ = property(lambda self: self.__dir__())
|
||||||
|
|
||||||
|
|
||||||
|
.. _deprecated-features-1.2:
|
||||||
|
|
||||||
|
Features deprecated in 1.2
|
||||||
|
==========================
|
||||||
|
|
||||||
|
CSRF response rewriting middleware
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
``CsrfResponseMiddleware``, the middleware that automatically inserted CSRF
|
||||||
|
tokens into POST forms in outgoing pages, has been deprecated in favor of a
|
||||||
|
template tag method (see above), and will be removed completely in Django
|
||||||
|
1.4. ``CsrfMiddleware``, which includes the functionality of
|
||||||
|
``CsrfResponseMiddleware`` and ``CsrfViewMiddleware`` has likewise been
|
||||||
|
deprecated.
|
||||||
|
|
||||||
|
Also, the CSRF module has moved from contrib to core, and the old imports are
|
||||||
|
deprecated, as described in the :ref:`upgrading notes <ref-csrf-upgrading-notes>`.
|
||||||
|
|
||||||
|
``SMTPConnection``
|
||||||
|
------------------
|
||||||
|
|
||||||
|
The ``SMTPConnection`` class has been deprecated in favor of a generic
|
||||||
|
E-mail backend API. Old code that explicitly instantiated an instance
|
||||||
|
of an SMTPConnection::
|
||||||
|
|
||||||
|
from django.core.mail import SMTPConnection
|
||||||
|
connection = SMTPConnection()
|
||||||
|
messages = get_notification_email()
|
||||||
|
connection.send_messages(messages)
|
||||||
|
|
||||||
|
should now call :meth:`~django.core.mail.get_connection()` to
|
||||||
|
instantiate a generic e-mail connection::
|
||||||
|
|
||||||
|
from django.core.mail import get_connection
|
||||||
|
connection = get_connection()
|
||||||
|
messages = get_notification_email()
|
||||||
|
connection.send_messages(messages)
|
||||||
|
|
||||||
|
Depending on the value of the :setting:`EMAIL_BACKEND` setting, this
|
||||||
|
may not return an SMTP connection. If you explicitly require an SMTP
|
||||||
|
connection with which to send e-mail, you can explicitly request an
|
||||||
|
SMTP connection::
|
||||||
|
|
||||||
|
from django.core.mail import get_connection
|
||||||
|
connection = get_connection('django.core.mail.backends.smtp')
|
||||||
|
messages = get_notification_email()
|
||||||
|
connection.send_messages(messages)
|
||||||
|
|
||||||
|
If your call to construct an instance of ``SMTPConnection`` required
|
||||||
|
additional arguments, those arguments can be passed to the
|
||||||
|
:meth:`~django.core.mail.get_connection()` call::
|
||||||
|
|
||||||
|
connection = get_connection('django.core.mail.backends.smtp', hostname='localhost', port=1234)
|
||||||
|
|
||||||
|
What's new in Django 1.2
|
||||||
|
========================
|
||||||
|
|
||||||
|
CSRF support
|
||||||
|
------------
|
||||||
|
|
||||||
|
Django now has much improved protection against :ref:`Cross-Site
|
||||||
|
Request Forgery (CSRF) attacks<ref-contrib-csrf>`. This type of attack
|
||||||
|
occurs when a malicious Web site contains a link, a form button or
|
||||||
|
some javascript that is intended to perform some action on your Web
|
||||||
|
site, using the credentials of a logged-in user who visits the
|
||||||
|
malicious site in their browser. A related type of attack, 'login
|
||||||
|
CSRF', where an attacking site tricks a user's browser into logging
|
||||||
|
into a site with someone else's credentials, is also covered.
|
||||||
|
|
||||||
|
E-mail Backends
|
||||||
|
---------------
|
||||||
|
|
||||||
|
You can now :ref:`configure the way that Django sends e-mail
|
||||||
|
<topic-email-backends>`. Instead of using SMTP to send all e-mail, you
|
||||||
|
can now choose a configurable e-mail backend to send messages. If your
|
||||||
|
hosting provider uses a sandbox or some other non-SMTP technique for
|
||||||
|
sending mail, you can now construct an e-mail backend that will allow
|
||||||
|
Django's standard :ref:`mail sending methods<topics-email>` to use
|
||||||
|
those facilities.
|
||||||
|
|
||||||
|
This also makes it easier to debug mail sending - Django ships with
|
||||||
|
backend implementations that allow you to send e-mail to a
|
||||||
|
:ref:`file<topic-email-file-backend>`, to the
|
||||||
|
:ref:`console<topic-email-console-backend>`, or to
|
||||||
|
:ref:`memory<topic-email-memory-backend>` - you can even configure all
|
||||||
|
e-mail to be :ref:`thrown away<topic-email-dummy-backend>`.
|
||||||
|
|
@ -1,5 +1,6 @@
|
|||||||
.. _releases-index:
|
.. _releases-index:
|
||||||
|
|
||||||
|
=============
|
||||||
Release notes
|
Release notes
|
||||||
=============
|
=============
|
||||||
|
|
||||||
@ -7,28 +8,60 @@ Release notes for the official Django releases. Each release note will tell you
|
|||||||
what's new in each version, and will also describe any backwards-incompatible
|
what's new in each version, and will also describe any backwards-incompatible
|
||||||
changes made in that version.
|
changes made in that version.
|
||||||
|
|
||||||
|
For those upgrading to a new version of Django, you will need to check
|
||||||
|
all the backwards-incompatible changes and deprecated features for
|
||||||
|
each 'final' release from the one after your current Django version,
|
||||||
|
up to and including the new version.
|
||||||
|
|
||||||
|
Final releases
|
||||||
|
==============
|
||||||
|
|
||||||
|
1.2 release
|
||||||
|
-----------
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
0.95
|
1.2
|
||||||
0.96
|
|
||||||
1.0-alpha-1
|
1.1 release
|
||||||
1.0-alpha-2
|
-----------
|
||||||
1.0-beta
|
.. toctree::
|
||||||
1.0-beta-2
|
:maxdepth: 1
|
||||||
1.0
|
|
||||||
1.0.1
|
1.1.2
|
||||||
1.0.2
|
|
||||||
1.1-alpha-1
|
|
||||||
1.1-beta-1
|
|
||||||
1.1-rc-1
|
|
||||||
1.1
|
1.1
|
||||||
|
|
||||||
.. seealso::
|
1.0 release
|
||||||
|
-----------
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
The list of `backwards-incompatible changes`_ made in the current
|
1.0.2
|
||||||
development "trunk". If you're running versions of Django newer than an
|
1.0.1
|
||||||
official release, you should keep track of new pieces pointed there. It's
|
1.0
|
||||||
also fun reading if you're looking forward to new versions of Django.
|
|
||||||
|
|
||||||
.. _backwards-incompatible changes: http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges
|
Pre-1.0 releases
|
||||||
|
----------------
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
0.96
|
||||||
|
0.95
|
||||||
|
|
||||||
|
Development releases
|
||||||
|
====================
|
||||||
|
|
||||||
|
These notes are retained for historical purposes. If you are upgrading
|
||||||
|
between formal Django releases, you don't need to worry about these
|
||||||
|
notes.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
1.1-rc-1
|
||||||
|
1.1-beta-1
|
||||||
|
1.1-alpha-1
|
||||||
|
1.0-beta-2
|
||||||
|
1.0-beta
|
||||||
|
1.0-alpha-2
|
||||||
|
1.0-alpha-1
|
||||||
|
@ -179,9 +179,9 @@ Local-memory caching
|
|||||||
If you want the speed advantages of in-memory caching but don't have the
|
If you want the speed advantages of in-memory caching but don't have the
|
||||||
capability of running Memcached, consider the local-memory cache backend. This
|
capability of running Memcached, consider the local-memory cache backend. This
|
||||||
cache is multi-process and thread-safe. To use it, set ``CACHE_BACKEND`` to
|
cache is multi-process and thread-safe. To use it, set ``CACHE_BACKEND`` to
|
||||||
``"locmem:///"``. For example::
|
``"locmem://"``. For example::
|
||||||
|
|
||||||
CACHE_BACKEND = 'locmem:///'
|
CACHE_BACKEND = 'locmem://'
|
||||||
|
|
||||||
Note that each process will have its own private cache instance, which means no
|
Note that each process will have its own private cache instance, which means no
|
||||||
cross-process caching is possible. This obviously also means the local memory
|
cross-process caching is possible. This obviously also means the local memory
|
||||||
@ -199,7 +199,7 @@ various places but a development/test environment where you don't want to cache
|
|||||||
and don't want to have to change your code to special-case the latter. To
|
and don't want to have to change your code to special-case the latter. To
|
||||||
activate dummy caching, set ``CACHE_BACKEND`` like so::
|
activate dummy caching, set ``CACHE_BACKEND`` like so::
|
||||||
|
|
||||||
CACHE_BACKEND = 'dummy:///'
|
CACHE_BACKEND = 'dummy://'
|
||||||
|
|
||||||
Using a custom cache backend
|
Using a custom cache backend
|
||||||
----------------------------
|
----------------------------
|
||||||
@ -249,7 +249,7 @@ In this example, ``timeout`` is set to ``60``::
|
|||||||
|
|
||||||
In this example, ``timeout`` is ``30`` and ``max_entries`` is ``400``::
|
In this example, ``timeout`` is ``30`` and ``max_entries`` is ``400``::
|
||||||
|
|
||||||
CACHE_BACKEND = "locmem:///?timeout=30&max_entries=400"
|
CACHE_BACKEND = "locmem://?timeout=30&max_entries=400"
|
||||||
|
|
||||||
Invalid arguments are silently ignored, as are invalid values of known
|
Invalid arguments are silently ignored, as are invalid values of known
|
||||||
arguments.
|
arguments.
|
||||||
|
@ -10,7 +10,7 @@ Sending e-mail
|
|||||||
Although Python makes sending e-mail relatively easy via the `smtplib
|
Although Python makes sending e-mail relatively easy via the `smtplib
|
||||||
library`_, Django provides a couple of light wrappers over it. These wrappers
|
library`_, Django provides a couple of light wrappers over it. These wrappers
|
||||||
are provided to make sending e-mail extra quick, to make it easy to test
|
are provided to make sending e-mail extra quick, to make it easy to test
|
||||||
email sending during development, and to provide support for platforms that
|
e-mail sending during development, and to provide support for platforms that
|
||||||
can't use SMTP.
|
can't use SMTP.
|
||||||
|
|
||||||
The code lives in the ``django.core.mail`` module.
|
The code lives in the ``django.core.mail`` module.
|
||||||
@ -64,7 +64,7 @@ are required.
|
|||||||
* ``auth_password``: The optional password to use to authenticate to the
|
* ``auth_password``: The optional password to use to authenticate to the
|
||||||
SMTP server. If this isn't provided, Django will use the value of the
|
SMTP server. If this isn't provided, Django will use the value of the
|
||||||
``EMAIL_HOST_PASSWORD`` setting.
|
``EMAIL_HOST_PASSWORD`` setting.
|
||||||
* ``connection``: The optional email backend to use to send the mail.
|
* ``connection``: The optional e-mail backend to use to send the mail.
|
||||||
If unspecified, an instance of the default backend will be used.
|
If unspecified, an instance of the default backend will be used.
|
||||||
See the documentation on :ref:`E-mail backends <topic-email-backends>`
|
See the documentation on :ref:`E-mail backends <topic-email-backends>`
|
||||||
for more details.
|
for more details.
|
||||||
@ -215,8 +215,8 @@ message itself. The :ref:`e-mail backend <topic-email-backends>` is then
|
|||||||
responsible for sending the e-mail.
|
responsible for sending the e-mail.
|
||||||
|
|
||||||
For convenience, :class:`~django.core.mail.EmailMessage` provides a simple
|
For convenience, :class:`~django.core.mail.EmailMessage` provides a simple
|
||||||
``send()`` method for sending a single email. If you need to send multiple
|
``send()`` method for sending a single e-mail. If you need to send multiple
|
||||||
messages, the email backend API :ref:`provides an alternative
|
messages, the e-mail backend API :ref:`provides an alternative
|
||||||
<topics-sending-multiple-emails>`.
|
<topics-sending-multiple-emails>`.
|
||||||
|
|
||||||
EmailMessage Objects
|
EmailMessage Objects
|
||||||
@ -264,7 +264,7 @@ For example::
|
|||||||
The class has the following methods:
|
The class has the following methods:
|
||||||
|
|
||||||
* ``send(fail_silently=False)`` sends the message. If a connection was
|
* ``send(fail_silently=False)`` sends the message. If a connection was
|
||||||
specified when the email was constructed, that connection will be used.
|
specified when the e-mail was constructed, that connection will be used.
|
||||||
Otherwise, an instance of the default backend will be instantiated and
|
Otherwise, an instance of the default backend will be instantiated and
|
||||||
used. If the keyword argument ``fail_silently`` is ``True``, exceptions
|
used. If the keyword argument ``fail_silently`` is ``True``, exceptions
|
||||||
raised while sending the message will be quashed.
|
raised while sending the message will be quashed.
|
||||||
@ -358,9 +358,9 @@ The actual sending of an e-mail is handled by the e-mail backend.
|
|||||||
|
|
||||||
The e-mail backend class has the following methods:
|
The e-mail backend class has the following methods:
|
||||||
|
|
||||||
* ``open()`` instantiates an long-lived email-sending connection.
|
* ``open()`` instantiates an long-lived e-mail-sending connection.
|
||||||
|
|
||||||
* ``close()`` closes the current email-sending connection.
|
* ``close()`` closes the current e-mail-sending connection.
|
||||||
|
|
||||||
* ``send_messages(email_messages)`` sends a list of
|
* ``send_messages(email_messages)`` sends a list of
|
||||||
:class:`~django.core.mail.EmailMessage` objects. If the connection is
|
:class:`~django.core.mail.EmailMessage` objects. If the connection is
|
||||||
@ -379,11 +379,11 @@ instance of the e-mail backend that you can use.
|
|||||||
.. function:: get_connection(backend=None, fail_silently=False, *args, **kwargs)
|
.. function:: get_connection(backend=None, fail_silently=False, *args, **kwargs)
|
||||||
|
|
||||||
By default, a call to ``get_connection()`` will return an instance of the
|
By default, a call to ``get_connection()`` will return an instance of the
|
||||||
email backend specified in :setting:`EMAIL_BACKEND`. If you specify the
|
e-mail backend specified in :setting:`EMAIL_BACKEND`. If you specify the
|
||||||
``backend`` argument, an instance of that backend will be instantiated.
|
``backend`` argument, an instance of that backend will be instantiated.
|
||||||
|
|
||||||
The ``fail_silently`` argument controls how the backend should handle errors.
|
The ``fail_silently`` argument controls how the backend should handle errors.
|
||||||
If ``fail_silently`` is True, exceptions during the email sending process
|
If ``fail_silently`` is True, exceptions during the e-mail sending process
|
||||||
will be silently ignored.
|
will be silently ignored.
|
||||||
|
|
||||||
All other arguments are passed directly to the constructor of the
|
All other arguments are passed directly to the constructor of the
|
||||||
@ -391,8 +391,8 @@ e-mail backend.
|
|||||||
|
|
||||||
Django ships with several e-mail sending backends. With the exception of the
|
Django ships with several e-mail sending backends. With the exception of the
|
||||||
SMTP backend (which is the default), these backends are only useful during
|
SMTP backend (which is the default), these backends are only useful during
|
||||||
testing and development. If you have special email sending requirements, you
|
testing and development. If you have special e-mail sending requirements, you
|
||||||
can :ref:`write your own email backend <topic-custom-email-backend>`.
|
can :ref:`write your own e-mail backend <topic-custom-email-backend>`.
|
||||||
|
|
||||||
.. _topic-email-smtp-backend:
|
.. _topic-email-smtp-backend:
|
||||||
|
|
||||||
@ -401,7 +401,7 @@ SMTP backend
|
|||||||
|
|
||||||
This is the default backend. E-mail will be sent through a SMTP server.
|
This is the default backend. E-mail will be sent through a SMTP server.
|
||||||
The server address and authentication credentials are set in the
|
The server address and authentication credentials are set in the
|
||||||
:setting:`EMAIL_HOST`, :setting:`EMAIL_POST`, :setting:`EMAIL_HOST_USER`,
|
:setting:`EMAIL_HOST`, :setting:`EMAIL_PORT`, :setting:`EMAIL_HOST_USER`,
|
||||||
:setting:`EMAIL_HOST_PASSWORD` and :setting:`EMAIL_USE_TLS` settings in your
|
:setting:`EMAIL_HOST_PASSWORD` and :setting:`EMAIL_USE_TLS` settings in your
|
||||||
settings file.
|
settings file.
|
||||||
|
|
||||||
@ -414,13 +414,15 @@ want to specify it explicitly, put the following in your settings::
|
|||||||
|
|
||||||
Prior to version 1.2, Django provided a
|
Prior to version 1.2, Django provided a
|
||||||
:class:`~django.core.mail.SMTPConnection` class. This class provided a way
|
:class:`~django.core.mail.SMTPConnection` class. This class provided a way
|
||||||
to directly control the use of SMTP to send email. This class has been
|
to directly control the use of SMTP to send e-mail. This class has been
|
||||||
deprecated in favor of the generic email backend API.
|
deprecated in favor of the generic e-mail backend API.
|
||||||
|
|
||||||
For backwards compatibility :class:`~django.core.mail.SMTPConnection` is
|
For backwards compatibility :class:`~django.core.mail.SMTPConnection` is
|
||||||
still available in ``django.core.mail`` as an alias for the SMTP backend.
|
still available in ``django.core.mail`` as an alias for the SMTP backend.
|
||||||
New code should use :meth:`~django.core.mail.get_connection` instead.
|
New code should use :meth:`~django.core.mail.get_connection` instead.
|
||||||
|
|
||||||
|
.. _topic-email-console-backend:
|
||||||
|
|
||||||
Console backend
|
Console backend
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@ -436,6 +438,8 @@ To specify this backend, put the following in your settings::
|
|||||||
This backend is not intended for use in production -- it is provided as a
|
This backend is not intended for use in production -- it is provided as a
|
||||||
convenience that can be used during development.
|
convenience that can be used during development.
|
||||||
|
|
||||||
|
.. _topic-email-file-backend:
|
||||||
|
|
||||||
File backend
|
File backend
|
||||||
~~~~~~~~~~~~
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
@ -453,6 +457,8 @@ To specify this backend, put the following in your settings::
|
|||||||
This backend is not intended for use in production -- it is provided as a
|
This backend is not intended for use in production -- it is provided as a
|
||||||
convenience that can be used during development.
|
convenience that can be used during development.
|
||||||
|
|
||||||
|
.. _topic-email-memory-backend:
|
||||||
|
|
||||||
In-memory backend
|
In-memory backend
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@ -469,6 +475,8 @@ To specify this backend, put the following in your settings::
|
|||||||
This backend is not intended for use in production -- it is provided as a
|
This backend is not intended for use in production -- it is provided as a
|
||||||
convenience that can be used during development and testing.
|
convenience that can be used during development and testing.
|
||||||
|
|
||||||
|
.. _topic-email-dummy-backend:
|
||||||
|
|
||||||
Dummy backend
|
Dummy backend
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
@ -500,15 +508,15 @@ implementation.
|
|||||||
|
|
||||||
.. _topics-sending-multiple-emails:
|
.. _topics-sending-multiple-emails:
|
||||||
|
|
||||||
Sending multiple emails
|
Sending multiple e-mails
|
||||||
-----------------------
|
------------------------
|
||||||
|
|
||||||
Establishing and closing an SMTP connection (or any other network connection,
|
Establishing and closing an SMTP connection (or any other network connection,
|
||||||
for that matter) is an expensive process. If you have a lot of emails to send,
|
for that matter) is an expensive process. If you have a lot of e-mails to send,
|
||||||
it makes sense to reuse an SMTP connection, rather than creating and
|
it makes sense to reuse an SMTP connection, rather than creating and
|
||||||
destroying a connection every time you want to send an email.
|
destroying a connection every time you want to send an e-mail.
|
||||||
|
|
||||||
There are two ways you tell an email backend to reuse a connection.
|
There are two ways you tell an e-mail backend to reuse a connection.
|
||||||
|
|
||||||
Firstly, you can use the ``send_messages()`` method. ``send_messages()`` takes
|
Firstly, you can use the ``send_messages()`` method. ``send_messages()`` takes
|
||||||
a list of :class:`~django.core.mail.EmailMessage` instances (or subclasses),
|
a list of :class:`~django.core.mail.EmailMessage` instances (or subclasses),
|
||||||
@ -516,11 +524,11 @@ and sends them all using a single connection.
|
|||||||
|
|
||||||
For example, if you have a function called ``get_notification_email()`` that
|
For example, if you have a function called ``get_notification_email()`` that
|
||||||
returns a list of :class:`~django.core.mail.EmailMessage` objects representing
|
returns a list of :class:`~django.core.mail.EmailMessage` objects representing
|
||||||
some periodic e-mail you wish to send out, you could send these emails using
|
some periodic e-mail you wish to send out, you could send these e-mails using
|
||||||
a single call to send_messages::
|
a single call to send_messages::
|
||||||
|
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
connection = mail.get_connection() # Use default email connection
|
connection = mail.get_connection() # Use default e-mail connection
|
||||||
messages = get_notification_email()
|
messages = get_notification_email()
|
||||||
connection.send_messages(messages)
|
connection.send_messages(messages)
|
||||||
|
|
||||||
@ -528,7 +536,7 @@ In this example, the call to ``send_messages()`` opens a connection on the
|
|||||||
backend, sends the list of messages, and then closes the connection again.
|
backend, sends the list of messages, and then closes the connection again.
|
||||||
|
|
||||||
The second approach is to use the ``open()`` and ``close()`` methods on the
|
The second approach is to use the ``open()`` and ``close()`` methods on the
|
||||||
email backend to manually control the connection. ``send_messages()`` will not
|
e-mail backend to manually control the connection. ``send_messages()`` will not
|
||||||
manually open or close the connection if it is already open, so if you
|
manually open or close the connection if it is already open, so if you
|
||||||
manually open the connection, you can control when it is closed. For example::
|
manually open the connection, you can control when it is closed. For example::
|
||||||
|
|
||||||
@ -538,10 +546,10 @@ manually open the connection, you can control when it is closed. For example::
|
|||||||
# Manually open the connection
|
# Manually open the connection
|
||||||
connection.open()
|
connection.open()
|
||||||
|
|
||||||
# Construct an email message that uses the connection
|
# Construct an e-mail message that uses the connection
|
||||||
email1 = mail.EmailMessage('Hello', 'Body goes here', 'from@example.com',
|
email1 = mail.EmailMessage('Hello', 'Body goes here', 'from@example.com',
|
||||||
['to1@example.com'], connection=connection)
|
['to1@example.com'], connection=connection)
|
||||||
email1.send() # Send the email
|
email1.send() # Send the e-mail
|
||||||
|
|
||||||
# Construct two more messages
|
# Construct two more messages
|
||||||
email2 = mail.EmailMessage('Hello', 'Body goes here', 'from@example.com',
|
email2 = mail.EmailMessage('Hello', 'Body goes here', 'from@example.com',
|
||||||
@ -549,7 +557,7 @@ manually open the connection, you can control when it is closed. For example::
|
|||||||
email3 = mail.EmailMessage('Hello', 'Body goes here', 'from@example.com',
|
email3 = mail.EmailMessage('Hello', 'Body goes here', 'from@example.com',
|
||||||
['to3@example.com'])
|
['to3@example.com'])
|
||||||
|
|
||||||
# Send the two emails in a single call -
|
# Send the two e-mails in a single call -
|
||||||
connection.send_messages([email2, email3])
|
connection.send_messages([email2, email3])
|
||||||
# The connection was already open so send_messages() doesn't close it.
|
# The connection was already open so send_messages() doesn't close it.
|
||||||
# We need to manually close the connection.
|
# We need to manually close the connection.
|
||||||
@ -566,10 +574,10 @@ people under the right conditions, and that those e-mails will contain the
|
|||||||
correct content.
|
correct content.
|
||||||
|
|
||||||
The easiest way to test your project's use of e-mail is to use the ``console``
|
The easiest way to test your project's use of e-mail is to use the ``console``
|
||||||
email backend. This backend redirects all email to stdout, allowing you to
|
e-mail backend. This backend redirects all e-mail to stdout, allowing you to
|
||||||
inspect the content of mail.
|
inspect the content of mail.
|
||||||
|
|
||||||
The ``file`` email backend can also be useful during development -- this backend
|
The ``file`` e-mail backend can also be useful during development -- this backend
|
||||||
dumps the contents of every SMTP connection to a file that can be inspected
|
dumps the contents of every SMTP connection to a file that can be inspected
|
||||||
at your leisure.
|
at your leisure.
|
||||||
|
|
||||||
@ -596,7 +604,7 @@ SMTPConnection
|
|||||||
|
|
||||||
.. deprecated:: 1.2
|
.. deprecated:: 1.2
|
||||||
|
|
||||||
The ``SMTPConnection`` class has been deprecated in favor of the generic email
|
The ``SMTPConnection`` class has been deprecated in favor of the generic e-mail
|
||||||
backend API.
|
backend API.
|
||||||
|
|
||||||
For backwards compatibility ``SMTPConnection`` is still available in
|
For backwards compatibility ``SMTPConnection`` is still available in
|
||||||
|
@ -40,7 +40,8 @@ algorithm the system follows to determine which Python code to execute:
|
|||||||
|
|
||||||
1. Django determines the root URLconf module to use. Ordinarily,
|
1. Django determines the root URLconf module to use. Ordinarily,
|
||||||
this is the value of the ``ROOT_URLCONF`` setting, but if the incoming
|
this is the value of the ``ROOT_URLCONF`` setting, but if the incoming
|
||||||
``HttpRequest`` object has an attribute called ``urlconf``, its value
|
``HttpRequest`` object has an attribute called ``urlconf`` (set by
|
||||||
|
middleware :ref:`request processing <request-middleware>`), its value
|
||||||
will be used in place of the ``ROOT_URLCONF`` setting.
|
will be used in place of the ``ROOT_URLCONF`` setting.
|
||||||
|
|
||||||
2. Django loads that Python module and looks for the variable
|
2. Django loads that Python module and looks for the variable
|
||||||
|
@ -980,19 +980,21 @@ subclass::
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
# Test definitions as before.
|
# Test definitions as before.
|
||||||
|
call_setup_methods()
|
||||||
|
|
||||||
def testFluffyAnimals(self):
|
def testFluffyAnimals(self):
|
||||||
# A test that uses the fixtures.
|
# A test that uses the fixtures.
|
||||||
|
call_some_test_code()
|
||||||
|
|
||||||
Here's specifically what will happen:
|
Here's specifically what will happen:
|
||||||
|
|
||||||
* At the start of each test case, before ``setUp()`` is run, Django will
|
* At the start of each test case, before ``setUp()`` is run, Django will
|
||||||
flush the database, returning the database to the state it was in
|
flush the database, returning the database to the state it was in
|
||||||
directly after ``syncdb`` was called.
|
directly after :djadmin:`syncdb` was called.
|
||||||
|
|
||||||
* Then, all the named fixtures are installed. In this example, Django will
|
* Then, all the named fixtures are installed. In this example, Django will
|
||||||
install any JSON fixture named ``mammals``, followed by any fixture named
|
install any JSON fixture named ``mammals``, followed by any fixture named
|
||||||
``birds``. See the :djadmin:`loaddata documentation<loaddata>` for more
|
``birds``. See the :djadmin:`loaddata` documentation for more
|
||||||
details on defining and installing fixtures.
|
details on defining and installing fixtures.
|
||||||
|
|
||||||
This flush/load procedure is repeated for each test in the test case, so you
|
This flush/load procedure is repeated for each test in the test case, so you
|
||||||
@ -1028,6 +1030,7 @@ For example::
|
|||||||
|
|
||||||
def testIndexPageView(self):
|
def testIndexPageView(self):
|
||||||
# Here you'd test your view using ``Client``.
|
# Here you'd test your view using ``Client``.
|
||||||
|
call_some_test_code()
|
||||||
|
|
||||||
This test case will use the contents of ``myapp.test_urls`` as the
|
This test case will use the contents of ``myapp.test_urls`` as the
|
||||||
URLconf for the duration of the test case.
|
URLconf for the duration of the test case.
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
"""
|
from django.db import models
|
||||||
|
|
||||||
|
class Advertisment(models.Model):
|
||||||
|
customer = models.CharField(max_length=100)
|
||||||
|
publications = models.ManyToManyField("model_package.Publication", null=True, blank=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
app_label = 'model_package'
|
||||||
|
|
||||||
|
__test__ = {'API_TESTS': """
|
||||||
>>> from models.publication import Publication
|
>>> from models.publication import Publication
|
||||||
>>> from models.article import Article
|
>>> from models.article import Article
|
||||||
>>> from django.contrib.auth.views import Site
|
>>> from django.contrib.auth.views import Site
|
||||||
@ -19,7 +28,6 @@
|
|||||||
>>> a.save()
|
>>> a.save()
|
||||||
>>> a.publications.add(p)
|
>>> a.publications.add(p)
|
||||||
>>> a.sites.add(current_site)
|
>>> a.sites.add(current_site)
|
||||||
>>> a.save()
|
|
||||||
|
|
||||||
>>> a = Article.objects.get(id=1)
|
>>> a = Article.objects.get(id=1)
|
||||||
>>> a
|
>>> a
|
||||||
@ -29,6 +37,19 @@
|
|||||||
>>> a.sites.count()
|
>>> a.sites.count()
|
||||||
1
|
1
|
||||||
|
|
||||||
"""
|
# Regression for #12248 - Models can exist in the test package, too
|
||||||
|
|
||||||
|
>>> ad = Advertisment(customer="Lawrence Journal-World")
|
||||||
|
>>> ad.save()
|
||||||
|
>>> ad.publications.add(p)
|
||||||
|
|
||||||
|
>>> ad = Advertisment.objects.get(id=1)
|
||||||
|
>>> ad
|
||||||
|
<Advertisment: Advertisment object>
|
||||||
|
|
||||||
|
>>> ad.publications.count()
|
||||||
|
1
|
||||||
|
|
||||||
|
"""}
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,6 +26,21 @@ class TwoAlbumFKAndAnE(models.Model):
|
|||||||
e = models.CharField(max_length=1)
|
e = models.CharField(max_length=1)
|
||||||
|
|
||||||
|
|
||||||
|
class Author(models.Model):
|
||||||
|
name = models.CharField(max_length=100)
|
||||||
|
|
||||||
|
|
||||||
|
class Book(models.Model):
|
||||||
|
name = models.CharField(max_length=100)
|
||||||
|
subtitle = models.CharField(max_length=100)
|
||||||
|
price = models.FloatField()
|
||||||
|
authors = models.ManyToManyField(Author, through='AuthorsBooks')
|
||||||
|
|
||||||
|
|
||||||
|
class AuthorsBooks(models.Model):
|
||||||
|
author = models.ForeignKey(Author)
|
||||||
|
book = models.ForeignKey(Book)
|
||||||
|
|
||||||
|
|
||||||
__test__ = {'API_TESTS':"""
|
__test__ = {'API_TESTS':"""
|
||||||
|
|
||||||
@ -95,4 +110,48 @@ Exception: <class 'regressiontests.admin_validation.models.TwoAlbumFKAndAnE'> ha
|
|||||||
|
|
||||||
>>> validate_inline(TwoAlbumFKAndAnEInline, None, Album)
|
>>> validate_inline(TwoAlbumFKAndAnEInline, None, Album)
|
||||||
|
|
||||||
|
# Regression test for #12203/#12237 - Fail more gracefully when a M2M field that
|
||||||
|
# specifies the 'through' option is included in the 'fields' or the 'fieldsets'
|
||||||
|
# ModelAdmin options.
|
||||||
|
|
||||||
|
>>> class BookAdmin(admin.ModelAdmin):
|
||||||
|
... fields = ['authors']
|
||||||
|
|
||||||
|
>>> validate(BookAdmin, Book)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ImproperlyConfigured: 'BookAdmin.fields' can't include the ManyToManyField field 'authors' because 'authors' manually specifies a 'through' model.
|
||||||
|
|
||||||
|
>>> class FieldsetBookAdmin(admin.ModelAdmin):
|
||||||
|
... fieldsets = (
|
||||||
|
... ('Header 1', {'fields': ('name',)}),
|
||||||
|
... ('Header 2', {'fields': ('authors',)}),
|
||||||
|
... )
|
||||||
|
|
||||||
|
>>> validate(FieldsetBookAdmin, Book)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ImproperlyConfigured: 'FieldsetBookAdmin.fieldsets[1][1]['fields']' can't include the ManyToManyField field 'authors' because 'authors' manually specifies a 'through' model.
|
||||||
|
|
||||||
|
>>> class NestedFieldsetAdmin(admin.ModelAdmin):
|
||||||
|
... fieldsets = (
|
||||||
|
... ('Main', {'fields': ('price', ('name', 'subtitle'))}),
|
||||||
|
... )
|
||||||
|
|
||||||
|
>>> validate(NestedFieldsetAdmin, Book)
|
||||||
|
|
||||||
|
# Regression test for #12209 -- If the explicitly provided through model
|
||||||
|
# is specified as a string, the admin should still be able use
|
||||||
|
# Model.m2m_field.through
|
||||||
|
|
||||||
|
>>> class AuthorsInline(admin.TabularInline):
|
||||||
|
... model = Book.authors.through
|
||||||
|
|
||||||
|
>>> class BookAdmin(admin.ModelAdmin):
|
||||||
|
... inlines = [AuthorsInline]
|
||||||
|
|
||||||
|
# If the through model is still a string (and hasn't been resolved to a model)
|
||||||
|
# the validation will fail.
|
||||||
|
>>> validate(BookAdmin, Book)
|
||||||
|
|
||||||
"""}
|
"""}
|
||||||
|
1
tests/regressiontests/bash_completion/__init__.py
Normal file
1
tests/regressiontests/bash_completion/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
|
@ -0,0 +1,14 @@
|
|||||||
|
import sys, os
|
||||||
|
from optparse import OptionParser, make_option
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
option_list = BaseCommand.option_list + (
|
||||||
|
make_option("--list", action="store_true", dest="list",
|
||||||
|
help="Print all options"),
|
||||||
|
)
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
pass
|
1
tests/regressiontests/bash_completion/models.py
Normal file
1
tests/regressiontests/bash_completion/models.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
87
tests/regressiontests/bash_completion/tests.py
Normal file
87
tests/regressiontests/bash_completion/tests.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
"""
|
||||||
|
A series of tests to establish that the command-line bash completion works.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
import sys
|
||||||
|
import StringIO
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.management import ManagementUtility
|
||||||
|
|
||||||
|
class BashCompletionTests(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
Testing the Python level bash completion code.
|
||||||
|
This requires setting up the environment as if we got passed data
|
||||||
|
from bash.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.old_DJANGO_AUTO_COMPLETE = os.environ.get('DJANGO_AUTO_COMPLETE')
|
||||||
|
os.environ['DJANGO_AUTO_COMPLETE'] = '1'
|
||||||
|
self.output = StringIO.StringIO()
|
||||||
|
self.old_stdout = sys.stdout
|
||||||
|
sys.stdout = self.output
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
sys.stdout = self.old_stdout
|
||||||
|
if self.old_DJANGO_AUTO_COMPLETE:
|
||||||
|
os.environ['DJANGO_AUTO_COMPLETE'] = self.old_DJANGO_AUTO_COMPLETE
|
||||||
|
else:
|
||||||
|
del os.environ['DJANGO_AUTO_COMPLETE']
|
||||||
|
|
||||||
|
def _user_input(self, input_str):
|
||||||
|
os.environ['COMP_WORDS'] = input_str
|
||||||
|
os.environ['COMP_CWORD'] = str(len(input_str.split()) - 1)
|
||||||
|
sys.argv = input_str.split(' ')
|
||||||
|
|
||||||
|
def _run_autocomplete(self):
|
||||||
|
util = ManagementUtility(argv=sys.argv)
|
||||||
|
try:
|
||||||
|
util.autocomplete()
|
||||||
|
except SystemExit:
|
||||||
|
pass
|
||||||
|
return self.output.getvalue().strip().split('\n')
|
||||||
|
|
||||||
|
def test_django_admin_py(self):
|
||||||
|
"django_admin.py will autocomplete option flags"
|
||||||
|
self._user_input('django-admin.py sqlall --v')
|
||||||
|
output = self._run_autocomplete()
|
||||||
|
self.assertEqual(output, ['--verbosity='])
|
||||||
|
|
||||||
|
def test_manage_py(self):
|
||||||
|
"manage.py will autocomplete option flags"
|
||||||
|
self._user_input('manage.py sqlall --v')
|
||||||
|
output = self._run_autocomplete()
|
||||||
|
self.assertEqual(output, ['--verbosity='])
|
||||||
|
|
||||||
|
def test_custom_command(self):
|
||||||
|
"A custom command can autocomplete option flags"
|
||||||
|
self._user_input('django-admin.py test_command --l')
|
||||||
|
output = self._run_autocomplete()
|
||||||
|
self.assertEqual(output, ['--list'])
|
||||||
|
|
||||||
|
def test_subcommands(self):
|
||||||
|
"Subcommands can be autocompleted"
|
||||||
|
self._user_input('django-admin.py sql')
|
||||||
|
output = self._run_autocomplete()
|
||||||
|
self.assertEqual(output, ['sql sqlall sqlclear sqlcustom sqlflush sqlindexes sqlinitialdata sqlreset sqlsequencereset'])
|
||||||
|
|
||||||
|
def test_help(self):
|
||||||
|
"No errors, just an empty list if there are no autocomplete options"
|
||||||
|
self._user_input('django-admin.py help --')
|
||||||
|
output = self._run_autocomplete()
|
||||||
|
self.assertEqual(output, [''])
|
||||||
|
|
||||||
|
def test_runfcgi(self):
|
||||||
|
"Command arguments will be autocompleted"
|
||||||
|
self._user_input('django-admin.py runfcgi h')
|
||||||
|
output = self._run_autocomplete()
|
||||||
|
self.assertEqual(output, ['host='])
|
||||||
|
|
||||||
|
def test_app_completion(self):
|
||||||
|
"Application names will be autocompleted for an AppCommand"
|
||||||
|
self._user_input('django-admin.py sqlall a')
|
||||||
|
output = self._run_autocomplete()
|
||||||
|
app_labels = [name.split('.')[-1] for name in settings.INSTALLED_APPS]
|
||||||
|
self.assertEqual(output, sorted(label for label in app_labels if label.startswith('a')))
|
@ -115,6 +115,23 @@ u'c1'
|
|||||||
>>> results[0].second_child.name
|
>>> results[0].second_child.name
|
||||||
u'c2'
|
u'c2'
|
||||||
|
|
||||||
|
# Test for #12163 - Pickling error saving session with unsaved model instances.
|
||||||
|
>>> from django.contrib.sessions.backends.db import SessionStore
|
||||||
|
>>> SESSION_KEY = '2b1189a188b44ad18c35e1baac6ceead'
|
||||||
|
>>> item = Item()
|
||||||
|
>>> item._deferred
|
||||||
|
False
|
||||||
|
>>> s = SessionStore(SESSION_KEY)
|
||||||
|
>>> s.clear()
|
||||||
|
>>> s['item'] = item
|
||||||
|
>>> s.save()
|
||||||
|
>>> s = SessionStore(SESSION_KEY)
|
||||||
|
>>> s.modified = True
|
||||||
|
>>> s.save()
|
||||||
|
>>> i2 = s['item']
|
||||||
|
>>> i2._deferred # Item must still be non-deferred
|
||||||
|
False
|
||||||
|
|
||||||
# Finally, we need to flush the app cache for the defer module.
|
# Finally, we need to flush the app cache for the defer module.
|
||||||
# Using only/defer creates some artifical entries in the app cache
|
# Using only/defer creates some artifical entries in the app cache
|
||||||
# that messes up later tests. Purge all entries, just to be sure.
|
# that messes up later tests. Purge all entries, just to be sure.
|
||||||
|
@ -1,4 +1,29 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
##########
|
||||||
|
# Fields #
|
||||||
|
##########
|
||||||
|
|
||||||
|
Each Field class does some sort of validation. Each Field has a clean() method,
|
||||||
|
which either raises django.forms.ValidationError or returns the "clean"
|
||||||
|
data -- usually a Unicode object, but, in some rare cases, a list.
|
||||||
|
|
||||||
|
Each Field's __init__() takes at least these parameters:
|
||||||
|
required -- Boolean that specifies whether the field is required.
|
||||||
|
True by default.
|
||||||
|
widget -- A Widget class, or instance of a Widget class, that should be
|
||||||
|
used for this Field when displaying it. Each Field has a default
|
||||||
|
Widget that it'll use if you don't specify this. In most cases,
|
||||||
|
the default widget is TextInput.
|
||||||
|
label -- A verbose name for this field, for use in displaying this field in
|
||||||
|
a form. By default, Django will use a "pretty" version of the form
|
||||||
|
field name, if the Field is part of a Form.
|
||||||
|
initial -- A value to use in this Field's initial display. This value is
|
||||||
|
*not* used as a fallback if data isn't given.
|
||||||
|
|
||||||
|
Other than that, the Field subclasses have class-specific options for
|
||||||
|
__init__(). For example, CharField has a max_length option.
|
||||||
|
"""
|
||||||
import datetime
|
import datetime
|
||||||
import time
|
import time
|
||||||
import re
|
import re
|
||||||
|
@ -102,4 +102,34 @@ u'<ul class="errorlist"><li>(Hidden field data) This field is required.</li></ul
|
|||||||
>>> f.as_table()
|
>>> f.as_table()
|
||||||
u'<tr><td colspan="2"><ul class="errorlist"><li>(Hidden field data) This field is required.</li></ul><input type="hidden" name="data" id="id_data" /></td></tr>'
|
u'<tr><td colspan="2"><ul class="errorlist"><li>(Hidden field data) This field is required.</li></ul><input type="hidden" name="data" id="id_data" /></td></tr>'
|
||||||
|
|
||||||
|
###################################################
|
||||||
|
# Tests for XSS vulnerabilities in error messages #
|
||||||
|
###################################################
|
||||||
|
|
||||||
|
# The forms layer doesn't escape input values directly because error messages
|
||||||
|
# might be presented in non-HTML contexts. Instead, the message is just marked
|
||||||
|
# for escaping by the template engine. So we'll need to construct a little
|
||||||
|
# silly template to trigger the escaping.
|
||||||
|
|
||||||
|
>>> from django.template import Template, Context
|
||||||
|
>>> t = Template('{{ form.errors }}')
|
||||||
|
|
||||||
|
>>> class SomeForm(Form):
|
||||||
|
... field = ChoiceField(choices=[('one', 'One')])
|
||||||
|
>>> f = SomeForm({'field': '<script>'})
|
||||||
|
>>> t.render(Context({'form': f}))
|
||||||
|
u'<ul class="errorlist"><li>field<ul class="errorlist"><li>Select a valid choice. <script> is not one of the available choices.</li></ul></li></ul>'
|
||||||
|
|
||||||
|
>>> class SomeForm(Form):
|
||||||
|
... field = MultipleChoiceField(choices=[('one', 'One')])
|
||||||
|
>>> f = SomeForm({'field': ['<script>']})
|
||||||
|
>>> t.render(Context({'form': f}))
|
||||||
|
u'<ul class="errorlist"><li>field<ul class="errorlist"><li>Select a valid choice. <script> is not one of the available choices.</li></ul></li></ul>'
|
||||||
|
|
||||||
|
>>> from regressiontests.forms.models import ChoiceModel
|
||||||
|
>>> class SomeForm(Form):
|
||||||
|
... field = ModelMultipleChoiceField(ChoiceModel.objects.all())
|
||||||
|
>>> f = SomeForm({'field': ['<script>']})
|
||||||
|
>>> t.render(Context({'form': f}))
|
||||||
|
u'<ul class="errorlist"><li>field<ul class="errorlist"><li>"<script>" is not a valid value for a primary key.</li></ul></li></ul>'
|
||||||
"""
|
"""
|
||||||
|
@ -167,4 +167,10 @@ Traceback (most recent call last):
|
|||||||
...
|
...
|
||||||
ValueError: Cannot assign "<Child: Child object>": "Child.parent" must be a "Parent" instance.
|
ValueError: Cannot assign "<Child: Child object>": "Child.parent" must be a "Parent" instance.
|
||||||
|
|
||||||
|
# Regression for #12190 -- Should be able to instantiate a FK
|
||||||
|
# outside of a model, and interrogate its related field.
|
||||||
|
>>> cat = models.ForeignKey(Category)
|
||||||
|
>>> cat.rel.get_related_field().name
|
||||||
|
'id'
|
||||||
|
|
||||||
"""}
|
"""}
|
||||||
|
@ -755,10 +755,20 @@ Bug #6180, #6203 -- dates with limits and/or counts
|
|||||||
>>> Item.objects.dates('created', 'day')[0]
|
>>> Item.objects.dates('created', 'day')[0]
|
||||||
datetime.datetime(2007, 12, 19, 0, 0)
|
datetime.datetime(2007, 12, 19, 0, 0)
|
||||||
|
|
||||||
Bug #7087 -- dates with extra select columns
|
Bug #7087/#12242 -- dates with extra select columns
|
||||||
>>> Item.objects.dates('created', 'day').extra(select={'a': 1})
|
>>> Item.objects.dates('created', 'day').extra(select={'a': 1})
|
||||||
[datetime.datetime(2007, 12, 19, 0, 0), datetime.datetime(2007, 12, 20, 0, 0)]
|
[datetime.datetime(2007, 12, 19, 0, 0), datetime.datetime(2007, 12, 20, 0, 0)]
|
||||||
|
|
||||||
|
>>> Item.objects.extra(select={'a': 1}).dates('created', 'day')
|
||||||
|
[datetime.datetime(2007, 12, 19, 0, 0), datetime.datetime(2007, 12, 20, 0, 0)]
|
||||||
|
|
||||||
|
>>> name="one"
|
||||||
|
>>> Item.objects.dates('created', 'day').extra(where=['name=%s'], params=[name])
|
||||||
|
[datetime.datetime(2007, 12, 19, 0, 0)]
|
||||||
|
|
||||||
|
>>> Item.objects.extra(where=['name=%s'], params=[name]).dates('created', 'day')
|
||||||
|
[datetime.datetime(2007, 12, 19, 0, 0)]
|
||||||
|
|
||||||
Bug #7155 -- nullable dates
|
Bug #7155 -- nullable dates
|
||||||
>>> Item.objects.dates('modified', 'day')
|
>>> Item.objects.dates('modified', 'day')
|
||||||
[datetime.datetime(2007, 12, 19, 0, 0)]
|
[datetime.datetime(2007, 12, 19, 0, 0)]
|
||||||
|
7
tests/regressiontests/urlpatterns_reverse/middleware.py
Normal file
7
tests/regressiontests/urlpatterns_reverse/middleware.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from django.core.urlresolvers import set_urlconf
|
||||||
|
|
||||||
|
import urlconf_inner
|
||||||
|
|
||||||
|
class ChangeURLconfMiddleware(object):
|
||||||
|
def process_request(self, request):
|
||||||
|
request.urlconf = urlconf_inner.__name__
|
@ -16,11 +16,16 @@ ImproperlyConfigured: The included urlconf regressiontests.urlpatterns_reverse.n
|
|||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse, resolve, NoReverseMatch, Resolver404
|
from django.core.urlresolvers import reverse, resolve, NoReverseMatch, Resolver404
|
||||||
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
|
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
import urlconf_outer
|
||||||
|
import urlconf_inner
|
||||||
|
import middleware
|
||||||
|
|
||||||
test_data = (
|
test_data = (
|
||||||
('places', '/places/3/', [3], {}),
|
('places', '/places/3/', [3], {}),
|
||||||
('places', '/places/3/', ['3'], {}),
|
('places', '/places/3/', ['3'], {}),
|
||||||
@ -239,3 +244,35 @@ class NamespaceTests(TestCase):
|
|||||||
self.assertEquals('/other1/inner/37/42/', reverse('nodefault:urlobject-view', args=[37,42], 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'))
|
self.assertEquals('/other1/inner/42/37/', reverse('nodefault:urlobject-view', kwargs={'arg1':42, 'arg2':37}, current_app='other-ns1'))
|
||||||
|
|
||||||
|
|
||||||
|
class RequestURLconfTests(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.root_urlconf = settings.ROOT_URLCONF
|
||||||
|
self.middleware_classes = settings.MIDDLEWARE_CLASSES
|
||||||
|
settings.ROOT_URLCONF = urlconf_outer.__name__
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
settings.ROOT_URLCONF = self.root_urlconf
|
||||||
|
settings.MIDDLEWARE_CLASSES = self.middleware_classes
|
||||||
|
|
||||||
|
def test_urlconf(self):
|
||||||
|
response = self.client.get('/test/me/')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(response.content, 'outer:/test/me/,'
|
||||||
|
'inner:/inner_urlconf/second_test/')
|
||||||
|
response = self.client.get('/inner_urlconf/second_test/')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
response = self.client.get('/second_test/')
|
||||||
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
|
def test_urlconf_overridden(self):
|
||||||
|
settings.MIDDLEWARE_CLASSES += (
|
||||||
|
'%s.ChangeURLconfMiddleware' % middleware.__name__,
|
||||||
|
)
|
||||||
|
response = self.client.get('/test/me/')
|
||||||
|
self.assertEqual(response.status_code, 404)
|
||||||
|
response = self.client.get('/inner_urlconf/second_test/')
|
||||||
|
self.assertEqual(response.status_code, 404)
|
||||||
|
response = self.client.get('/second_test/')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(response.content, 'outer:,inner:/second_test/')
|
||||||
|
12
tests/regressiontests/urlpatterns_reverse/urlconf_inner.py
Normal file
12
tests/regressiontests/urlpatterns_reverse/urlconf_inner.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from django.conf.urls.defaults import *
|
||||||
|
from django.template import Template, Context
|
||||||
|
from django.http import HttpResponse
|
||||||
|
|
||||||
|
def inner_view(request):
|
||||||
|
content = Template('{% url outer as outer_url %}outer:{{ outer_url }},'
|
||||||
|
'{% url inner as inner_url %}inner:{{ inner_url }}').render(Context())
|
||||||
|
return HttpResponse(content)
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
url(r'^second_test/$', inner_view, name='inner'),
|
||||||
|
)
|
@ -0,0 +1,9 @@
|
|||||||
|
from django.conf.urls.defaults import *
|
||||||
|
|
||||||
|
import urlconf_inner
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
url(r'^test/me/$', urlconf_inner.inner_view, name='outer'),
|
||||||
|
url(r'^inner_urlconf/', include(urlconf_inner.__name__))
|
||||||
|
)
|
Loading…
x
Reference in New Issue
Block a user