Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

gis: Merged revisions 7574-7583,7585-7586,7590-7602,7614-7615,7619-76…

…25,7629,7632-7636 via svnmerge from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@7642 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 842dae0ed59cc7566cf35090093222ea3a61ec79 1 parent 4ec80c4
@jbronn jbronn authored
Showing with 1,563 additions and 441 deletions.
  1. +5 −1 AUTHORS
  2. +5 −4 django/conf/global_settings.py
  3. BIN  django/conf/locale/es/LC_MESSAGES/django.mo
  4. +173 −186 django/conf/locale/es/LC_MESSAGES/django.po
  5. +4 −90 django/contrib/auth/create_superuser.py
  6. +6 −4 django/contrib/auth/{management.py → management/__init__.py}
  7. 0  django/contrib/auth/management/commands/__init__.py
  8. +123 −0 django/contrib/auth/management/commands/createsuperuser.py
  9. +7 −0 django/contrib/auth/models.py
  10. +17 −0 django/contrib/auth/tests.py
  11. +57 −0 django/contrib/sessions/backends/base.py
  12. +4 −4 django/contrib/sessions/backends/cache.py
  13. +1 −1  django/contrib/sessions/backends/db.py
  14. +4 −4 django/contrib/sessions/middleware.py
  15. +94 −0 django/contrib/sessions/tests.py
  16. +8 −3 django/core/management/commands/dumpdata.py
  17. +28 −7 django/core/management/commands/loaddata.py
  18. +10 −1 django/core/management/commands/syncdb.py
  19. +1 −1  django/core/management/sql.py
  20. +1 −1  django/core/serializers/base.py
  21. +2 −2 django/db/backends/__init__.py
  22. +9 −4 django/db/models/base.py
  23. +36 −11 django/db/models/fields/related.py
  24. +7 −3 django/db/models/options.py
  25. +7 −1 django/db/models/query.py
  26. +12 −4 django/db/models/sql/query.py
  27. +2 −3 django/db/models/sql/subqueries.py
  28. +1 −1  django/db/models/sql/where.py
  29. +4 −4 django/template/__init__.py
  30. +10 −4 django/test/client.py
  31. +12 −0 django/test/testcases.py
  32. +13 −9 django/utils/text.py
  33. +16 −5 docs/authentication.txt
  34. +83 −21 docs/contributing.txt
  35. +42 −6 docs/db-api.txt
  36. +53 −12 docs/django-admin.txt
  37. +89 −6 docs/faq.txt
  38. +3 −0  docs/outputting_pdf.txt
  39. +35 −0 docs/serialization.txt
  40. +59 −1 docs/sessions.txt
  41. +2 −0  docs/settings.txt
  42. +10 −6 docs/testing.txt
  43. +3 −2 tests/modeltests/basic/models.py
  44. +8 −0 tests/modeltests/many_to_many/models.py
  45. +6 −0 tests/modeltests/many_to_one/models.py
  46. +5 −0 tests/modeltests/model_inheritance/models.py
  47. +1 −4 tests/modeltests/one_to_one/models.py
  48. +3 −2 tests/modeltests/or_lookups/models.py
  49. +18 −0 tests/modeltests/test_client/fixtures/testdata.json
  50. +7 −0 tests/modeltests/update/models.py
  51. +11 −9 tests/regressiontests/defaultfilters/tests.py
  52. +1 −0  tests/regressiontests/fixtures_regress/fixtures/bad_fixture1.unkn
  53. +7 −0 tests/regressiontests/fixtures_regress/fixtures/bad_fixture2.xml
  54. +23 −0 tests/regressiontests/fixtures_regress/models.py
  55. +44 −2 tests/regressiontests/many_to_one_regress/models.py
  56. 0  tests/regressiontests/model_inheritance_regress/__init__.py
  57. +120 −0 tests/regressiontests/model_inheritance_regress/models.py
  58. 0  tests/regressiontests/null_fk/__init__.py
  59. +55 −0 tests/regressiontests/null_fk/models.py
  60. +38 −0 tests/regressiontests/one_to_one_regress/models.py
  61. +9 −2 tests/regressiontests/queries/models.py
  62. +20 −0 tests/regressiontests/serializers_regress/models.py
  63. +42 −8 tests/regressiontests/serializers_regress/tests.py
  64. +36 −0 tests/regressiontests/test_client_regress/fixtures/testdata.json
  65. +29 −0 tests/regressiontests/test_client_regress/models.py
  66. +1 −0  tests/regressiontests/test_client_regress/urls.py
  67. +14 −0 tests/regressiontests/test_client_regress/views.py
  68. +7 −2 tests/runtests.py
View
6 AUTHORS
@@ -57,6 +57,7 @@ answer newbie questions, and generally made Django that much better:
David Ascher <http://ascher.ca/>
Jökull Sólberg Auðunsson <jokullsolberg@gmail.com>
Arthur <avandorp@gmail.com>
+ av0000@mail.ru
David Avsajanishvili <avsd05@gmail.com>
axiak@mit.edu
Niran Babalola <niran@niran.org>
@@ -78,6 +79,7 @@ answer newbie questions, and generally made Django that much better:
brut.alll@gmail.com
btoll@bestweb.net
Jonathan Buchanan <jonathan.buchanan@gmail.com>
+ Keith Bussell <kbussell@gmail.com>
Juan Manuel Caicedo <juan.manuel.caicedo@gmail.com>
Trevor Caira <trevor@caira.com>
Ricardo Javier Cárdenes Medina <ricardo.cardenes@gmail.com>
@@ -142,6 +144,7 @@ answer newbie questions, and generally made Django that much better:
Bill Fenner <fenner@gmail.com>
Stefane Fermgier <sf@fermigier.com>
Afonso Fernández Nogueira <fonzzo.django@gmail.com>
+ J. Pablo Fernandez <pupeno@pupeno.com>
Matthew Flanagan <http://wadofstuff.blogspot.com>
Eric Floehr <eric@intellovations.com>
Vincent Foley <vfoleybourgon@yahoo.ca>
@@ -359,13 +362,14 @@ answer newbie questions, and generally made Django that much better:
Makoto Tsuyuki <mtsuyuki@gmail.com>
tt@gurgle.no
David Tulig <david.tulig@gmail.com>
- Amit Upadhyay
+ Amit Upadhyay <http://www.amitu.com/blog/>
Geert Vanderkelen
I.S. van Oostveen <v.oostveen@idca.nl>
viestards.lists@gmail.com
George Vilches <gav@thataddress.com>
Vlado <vlado@labath.org>
Milton Waddams
+ Chris Wagner <cw264701@ohio.edu>
wam-djangobug@wamber.net
Wang Chun <wangchun@exoweb.net>
Filip Wasilewski <filip.wasilewski@gmail.com>
View
9 django/conf/global_settings.py
@@ -11,9 +11,10 @@
DEBUG = False
TEMPLATE_DEBUG = False
-# True if BaseHandler.get_response() should propagate raw exceptions
-# rather than catching them. This is useful under some testing siutations,
-# and should never be used on a live site.
+
+# Whether the framework should propagate raw exceptions rather than catching
+# them. This is useful under some testing siutations and should never be used
+# on a live site.
DEBUG_PROPAGATE_EXCEPTIONS = False
# Whether to use the "Etag" header. This saves bandwidth but slows down performance.
@@ -289,7 +290,7 @@
SESSION_COOKIE_SECURE = False # Whether the session cookie should be secure (https:// only).
SESSION_COOKIE_PATH = '/' # The path of the session cookie.
SESSION_SAVE_EVERY_REQUEST = False # Whether to save the session data on every request.
-SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user closes his browser.
+SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether a user's session cookie expires when the Web browser is closed.
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # The module to store session data
SESSION_FILE_PATH = None # Directory to store session files if using the file session module. If None, the backend will use a sensible default.
View
BIN  django/conf/locale/es/LC_MESSAGES/django.mo
Binary file not shown
View
359 django/conf/locale/es/LC_MESSAGES/django.po
@@ -5,201 +5,200 @@ msgid ""
msgstr ""
"Project-Id-Version: Django\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-05-26 10:38+0200\n"
+"POT-Creation-Date: 2008-06-13 16:14+0200\n"
"PO-Revision-Date: 2008-03-30 01:04+0100\n"
-"Last-Translator: Django Spanish Group <django-i18n@googlegroups.com>\n"
-"Language-Team: Spanish <django-i18n@googlegroups.com>\n"
+"Last-Translator: Django Spanish Translation Team <django-cat@googlegroups.com>\n"
+"Language-Team: Django Spanish Translation Team <django-cat@googlegroups.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: conf/global_settings.py:43
+#: conf/global_settings.py:44
msgid "Arabic"
msgstr "Árabe"
-#: conf/global_settings.py:44
+#: conf/global_settings.py:45
msgid "Bengali"
msgstr "Bengalí"
-#: conf/global_settings.py:45
+#: conf/global_settings.py:46
msgid "Bulgarian"
msgstr "Búlgaro"
-#: conf/global_settings.py:46
+#: conf/global_settings.py:47
msgid "Catalan"
msgstr "Catalán"
-#: conf/global_settings.py:47
+#: conf/global_settings.py:48
msgid "Czech"
msgstr "Checo"
-#: conf/global_settings.py:48
+#: conf/global_settings.py:49
msgid "Welsh"
msgstr "Galés"
-#: conf/global_settings.py:49
+#: conf/global_settings.py:50
msgid "Danish"
msgstr "Danés"
-#: conf/global_settings.py:50
+#: conf/global_settings.py:51
msgid "German"
msgstr "Alemán"
-#: conf/global_settings.py:51
+#: conf/global_settings.py:52
msgid "Greek"
msgstr "Griego"
-#: conf/global_settings.py:52
+#: conf/global_settings.py:53
msgid "English"
msgstr "Inglés"
-#: conf/global_settings.py:53
+#: conf/global_settings.py:54
msgid "Spanish"
msgstr "Español"
-#: conf/global_settings.py:54
+#: conf/global_settings.py:55
msgid "Argentinean Spanish"
msgstr "Español Argentino"
-#: conf/global_settings.py:55
+#: conf/global_settings.py:56
msgid "Basque"
msgstr "Vasco"
-#: conf/global_settings.py:56
+#: conf/global_settings.py:57
msgid "Persian"
msgstr "Persa"
-#: conf/global_settings.py:57
+#: conf/global_settings.py:58
msgid "Finnish"
msgstr "Finés"
-#: conf/global_settings.py:58
+#: conf/global_settings.py:59
msgid "French"
msgstr "Francés"
-#: conf/global_settings.py:59
+#: conf/global_settings.py:60
msgid "Irish"
msgstr "Irlandés"
-#: conf/global_settings.py:60
+#: conf/global_settings.py:61
msgid "Galician"
msgstr "Gallego"
-#: conf/global_settings.py:61
+#: conf/global_settings.py:62
msgid "Hungarian"
msgstr "Húngaro"
-#: conf/global_settings.py:62
+#: conf/global_settings.py:63
msgid "Hebrew"
msgstr "Hebreo"
-#: conf/global_settings.py:63
+#: conf/global_settings.py:64
msgid "Croatian"
msgstr "Croata"
-#: conf/global_settings.py:64
+#: conf/global_settings.py:65
msgid "Icelandic"
msgstr "Islandés"
-#: conf/global_settings.py:65
+#: conf/global_settings.py:66
msgid "Italian"
msgstr "Italiano"
-#: conf/global_settings.py:66
+#: conf/global_settings.py:67
msgid "Japanese"
msgstr "Japonés"
-#: conf/global_settings.py:67
+#: conf/global_settings.py:68
msgid "Georgian"
msgstr "Georgiano"
-#: conf/global_settings.py:68
+#: conf/global_settings.py:69
msgid "Korean"
msgstr "Koreano"
-#: conf/global_settings.py:69
+#: conf/global_settings.py:70
msgid "Khmer"
msgstr "Khmer"
-#: conf/global_settings.py:70
+#: conf/global_settings.py:71
msgid "Kannada"
msgstr "Kannada"
-#: conf/global_settings.py:71
+#: conf/global_settings.py:72
msgid "Latvian"
msgstr "Latvio"
-#: conf/global_settings.py:72
+#: conf/global_settings.py:73
msgid "Macedonian"
msgstr "Macedonio"
-#: conf/global_settings.py:73
+#: conf/global_settings.py:74
msgid "Dutch"
-msgstr "Alemán"
+msgstr "Holandés"
-#: conf/global_settings.py:74
+#: conf/global_settings.py:75
msgid "Norwegian"
msgstr "Noruego"
-#: conf/global_settings.py:75
+#: conf/global_settings.py:76
msgid "Polish"
msgstr "Polaco"
-#: conf/global_settings.py:76
+#: conf/global_settings.py:77
msgid "Portugese"
msgstr "Portugés"
-#: conf/global_settings.py:77
-#, fuzzy
+#: conf/global_settings.py:78
msgid "Brazilian Portuguese"
-msgstr "Portugés"
+msgstr "Portugés Brasileño"
-#: conf/global_settings.py:78
+#: conf/global_settings.py:79
msgid "Romanian"
msgstr "Rumano"
-#: conf/global_settings.py:79
+#: conf/global_settings.py:80
msgid "Russian"
msgstr "Ruso"
-#: conf/global_settings.py:80
+#: conf/global_settings.py:81
msgid "Slovak"
msgstr "Eslovaco"
-#: conf/global_settings.py:81
+#: conf/global_settings.py:82
msgid "Slovenian"
msgstr "Esloveno"
-#: conf/global_settings.py:82
+#: conf/global_settings.py:83
msgid "Serbian"
msgstr "Serbio"
-#: conf/global_settings.py:83
+#: conf/global_settings.py:84
msgid "Swedish"
msgstr "Sueco"
-#: conf/global_settings.py:84
+#: conf/global_settings.py:85
msgid "Tamil"
msgstr "Tamil"
-#: conf/global_settings.py:85
+#: conf/global_settings.py:86
msgid "Telugu"
msgstr "Telugu"
-#: conf/global_settings.py:86
+#: conf/global_settings.py:87
msgid "Turkish"
msgstr "Turco"
-#: conf/global_settings.py:87
+#: conf/global_settings.py:88
msgid "Ukrainian"
msgstr "Ucraniano"
-#: conf/global_settings.py:88
+#: conf/global_settings.py:89
msgid "Simplified Chinese"
msgstr "Chino simplificado"
-#: conf/global_settings.py:89
+#: conf/global_settings.py:90
msgid "Traditional Chinese"
msgstr "Chino tradicional"
@@ -329,7 +328,7 @@ msgstr ""
#: contrib/admin/templates/admin/base.html:26
msgid "Welcome,"
-msgstr "Bienvenido,"
+msgstr "Bienvenido/a,"
#: contrib/admin/templates/admin/base.html:28
#: contrib/admin/templates/admin_doc/bookmarklets.html:3
@@ -357,7 +356,7 @@ msgstr "Administración de Django"
#: contrib/admin/templates/admin/change_form.html:14
#: contrib/admin/templates/admin/index.html:28
-msgid "Add"
+msgid "Añadir"
msgstr "Agregar"
#: contrib/admin/templates/admin/change_form.html:20
@@ -387,7 +386,7 @@ msgstr "Orden:"
#: contrib/admin/templates/admin/change_list.html:11
#, python-format
msgid "Add %(name)s"
-msgstr "Agregar %(name)s"
+msgstr "Añadir %(name)s"
#: contrib/admin/templates/admin/delete_confirmation.html:8
#: contrib/admin/templates/admin/submit_line.html:3
@@ -463,7 +462,7 @@ msgid ""
"database tables have been created, and make sure the database is readable by "
"the appropriate user."
msgstr ""
-"Algo va mal con la instalación de la base de datos. Asegúrate que las tablas "
+"Algo va mal con la instalación de la base de datos. Asegúrese que las tablas "
"necesarias han sido creadas, y que la base de datos puede ser leída por el "
"usuario apropiado."
@@ -476,12 +475,12 @@ msgstr "Usuario:"
#: contrib/admin/templates/admin/login.html:20
#: contrib/comments/templates/comments/form.html:8
msgid "Password:"
-msgstr "Clave:"
+msgstr "Contraseña:"
#: contrib/admin/templates/admin/login.html:25
#: contrib/admin/views/decorators.py:31
msgid "Log in"
-msgstr "Identificarse"
+msgstr "Iniciar sesión"
#: contrib/admin/templates/admin/object_history.html:17
msgid "Date/time"
@@ -509,11 +508,11 @@ msgstr ""
#: contrib/admin/templates/admin/pagination.html:10
msgid "Show all"
-msgstr "Mostrarlo todo"
+msgstr "Mostrar todo"
#: contrib/admin/templates/admin/search_form.html:8
msgid "Go"
-msgstr "Buscar"
+msgstr "Ir"
#: contrib/admin/templates/admin/search_form.html:10
#, python-format
@@ -568,7 +567,7 @@ msgstr "Contraseña (de nuevo)"
#: contrib/admin/templates/admin/auth/user/add_form.html:24
#: contrib/admin/templates/admin/auth/user/change_password.html:39
msgid "Enter the same password as above, for verification."
-msgstr "Introduzca la misma contraseña que arriba, para verificación"
+msgstr "Introduzca la misma contraseña que arriba, para verificación."
#: contrib/admin/templates/admin/auth/user/change_password.html:27
#, python-format
@@ -599,22 +598,22 @@ msgstr ""
"<p class=\"help\">Para instalar bookmarklets, arrastre el enlace a su barra\n"
"de favoritos, o pulse con el botón derecho el enlace y añádalo a sus "
"favoritos.\n"
-"Ahora puede escoger el bookmarklet desde cualquier página en el sitio.\n"
-"Observer que algunos de estos bookmarklets precisan que esté viendo\n"
-"el sitio desde un computador señalado como \"interno\" (hable\n"
-"con su administrador de sistemas si no está seguro de si el suyo lo es).</"
+"Ahora puede escoger el bookmarklet desde cualquier página del sitio.\n"
+"Observe que algunos de estos bookmarklets precisan que esté viendo\n"
+"el sitio desde un ordenador señalado como \"interno\" (hable\n"
+"con su administrador de sistemas si no está seguro si el suyo lo es).</"
"p>\n"
#: contrib/admin/templates/admin_doc/bookmarklets.html:18
msgid "Documentation for this page"
-msgstr "Documentación de esta página"
+msgstr "Documentación para esta página"
#: contrib/admin/templates/admin_doc/bookmarklets.html:19
msgid ""
"Jumps you from any page to the documentation for the view that generates "
"that page."
msgstr ""
-"Le lleva desde cualquier página a la documentación de la vista que la genera."
+"Lleva desde cualquier página a la documentación de la vista que la genera."
#: contrib/admin/templates/admin_doc/bookmarklets.html:21
msgid "Show object ID"
@@ -625,8 +624,8 @@ msgid ""
"Shows the content-type and unique ID for pages that represent a single "
"object."
msgstr ""
-"Muestra el tipo de contenido e ID unívoco de las páginas que representan un "
-"único objeto."
+"Muestra el tipo de contenido e ID único de las páginas que representan un "
+"simple objeto."
#: contrib/admin/templates/admin_doc/bookmarklets.html:24
msgid "Edit this object (current window)"
@@ -635,7 +634,7 @@ msgstr "Editar este objeto (ventana actual)"
#: contrib/admin/templates/admin_doc/bookmarklets.html:25
msgid "Jumps to the admin page for pages that represent a single object."
msgstr ""
-"Le lleva a la página de administración de páginas que representan un único "
+"Lleva a la página de administración de páginas que representan un único "
"objeto."
#: contrib/admin/templates/admin_doc/bookmarklets.html:27
@@ -649,85 +648,85 @@ msgstr ""
#: contrib/admin/templates/registration/logged_out.html:8
msgid "Thanks for spending some quality time with the Web site today."
-msgstr "Gracias por el tiempo que ha dedicado al sitio web hoy."
+msgstr "Gracias por el tiempo que ha dedicado hoy al sitio web."
#: contrib/admin/templates/registration/logged_out.html:10
msgid "Log in again"
-msgstr "Identificarse de nuevo"
+msgstr "Iniciar sesión de nuevo"
#: 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:5
#: contrib/admin/templates/registration/password_change_form.html:9
msgid "Password change"
-msgstr "Cambio de clave"
+msgstr "Cambio de contraseña"
#: contrib/admin/templates/registration/password_change_done.html:5
#: contrib/admin/templates/registration/password_change_done.html:9
msgid "Password change successful"
-msgstr "Cambio de clave exitoso"
+msgstr "Cambio de contraseña exitoso"
#: contrib/admin/templates/registration/password_change_done.html:11
msgid "Your password was changed."
-msgstr "Su clave ha sido cambiada."
+msgstr "Su contraseña ha sido cambiada."
#: contrib/admin/templates/registration/password_change_form.html:11
msgid ""
"Please enter your old password, for security's sake, and then enter your new "
"password twice so we can verify you typed it in correctly."
msgstr ""
-"Por favor, introduzca su clave antigua, por seguridad, y después introduzca "
-"la nueva clave dos veces para verificar que la ha escrito correctamente."
+"Por favor, introduzca su contraseña antigua, por seguridad, y después introduzca "
+"la nueva contraseña dos veces para verificar que la ha escrito correctamente."
#: contrib/admin/templates/registration/password_change_form.html:16
msgid "Old password:"
-msgstr "Clave antigua:"
+msgstr "Contraseña antigua:"
#: contrib/admin/templates/registration/password_change_form.html:18
msgid "New password:"
-msgstr "Clave nueva:"
+msgstr "Contraseña nueva:"
#: contrib/admin/templates/registration/password_change_form.html:20
msgid "Confirm password:"
-msgstr "Confirme clave:"
+msgstr "Confirme contraseña:"
#: contrib/admin/templates/registration/password_change_form.html:22
msgid "Change my password"
-msgstr "Cambiar mi clave"
+msgstr "Cambiar mi contraseña"
#: contrib/admin/templates/registration/password_reset_done.html:4
#: contrib/admin/templates/registration/password_reset_form.html:4
#: contrib/admin/templates/registration/password_reset_form.html:6
#: contrib/admin/templates/registration/password_reset_form.html:10
msgid "Password reset"
-msgstr "Recuperar clave"
+msgstr "Restablecer contraseña"
#: contrib/admin/templates/registration/password_reset_done.html:6
#: contrib/admin/templates/registration/password_reset_done.html:10
msgid "Password reset successful"
-msgstr "Recuperación de clave exitosa"
+msgstr "Restablecimiento de contraseña exitoso"
#: contrib/admin/templates/registration/password_reset_done.html:12
msgid ""
"We've e-mailed a new password to the e-mail address you submitted. You "
"should be receiving it shortly."
msgstr ""
-"Le hemos enviado una clave nueva a la dirección que ha suministrado. Debería "
+"Le hemos enviado una contraseña nueva a la dirección que ha suministrado. Debería "
"recibirla en breve."
#: contrib/admin/templates/registration/password_reset_email.html:2
msgid "You're receiving this e-mail because you requested a password reset"
-msgstr "Está recibiendo este mensaje debido a que solicitó recuperar la clave"
+msgstr "Está recibiendo este mensaje debido a que solicitó restablecer la contraseña"
#: contrib/admin/templates/registration/password_reset_email.html:3
#, python-format
msgid "for your user account at %(site_name)s"
-msgstr "de su cuenta de usuario en %(site_name)s."
+msgstr "para su cuenta de usuario en %(site_name)s."
#: contrib/admin/templates/registration/password_reset_email.html:5
#, python-format
msgid "Your new password is: %(new_password)s"
-msgstr "Su nueva clave es: %(new_password)s"
+msgstr "Su nueva contraseña es: %(new_password)s"
#: contrib/admin/templates/registration/password_reset_email.html:7
msgid "Feel free to change this password by going to this page:"
@@ -751,7 +750,7 @@ msgid ""
"Forgotten your password? Enter your e-mail address below, and we'll reset "
"your password and e-mail the new one to you."
msgstr ""
-"¿Ha olvidado su clave? Introduzca su dirección de correo electrónico, y "
+"¿Ha olvidado su contraseña? Introduzca su dirección de correo electrónico, y "
"crearemos una nueva que le enviaremos por correo."
#: contrib/admin/templates/registration/password_reset_form.html:16
@@ -760,7 +759,7 @@ msgstr "Dirección de correo electrónico:"
#: contrib/admin/templates/registration/password_reset_form.html:16
msgid "Reset my password"
-msgstr "Recuperar mi clave"
+msgstr "Restablecer mi contraseña"
#: contrib/admin/templates/widget/date_time.html:3
msgid "Date:"
@@ -798,7 +797,7 @@ msgstr "Añadir usuario"
#: contrib/admin/views/auth.py:58
msgid "Password changed successfully."
-msgstr "La clave se ha cambiado exitosamente."
+msgstr "La contraseña se ha cambiado con éxito."
#: contrib/admin/views/auth.py:65
#, python-format
@@ -810,7 +809,7 @@ msgid ""
"Please enter a correct username and password. Note that both fields are case-"
"sensitive."
msgstr ""
-"Por favor, introduzca un correcto nombre de usuario y contraseña. Note que "
+"Por favor, introduzca un nombre de usuario correcto y una contraseña. Note que "
"ambos campos son sensibles a mayúsculas/minúsculas."
#: contrib/admin/views/decorators.py:69
@@ -818,7 +817,7 @@ msgid ""
"Please log in again, because your session has expired. Don't worry: Your "
"submission has been saved."
msgstr ""
-"Por favor, identifíquese de nuevo, porque su sesión ha caducado. No se "
+"Por favor, inicie sesión de nuevo, ya que su sesión ha caducado. No se "
"preocupe: se ha guardado su envío."
#: contrib/admin/views/decorators.py:76
@@ -827,7 +826,7 @@ msgid ""
"cookies, reload this page, and try again."
msgstr ""
"Parece que su navegador no está configurado para aceptar cookies. Actívelas "
-"por favor, recargue esta página, e inténtelo de nuevo."
+", recargue esta página, e inténtelo de nuevo."
#: contrib/admin/views/decorators.py:89
#, python-format
@@ -937,7 +936,7 @@ msgstr "Ruta de fichero"
#: contrib/admin/views/doc.py:303
msgid "Floating point number"
-msgstr "Número decimal"
+msgstr "Número en coma flotante"
#: contrib/admin/views/doc.py:307 contrib/comments/models.py:89
msgid "IP address"
@@ -987,17 +986,17 @@ msgstr "Sitio administrativo"
#: contrib/admin/views/main.py:280 contrib/admin/views/main.py:365
#, python-format
msgid "You may add another %s below."
-msgstr "Puede agregar otro %s abajo."
+msgstr "Puede añadir otro %s abajo."
#: contrib/admin/views/main.py:298
#, python-format
msgid "Add %s"
-msgstr "Agregar %s"
+msgstr "Añadir %s"
#: contrib/admin/views/main.py:344
#, python-format
msgid "Added %s."
-msgstr "Agregado %s."
+msgstr "Añadido %s."
#: contrib/admin/views/main.py:344 contrib/admin/views/main.py:346
#: contrib/admin/views/main.py:348 core/validators.py:283
@@ -1029,7 +1028,7 @@ msgstr "Se modificó con éxito el %(name)s \"%(obj)s\"."
msgid ""
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
msgstr ""
-"Se agregó 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/views/main.py:400
#, python-format
@@ -1087,7 +1086,7 @@ msgid ""
"Your Web browser doesn't appear to have cookies enabled. Cookies are "
"required for logging in."
msgstr ""
-"Tu navegador de internet parece no tener las cookies habilitadas. Las "
+"Su navegador no parece tener las cookies habilitadas. Las "
"cookies se necesitan para poder ingresar."
#: contrib/auth/forms.py:62
@@ -1105,17 +1104,17 @@ msgstr ""
#: contrib/auth/forms.py:107
#, python-format
msgid "Password reset on %s"
-msgstr "Clave restablecida en %s"
+msgstr "Contraseña restablecida en %s"
#: contrib/auth/forms.py:117
msgid "The two 'new password' fields didn't match."
msgstr ""
-"Las contraseñas introducidas en los campos 'nueva contraseña' no coinciden."
+"Los dos campos 'nueva contraseña' no coinciden."
#: contrib/auth/forms.py:124
msgid "Your old password was entered incorrectly. Please enter it again."
msgstr ""
-"Tu contraseña antigua es incorrecta. Por favor, vuelve a introducirla "
+"Tu contraseña antigua es incorrecta. Por favor, vuelva a introducirla "
"correctamente."
#: contrib/auth/models.py:73 contrib/auth/models.py:93
@@ -1138,15 +1137,15 @@ msgstr "permisos"
msgid "group"
msgstr "grupo"
-#: contrib/auth/models.py:98 contrib/auth/models.py:141
+#: contrib/auth/models.py:98 contrib/auth/models.py:148
msgid "groups"
msgstr "grupos"
-#: contrib/auth/models.py:131
+#: contrib/auth/models.py:138
msgid "username"
msgstr "nombre de usuario"
-#: contrib/auth/models.py:131
+#: contrib/auth/models.py:138
msgid ""
"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
"digits and underscores)."
@@ -1154,23 +1153,23 @@ msgstr ""
"Requerido. 30 caracteres o menos. Sólo caracteres alfanuméricos (letras, "
"dígitos y guiones bajos)."
-#: contrib/auth/models.py:132
+#: contrib/auth/models.py:139
msgid "first name"
-msgstr "nombre"
+msgstr "nombre propio"
-#: contrib/auth/models.py:133
+#: contrib/auth/models.py:140
msgid "last name"
msgstr "apellidos"
-#: contrib/auth/models.py:134
+#: contrib/auth/models.py:141
msgid "e-mail address"
-msgstr "dirección de correo"
+msgstr "dirección de correo electrónico"
-#: contrib/auth/models.py:135
+#: contrib/auth/models.py:142
msgid "password"
-msgstr "clave"
+msgstr "contraseña"
-#: contrib/auth/models.py:135
+#: contrib/auth/models.py:142
msgid ""
"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
"password form</a>."
@@ -1178,32 +1177,31 @@ msgstr ""
"Use'[algo]$[sal]$[hash hexadecimal]' o use <a href=\"password/\">el "
"formulario para cambiar la contraseña</a>."
-#: contrib/auth/models.py:136
+#: contrib/auth/models.py:143
msgid "staff status"
msgstr "es staff"
-#: contrib/auth/models.py:136
+#: contrib/auth/models.py:143
msgid "Designates whether the user can log into this admin site."
msgstr "Indica si el usuario puede entrar en este sitio de administración."
-#: contrib/auth/models.py:137
+#: contrib/auth/models.py:144
msgid "active"
msgstr "activo"
-#: contrib/auth/models.py:137
-#, fuzzy
+#: contrib/auth/models.py:144
msgid ""
"Designates whether this user should be treated as active. Unselect this "
"instead of deleting accounts."
msgstr ""
-"Indica si el usuario puede entrar en este sitio de administración. Desmarque "
-"esto en lugar de borrar la cuenta."
+"Indica si el usuario puede ser tratado como activo. Desmarque "
+"esta opción en lugar de borrar la cuenta."
-#: contrib/auth/models.py:138
+#: contrib/auth/models.py:145
msgid "superuser status"
msgstr "es superusuario"
-#: contrib/auth/models.py:138
+#: contrib/auth/models.py:145
msgid ""
"Designates that this user has all permissions without explicitly assigning "
"them."
@@ -1211,15 +1209,15 @@ msgstr ""
"Indica que este usuario tiene todos los permisos sin asignárselos "
"explícitamente."
-#: contrib/auth/models.py:139
+#: contrib/auth/models.py:146
msgid "last login"
-msgstr "Último registro"
+msgstr "Último inicio de sesión"
-#: contrib/auth/models.py:140
+#: contrib/auth/models.py:147
msgid "date joined"
-msgstr "fecha de creación"
+msgstr "fecha de alta"
-#: contrib/auth/models.py:142
+#: contrib/auth/models.py:149
msgid ""
"In addition to the permissions manually assigned, this user will also get "
"all permissions granted to each group he/she is in."
@@ -1227,35 +1225,35 @@ msgstr ""
"Además de los permisos asignados manualmente, este usuario también tendrá "
"todos los permisos de los grupos en los que esté."
-#: contrib/auth/models.py:143
+#: contrib/auth/models.py:150
msgid "user permissions"
-msgstr "permisos"
+msgstr "permisos de usuario"
-#: contrib/auth/models.py:147
+#: contrib/auth/models.py:154
msgid "user"
msgstr "usuario"
-#: contrib/auth/models.py:148
+#: contrib/auth/models.py:155
msgid "users"
msgstr "usuarios"
-#: contrib/auth/models.py:154
+#: contrib/auth/models.py:161
msgid "Personal info"
msgstr "Información personal"
-#: contrib/auth/models.py:155
+#: contrib/auth/models.py:162
msgid "Permissions"
msgstr "Permisos"
-#: contrib/auth/models.py:156
+#: contrib/auth/models.py:163
msgid "Important dates"
msgstr "Fechas importantes"
-#: contrib/auth/models.py:157
+#: contrib/auth/models.py:164
msgid "Groups"
msgstr "Grupos"
-#: contrib/auth/models.py:316
+#: contrib/auth/models.py:323
msgid "message"
msgstr "mensaje"
@@ -1278,39 +1276,39 @@ msgstr "comentario"
#: contrib/comments/models.py:74
msgid "rating #1"
-msgstr "calificación 1"
+msgstr "puntuación 1"
#: contrib/comments/models.py:75
msgid "rating #2"
-msgstr "calificación 2"
+msgstr "puntuación 2"
#: contrib/comments/models.py:76
msgid "rating #3"
-msgstr "calificación 3"
+msgstr "puntuación 3"
#: contrib/comments/models.py:77
msgid "rating #4"
-msgstr "calificación 4"
+msgstr "puntuación 4"
#: contrib/comments/models.py:78
msgid "rating #5"
-msgstr "calificación 5"
+msgstr "puntuación 5"
#: contrib/comments/models.py:79
msgid "rating #6"
-msgstr "calificación 6"
+msgstr "puntuación 6"
#: contrib/comments/models.py:80
msgid "rating #7"
-msgstr "calificación 7"
+msgstr "puntuación 7"
#: contrib/comments/models.py:81
msgid "rating #8"
-msgstr "calificación 8"
+msgstr "puntuación 8"
#: contrib/comments/models.py:86
msgid "is valid rating"
-msgstr "es calificación válida"
+msgstr "puntuación válida"
#: contrib/comments/models.py:87 contrib/comments/models.py:179
msgid "date/time submitted"
@@ -1329,8 +1327,8 @@ msgid ""
"Check this box if the comment is inappropriate. A \"This comment has been "
"removed\" message will be displayed instead."
msgstr ""
-"Marque esta caja si el comentario es inapropiado. En su lugar se mostrará "
-"\"Este comentario ha sido eliminado\"."
+"Marque esta opción si el comentario es inapropiado. En su lugar se mostrará "
+"el mensaje \"Este comentario ha sido eliminado\"."
#: contrib/comments/models.py:96
msgid "comments"
@@ -1426,15 +1424,15 @@ msgstr "Marca de %r"
#: contrib/comments/models.py:300
msgid "deletion date"
-msgstr "fecha de eliminación"
+msgstr "fecha de borrado"
#: contrib/comments/models.py:303
msgid "moderator deletion"
-msgstr "eliminación de moderador"
+msgstr "borrado del moderador"
#: contrib/comments/models.py:304
msgid "moderator deletions"
-msgstr "eliminaciones de moderador"
+msgstr "eliminaciones del moderador"
#: contrib/comments/models.py:308
#, python-format
@@ -1447,7 +1445,7 @@ msgstr "¿Has olvidado tu contraseña?"
#: contrib/comments/templates/comments/form.html:12
msgid "Ratings"
-msgstr "Calificaciones"
+msgstr "Puntuaciones"
#: contrib/comments/templates/comments/form.html:12
#: contrib/comments/templates/comments/form.html:23
@@ -1461,7 +1459,7 @@ msgstr "Opcional"
#: contrib/comments/templates/comments/form.html:23
msgid "Post a photo"
-msgstr "Postea una fotografía"
+msgstr "Publica una fotografía"
#: contrib/comments/templates/comments/form.html:28
#: contrib/comments/templates/comments/freeform.html:5
@@ -1519,7 +1517,7 @@ msgstr ""
#: contrib/comments/views/comments.py:190
#: contrib/comments/views/comments.py:283
msgid "Only POSTs are allowed"
-msgstr "Sólo se admite POST"
+msgstr "Sólo se admiten POSTs"
#: contrib/comments/views/comments.py:194
#: contrib/comments/views/comments.py:287
@@ -1530,7 +1528,7 @@ msgstr "No se proporcionó uno o más de los siguientes campos requeridos"
#: contrib/comments/views/comments.py:289
msgid "Somebody tampered with the comment form (security violation)"
msgstr ""
-"Alguien está jugando con el formulario de comentarios (violación de "
+"Alguien realizó manipulaciones con el formulario de comentarios (violación de "
"seguridad)"
#: contrib/comments/views/comments.py:208
@@ -1557,11 +1555,11 @@ msgstr "ID de comentario no válido"
#: contrib/comments/views/karma.py:27
msgid "No voting for yourself"
-msgstr "No puedes votarte mismo"
+msgstr "No puedes votarte a ti mismo"
#: contrib/contenttypes/models.py:67
msgid "python model class name"
-msgstr "nombre de módulo python"
+msgstr "nombre de la clase modelo de python"
#: contrib/contenttypes/models.py:71
msgid "content type"
@@ -1588,7 +1586,7 @@ msgstr "contenido"
#: contrib/flatpages/models.py:12
msgid "enable comments"
-msgstr "admitir comentarios"
+msgstr "habilitar comentarios"
#: contrib/flatpages/models.py:13
msgid "template name"
@@ -1624,19 +1622,19 @@ msgstr "Opciones avanzadas"
#: contrib/humanize/templatetags/humanize.py:19
msgid "th"
-msgstr "th"
+msgstr "º"
#: contrib/humanize/templatetags/humanize.py:19
msgid "st"
-msgstr "st"
+msgstr "º"
#: contrib/humanize/templatetags/humanize.py:19
msgid "nd"
-msgstr "nd"
+msgstr "º"
#: contrib/humanize/templatetags/humanize.py:19
msgid "rd"
-msgstr "rd"
+msgstr "º"
#: contrib/humanize/templatetags/humanize.py:51
#, python-format
@@ -1649,15 +1647,15 @@ msgstr[1] "%(value).1f millión"
#, python-format
msgid "%(value).1f billion"
msgid_plural "%(value).1f billion"
-msgstr[0] "%(value).1f billión"
-msgstr[1] "%(value).1f billión"
+msgstr[0] "%(value).1f billón"
+msgstr[1] "%(value).1f billón"
#: contrib/humanize/templatetags/humanize.py:57
#, python-format
msgid "%(value).1f trillion"
msgid_plural "%(value).1f trillion"
-msgstr[0] "%(value).1f trillión"
-msgstr[1] "%(value).1f trillión"
+msgstr[0] "%(value).1f trillón"
+msgstr[1] "%(value).1f trillón"
#: contrib/humanize/templatetags/humanize.py:73
msgid "one"
@@ -3507,7 +3505,7 @@ msgid ""
"This should be an absolute path, excluding the domain name. Example: '/"
"events/search/'."
msgstr ""
-"Esta ruta debería ser absoluta, excluyendo el nombre de dominio. Ejeplo: '/"
+"Esta ruta debería ser absoluta, excluyendo el nombre de dominio. Ejemplo: '/"
"events/search/'."
#: contrib/redirects/models.py:9
@@ -3575,7 +3573,7 @@ msgid ""
"This value must contain only letters, numbers, underscores, dashes or "
"slashes."
msgstr ""
-"Este valor debe contener letras, números, guiones bajos o barras solamente."
+"Este valor debe contener sólo letras, números, guiones bajos y barras."
#: core/validators.py:80
msgid "This value must contain only letters, numbers, underscores or hyphens."
@@ -3830,7 +3828,7 @@ msgstr "Este campo no es válido."
#: core/validators.py:536
#, python-format
msgid "Could not retrieve anything from %s."
-msgstr "No pude obtener nada de %s."
+msgstr "No se pudo obtener nada de %s."
#: core/validators.py:539
#, python-format
@@ -3932,25 +3930,25 @@ msgstr "Introduzca un nombre de fichero válido"
#: db/models/fields/__init__.py:981
msgid "This value must be either None, True or False."
-msgstr "Este valor debe ser Verdadero o Falso."
+msgstr "Este valor debe ser Verdadero, Falso o Ninguno."
#: db/models/fields/related.py:94
#, python-format
msgid "Please enter a valid %s."
msgstr "Por favor, introduzca un %s válido."
-#: db/models/fields/related.py:721
+#: db/models/fields/related.py:746
msgid "Separate multiple IDs with commas."
msgstr "Separe múltiples IDs con comas."
-#: db/models/fields/related.py:723
+#: db/models/fields/related.py:748
msgid ""
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgstr ""
"Mantenga presionado \"Control\", o \"Command\" en un Mac, para seleccionar "
-"más de uno."
+"más de una opción."
-#: db/models/fields/related.py:770
+#: db/models/fields/related.py:795
#, python-format
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
msgid_plural ""
@@ -4405,16 +4403,5 @@ msgstr "Se actualizó con éxito el %(verbose_name)s."
#: views/generic/create_update.py:184
#, python-format
msgid "The %(verbose_name)s was deleted."
-msgstr "El %(verbose_name)s ha sido eliminado."
-
-#~ msgid "Brazilian"
-#~ msgstr "Brasileño"
-
-#~ msgid "Gaeilge"
-#~ msgstr "Gaeilge"
+msgstr "El %(verbose_name)s ha sido borrado."
-#~ msgid ""
-#~ "Enter a postcode. A space is required between the two postcode parts."
-#~ msgstr ""
-#~ "Introduzca un código postal. Se necesita un espacio entre las dos partes "
-#~ "del código."
View
94 django/contrib/auth/create_superuser.py
@@ -1,94 +1,8 @@
"""
-Helper function for creating superusers in the authentication system.
-
-If run from the command line, this module lets you create a superuser
-interactively.
+Create a superuser from the command line. Deprecated; use manage.py
+createsuperuser instead.
"""
-from django.core import validators
-from django.contrib.auth.models import User
-import getpass
-import os
-import sys
-import re
-
-RE_VALID_USERNAME = re.compile('\w+$')
-
-def createsuperuser(username=None, email=None, password=None):
- """
- Helper function for creating a superuser from the command line. All
- arguments are optional and will be prompted-for if invalid or not given.
- """
- try:
- import pwd
- except ImportError:
- default_username = ''
- else:
- # Determine the current system user's username, to use as a default.
- default_username = pwd.getpwuid(os.getuid())[0].replace(' ', '').lower()
-
- # Determine whether the default username is taken, so we don't display
- # it as an option.
- if default_username:
- try:
- User.objects.get(username=default_username)
- except User.DoesNotExist:
- pass
- else:
- default_username = ''
-
- try:
- while 1:
- if not username:
- input_msg = 'Username'
- if default_username:
- input_msg += ' (Leave blank to use %r)' % default_username
- username = raw_input(input_msg + ': ')
- if default_username and username == '':
- username = default_username
- if not RE_VALID_USERNAME.match(username):
- sys.stderr.write("Error: That username is invalid. Use only letters, digits and underscores.\n")
- username = None
- continue
- try:
- User.objects.get(username=username)
- except User.DoesNotExist:
- break
- else:
- sys.stderr.write("Error: That username is already taken.\n")
- username = None
- while 1:
- if not email:
- email = raw_input('E-mail address: ')
- try:
- validators.isValidEmail(email, None)
- except validators.ValidationError:
- sys.stderr.write("Error: That e-mail address is invalid.\n")
- email = None
- else:
- break
- while 1:
- if not password:
- password = getpass.getpass()
- password2 = getpass.getpass('Password (again): ')
- if password != password2:
- sys.stderr.write("Error: Your passwords didn't match.\n")
- password = None
- continue
- if password.strip() == '':
- sys.stderr.write("Error: Blank passwords aren't allowed.\n")
- password = None
- continue
- break
- except KeyboardInterrupt:
- sys.stderr.write("\nOperation cancelled.\n")
- sys.exit(1)
- u = User.objects.create_user(username, email, password)
- u.is_staff = True
- u.is_active = True
- u.is_superuser = True
- u.save()
- print "Superuser created successfully."
-
if __name__ == "__main__":
- createsuperuser()
+ from django.core.management import call_command
+ call_command("createsuperuser")
View
10 django/contrib/auth/management.py → django/contrib/auth/management/__init__.py
@@ -32,7 +32,7 @@ def create_permissions(app, created_models, verbosity):
def create_superuser(app, created_models, verbosity, **kwargs):
from django.contrib.auth.models import User
- from django.contrib.auth.create_superuser import createsuperuser as do_create
+ from django.core.management import call_command
if User in created_models and kwargs.get('interactive', True):
msg = "\nYou just installed Django's auth system, which means you don't have " \
"any superusers defined.\nWould you like to create one now? (yes/no): "
@@ -42,8 +42,10 @@ def create_superuser(app, created_models, verbosity, **kwargs):
confirm = raw_input('Please enter either "yes" or "no": ')
continue
if confirm == 'yes':
- do_create()
+ call_command("createsuperuser", interactive=True)
break
-dispatcher.connect(create_permissions, signal=signals.post_syncdb)
-dispatcher.connect(create_superuser, sender=auth_app, signal=signals.post_syncdb)
+if 'create_permissions' not in [i.__name__ for i in dispatcher.getAllReceivers(signal=signals.post_syncdb)]:
+ dispatcher.connect(create_permissions, signal=signals.post_syncdb)
+if 'create_superuser' not in [i.__name__ for i in dispatcher.getAllReceivers(signal=signals.post_syncdb, sender=auth_app)]:
+ dispatcher.connect(create_superuser, sender=auth_app, signal=signals.post_syncdb)
View
0  django/contrib/auth/management/commands/__init__.py
No changes.
View
123 django/contrib/auth/management/commands/createsuperuser.py
@@ -0,0 +1,123 @@
+"""
+Management utility to create superusers.
+"""
+
+import getpass
+import os
+import re
+import sys
+from optparse import make_option
+from django.contrib.auth.models import User, UNUSABLE_PASSWORD
+from django.core import validators
+from django.core.management.base import BaseCommand, CommandError
+
+RE_VALID_USERNAME = re.compile('\w+$')
+
+class Command(BaseCommand):
+ option_list = BaseCommand.option_list + (
+ make_option('--username', dest='username', default=None,
+ help='Specifies the username for the superuser.'),
+ make_option('--email', dest='email', default=None,
+ help='Specifies the email address for the superuser.'),
+ make_option('--noinput', action='store_false', dest='interactive', default=True,
+ help='Tells Django to NOT prompt the user for input of any kind. ' \
+ 'You must use --username and --email with --noinput, and ' \
+ 'superusers created with --noinput will not be able to log in ' \
+ 'until they\'re given a valid password.'),
+ )
+ help = 'Used to create a superuser.'
+
+ def handle(self, *args, **options):
+ username = options.get('username', None)
+ email = options.get('email', None)
+ interactive = options.get('interactive')
+
+ # Do quick and dirty validation if --noinput
+ if not interactive:
+ if not username or not email:
+ raise CommandError("You must use --username and --email with --noinput.")
+ if not RE_VALID_USERNAME.match(username):
+ raise CommandError("Invalid username. Use only letters, digits, and underscores")
+ try:
+ validators.isValidEmail(email, None)
+ except validators.ValidationError:
+ raise CommandError("Invalid email address.")
+
+ password = ''
+
+ # Try to determine the current system user's username to use as a default.
+ try:
+ import pwd
+ except ImportError:
+ default_username = ''
+ else:
+ default_username = pwd.getpwuid(os.getuid())[0].replace(' ', '').lower()
+
+ # Determine whether the default username is taken, so we don't display
+ # it as an option.
+ if default_username:
+ try:
+ User.objects.get(username=default_username)
+ except User.DoesNotExist:
+ pass
+ else:
+ default_username = ''
+
+ # Prompt for username/email/password. Enclose this whole thing in a
+ # try/except to trap for a keyboard interrupt and exit gracefully.
+ if interactive:
+ try:
+
+ # Get a username
+ while 1:
+ if not username:
+ input_msg = 'Username'
+ if default_username:
+ input_msg += ' (Leave blank to use %r)' % default_username
+ username = raw_input(input_msg + ': ')
+ if default_username and username == '':
+ username = default_username
+ if not RE_VALID_USERNAME.match(username):
+ sys.stderr.write("Error: That username is invalid. Use only letters, digits and underscores.\n")
+ username = None
+ continue
+ try:
+ User.objects.get(username=username)
+ except User.DoesNotExist:
+ break
+ else:
+ sys.stderr.write("Error: That username is already taken.\n")
+ username = None
+
+ # Get an email
+ while 1:
+ if not email:
+ email = raw_input('E-mail address: ')
+ try:
+ validators.isValidEmail(email, None)
+ except validators.ValidationError:
+ sys.stderr.write("Error: That e-mail address is invalid.\n")
+ email = None
+ else:
+ break
+
+ # Get a password
+ while 1:
+ if not password:
+ password = getpass.getpass()
+ password2 = getpass.getpass('Password (again): ')
+ if password != password2:
+ sys.stderr.write("Error: Your passwords didn't match.\n")
+ password = None
+ continue
+ if password.strip() == '':
+ sys.stderr.write("Error: Blank passwords aren't allowed.\n")
+ password = None
+ continue
+ break
+ except KeyboardInterrupt:
+ sys.stderr.write("\nOperation cancelled.\n")
+ sys.exit(1)
+
+ User.objects.create_superuser(username, email, password)
+ print "Superuser created successfully."
View
7 django/contrib/auth/models.py
@@ -116,6 +116,13 @@ def create_user(self, username, email, password=None):
user.save()
return user
+ def create_superuser(self, username, email, password):
+ u = self.create_user(username, email, password)
+ u.is_staff = True
+ u.is_active = True
+ u.is_superuser = True
+ u.save()
+
def make_random_password(self, length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'):
"Generates a random password with the given length and given allowed_chars"
# Note that default value of allowed_chars does not have "I" or letters
View
17 django/contrib/auth/tests.py
@@ -35,4 +35,21 @@
[]
>>> a.user_permissions.all()
[]
+
+#
+# Tests for createsuperuser management command.
+# It's nearly impossible to test the interactive mode -- a command test helper
+# would be needed (and *awesome*) -- so just test the non-interactive mode.
+# This covers most of the important validation, but not all.
+#
+>>> from django.core.management import call_command
+
+>>> call_command("createsuperuser", noinput=True, username="joe", email="joe@somewhere.org")
+Superuser created successfully.
+
+>>> u = User.objects.get(username="joe")
+>>> u.email
+u'joe@somewhere.org'
+>>> u.password
+u'!'
"""
View
57 django/contrib/sessions/backends/base.py
@@ -4,6 +4,7 @@
import random
import sys
import time
+from datetime import datetime, timedelta
from django.conf import settings
from django.core.exceptions import SuspiciousOperation
@@ -128,6 +129,62 @@ def _get_session(self):
_session = property(_get_session)
+ def get_expiry_age(self):
+ """Get the number of seconds until the session expires."""
+ expiry = self.get('_session_expiry')
+ if not expiry: # Checks both None and 0 cases
+ return settings.SESSION_COOKIE_AGE
+ if not isinstance(expiry, datetime):
+ return expiry
+ delta = expiry - datetime.now()
+ return delta.days * 86400 + delta.seconds
+
+ def get_expiry_date(self):
+ """Get session the expiry date (as a datetime object)."""
+ expiry = self.get('_session_expiry')
+ if isinstance(expiry, datetime):
+ return expiry
+ if not expiry: # Checks both None and 0 cases
+ expiry = settings.SESSION_COOKIE_AGE
+ return datetime.now() + timedelta(seconds=expiry)
+
+ def set_expiry(self, value):
+ """
+ Sets a custom expiration for the session. ``value`` can be an integer, a
+ Python ``datetime`` or ``timedelta`` object or ``None``.
+
+ If ``value`` is an integer, the session will expire after that many
+ seconds of inactivity. If set to ``0`` then the session will expire on
+ browser close.
+
+ If ``value`` is a ``datetime`` or ``timedelta`` object, the session
+ will expire at that specific future time.
+
+ If ``value`` is ``None``, the session uses the global session expiry
+ policy.
+ """
+ if value is None:
+ # Remove any custom expiration for this session.
+ try:
+ del self['_session_expiry']
+ except KeyError:
+ pass
+ return
+ if isinstance(value, timedelta):
+ value = datetime.now() + value
+ self['_session_expiry'] = value
+
+ def get_expire_at_browser_close(self):
+ """
+ Returns ``True`` if the session is set to expire when the browser
+ closes, and ``False`` if there's an expiry date. Use
+ ``get_expiry_date()`` or ``get_expiry_age()`` to find the actual expiry
+ date/age, if there is one.
+ """
+ if self.get('_session_expiry') is None:
+ return settings.SESSION_EXPIRE_AT_BROWSER_CLOSE
+ return self.get('_session_expiry') == 0
+
# Methods that child classes must implement.
def exists(self, session_key):
View
8 django/contrib/sessions/backends/cache.py
@@ -4,23 +4,23 @@
class SessionStore(SessionBase):
"""
- A cache-based session store.
+ A cache-based session store.
"""
def __init__(self, session_key=None):
self._cache = cache
super(SessionStore, self).__init__(session_key)
-
+
def load(self):
session_data = self._cache.get(self.session_key)
return session_data or {}
def save(self):
- self._cache.set(self.session_key, self._session, settings.SESSION_COOKIE_AGE)
+ self._cache.set(self.session_key, self._session, self.get_expiry_age())
def exists(self, session_key):
if self._cache.get(session_key):
return True
return False
-
+
def delete(self, session_key):
self._cache.delete(session_key)
View
2  django/contrib/sessions/backends/db.py
@@ -41,7 +41,7 @@ def save(self):
Session.objects.create(
session_key = self.session_key,
session_data = self.encode(self._session),
- expire_date = datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE)
+ expire_date = self.get_expiry_date()
)
def delete(self, session_key):
View
8 django/contrib/sessions/middleware.py
@@ -26,14 +26,14 @@ def process_response(self, request, response):
if accessed:
patch_vary_headers(response, ('Cookie',))
if modified or settings.SESSION_SAVE_EVERY_REQUEST:
- if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE:
+ if request.session.get_expire_at_browser_close():
max_age = None
expires = None
else:
- max_age = settings.SESSION_COOKIE_AGE
- expires_time = time.time() + settings.SESSION_COOKIE_AGE
+ max_age = request.session.get_expiry_age()
+ expires_time = time.time() + max_age
expires = cookie_date(expires_time)
- # Save the seesion data and refresh the client cookie.
+ # Save the session data and refresh the client cookie.
request.session.save()
response.set_cookie(settings.SESSION_COOKIE_NAME,
request.session.session_key, max_age=max_age,
View
94 django/contrib/sessions/tests.py
@@ -88,6 +88,100 @@
>>> s.pop('some key', 'does not exist')
'does not exist'
+
+#########################
+# Custom session expiry #
+#########################
+
+>>> from django.conf import settings
+>>> from datetime import datetime, timedelta
+
+>>> td10 = timedelta(seconds=10)
+
+# A normal session has a max age equal to settings
+>>> s.get_expiry_age() == settings.SESSION_COOKIE_AGE
+True
+
+# So does a custom session with an idle expiration time of 0 (but it'll expire
+# at browser close)
+>>> s.set_expiry(0)
+>>> s.get_expiry_age() == settings.SESSION_COOKIE_AGE
+True
+
+# Custom session idle expiration time
+>>> s.set_expiry(10)
+>>> delta = s.get_expiry_date() - datetime.now()
+>>> delta.seconds in (9, 10)
+True
+>>> age = s.get_expiry_age()
+>>> age in (9, 10)
+True
+
+# Custom session fixed expiry date (timedelta)
+>>> s.set_expiry(td10)
+>>> delta = s.get_expiry_date() - datetime.now()
+>>> delta.seconds in (9, 10)
+True
+>>> age = s.get_expiry_age()
+>>> age in (9, 10)
+True
+
+# Custom session fixed expiry date (fixed datetime)
+>>> s.set_expiry(datetime.now() + td10)
+>>> delta = s.get_expiry_date() - datetime.now()
+>>> delta.seconds in (9, 10)
+True
+>>> age = s.get_expiry_age()
+>>> age in (9, 10)
+True
+
+# Set back to default session age
+>>> s.set_expiry(None)
+>>> s.get_expiry_age() == settings.SESSION_COOKIE_AGE
+True
+
+# Allow to set back to default session age even if no alternate has been set
+>>> s.set_expiry(None)
+
+
+# We're changing the setting then reverting back to the original setting at the
+# end of these tests.
+>>> original_expire_at_browser_close = settings.SESSION_EXPIRE_AT_BROWSER_CLOSE
+>>> settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = False
+
+# Custom session age
+>>> s.set_expiry(10)
+>>> s.get_expire_at_browser_close()
+False
+
+# Custom expire-at-browser-close
+>>> s.set_expiry(0)
+>>> s.get_expire_at_browser_close()
+True
+
+# Default session age
+>>> s.set_expiry(None)
+>>> s.get_expire_at_browser_close()
+False
+
+>>> settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = True
+
+# Custom session age
+>>> s.set_expiry(10)
+>>> s.get_expire_at_browser_close()
+False
+
+# Custom expire-at-browser-close
+>>> s.set_expiry(0)
+>>> s.get_expire_at_browser_close()
+True
+
+# Default session age
+>>> s.set_expiry(None)
+>>> s.get_expire_at_browser_close()
+True
+
+>>> settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = original_expire_at_browser_close
"""
if __name__ == '__main__':
View
11 django/core/management/commands/dumpdata.py
@@ -9,6 +9,8 @@ class Command(BaseCommand):
help='Specifies the output serialization format for fixtures.'),
make_option('--indent', default=None, dest='indent', type='int',
help='Specifies the indent level to use when pretty-printing output'),
+ make_option('-e', '--exclude', dest='exclude',action='append', default=[],
+ help='App to exclude (use multiple --exclude to exclude multiple apps).'),
)
help = 'Output the contents of the database as a fixture of the given format.'
args = '[appname ...]'
@@ -16,12 +18,15 @@ class Command(BaseCommand):
def handle(self, *app_labels, **options):
from django.db.models import get_app, get_apps, get_models
- format = options.get('format', 'json')
- indent = options.get('indent', None)
+ format = options.get('format','json')
+ indent = options.get('indent',None)
+ exclude = options.get('exclude',[])
show_traceback = options.get('traceback', False)
+ excluded_apps = [get_app(app_label) for app_label in exclude]
+
if len(app_labels) == 0:
- app_list = get_apps()
+ app_list = [app for app in get_apps() if app not in excluded_apps]
else:
app_list = [get_app(app_label) for app_label in app_labels]
View
35 django/core/management/commands/loaddata.py
@@ -32,6 +32,7 @@ def handle(self, *fixture_labels, **options):
# Keep a count of the installed objects and fixtures
fixture_count = 0
object_count = 0
+ objects_per_fixture = []
models = set()
humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path'
@@ -60,11 +61,16 @@ def handle(self, *fixture_labels, **options):
else:
formats = []
- if verbosity >= 2:
- if formats:
+ if formats:
+ if verbosity > 1:
print "Loading '%s' fixtures..." % fixture_name
- else:
- print "Skipping fixture '%s': %s is not a known serialization format" % (fixture_name, format)
+ else:
+ sys.stderr.write(
+ self.style.ERROR("Problem installing fixture '%s': %s is not a known serialization format." %
+ (fixture_name, format)))
+ transaction.rollback()
+ transaction.leave_transaction_management()
+ return
if os.path.isabs(fixture_name):
fixture_dirs = [fixture_name]
@@ -93,6 +99,7 @@ def handle(self, *fixture_labels, **options):
return
else:
fixture_count += 1
+ objects_per_fixture.append(0)
if verbosity > 0:
print "Installing %s fixture '%s' from %s." % \
(format, fixture_name, humanize(fixture_dir))
@@ -100,6 +107,7 @@ def handle(self, *fixture_labels, **options):
objects = serializers.deserialize(format, fixture)
for obj in objects:
object_count += 1
+ objects_per_fixture[-1] += 1
models.add(obj.object.__class__)
obj.save()
label_found = True
@@ -117,10 +125,23 @@ def handle(self, *fixture_labels, **options):
return
fixture.close()
except:
- if verbosity >= 2:
+ if verbosity > 1:
print "No %s fixture '%s' in %s." % \
(format, fixture_name, humanize(fixture_dir))
+
+ # If any of the fixtures we loaded contain 0 objects, assume that an
+ # error was encountered during fixture loading.
+ if 0 in objects_per_fixture:
+ sys.stderr.write(
+ self.style.ERROR("No fixture data found for '%s'. (File format may be invalid.)" %
+ (fixture_name)))
+ transaction.rollback()
+ transaction.leave_transaction_management()
+ return
+
+ # If we found even one object in a fixture, we need to reset the
+ # database sequences.
if object_count > 0:
sequence_sql = connection.ops.sequence_reset_sql(self.style, models)
if sequence_sql:
@@ -128,12 +149,12 @@ def handle(self, *fixture_labels, **options):
print "Resetting sequences"
for line in sequence_sql:
cursor.execute(line)
-
+
transaction.commit()
transaction.leave_transaction_management()
if object_count == 0:
- if verbosity >= 2:
+ if verbosity > 1:
print "No fixtures found."
else:
if verbosity > 0:
View
11 django/core/management/commands/syncdb.py
@@ -34,7 +34,16 @@ def handle_noargs(self, **options):
try:
__import__(app_name + '.management', {}, {}, [''])
except ImportError, exc:
- if not exc.args[0].startswith('No module named management'):
+ # This is slightly hackish. We want to ignore ImportErrors
+ # if the "management" module itself is missing -- but we don't
+ # want to ignore the exception if the management module exists
+ # but raises an ImportError for some reason. The only way we
+ # can do this is to check the text of the exception. Note that
+ # we're a bit broad in how we check the text, because different
+ # Python implementations may not use the same text. CPython
+ # uses the text "No module named management".
+ msg = exc.args[0]
+ if not msg.startswith('No module named management') or 'management' not in msg:
raise
cursor = connection.cursor()
View
2  django/core/management/sql.py
@@ -454,7 +454,7 @@ def custom_sql_for_model(model, style):
fp = open(sql_file, 'U')
for statement in statements.split(fp.read().decode(settings.FILE_CHARSET)):
# Remove any comments from the file
- statement = re.sub(ur"--.*[\n\Z]", "", statement)
+ statement = re.sub(ur"--.*([\n\Z]|$)", "", statement)
if statement.strip():
output.append(statement + u";")
fp.close()
View
2  django/core/serializers/base.py
@@ -38,7 +38,7 @@ def serialize(self, queryset, **options):
self.start_serialization()
for obj in queryset:
self.start_object(obj)
- for field in obj._meta.fields:
+ for field in obj._meta.local_fields:
if field.serialize:
if field.rel is None:
if self.selected_fields is None or field.attname in self.selected_fields:
View
4 django/db/backends/__init__.py
@@ -202,8 +202,8 @@ def pk_default_value(self):
def query_class(self, DefaultQueryClass):
"""
- Given the default QuerySet class, returns a custom QuerySet class
- to use for this backend. Returns None if a custom QuerySet isn't used.
+ Given the default Query class, returns a custom Query class
+ to use for this backend. Returns None if a custom Query isn't used.
See also BaseDatabaseFeatures.uses_custom_query_class, which regulates
whether this method is called at all.
"""
View
13 django/db/models/base.py
@@ -290,12 +290,17 @@ def save_base(self, raw=False, cls=None):
meta = cls._meta
signal = False
- for parent, field in meta.parents.items():
- self.save_base(raw, parent)
- setattr(self, field.attname, self._get_pk_val(parent._meta))
+ # If we are in a raw save, save the object exactly as presented.
+ # That means that we don't try to be smart about saving attributes
+ # that might have come from the parent class - we just save the
+ # attributes we have been given to the class we have been given.
+ if not raw:
+ for parent, field in meta.parents.items():
+ self.save_base(raw, parent)
+ setattr(self, field.attname, self._get_pk_val(parent._meta))
non_pks = [f for f in meta.local_fields if not f.primary_key]
-
+
# First, try an UPDATE. If that doesn't update anything, do an INSERT.
pk_val = self._get_pk_val(meta)
# Note: the comparison with '' is required for compatibility with
View
47 django/db/models/fields/related.py
@@ -182,14 +182,29 @@ def __get__(self, instance, instance_type=None):
def __set__(self, instance, value):
if instance is None:
raise AttributeError, "%s must be accessed via instance" % self.related.opts.object_name
+
+ # The similarity of the code below to the code in
+ # ReverseSingleRelatedObjectDescriptor is annoying, but there's a bunch
+ # of small differences that would make a common base class convoluted.
+
+ # If null=True, we can assign null here, but otherwise the value needs
+ # to be an instance of the related class.
+ if value is None and self.related.field.null == False:
+ raise ValueError('Cannot assign None: "%s.%s" does not allow null values.' %
+ (instance._meta.object_name, self.related.get_accessor_name()))
+ elif value is not None and not isinstance(value, self.related.model):
+ raise ValueError('Cannot assign "%r": "%s.%s" must be a "%s" instance.' %
+ (value, instance._meta.object_name,
+ self.related.get_accessor_name(), self.related.opts.object_name))
+
# Set the value of the related field
setattr(value, self.related.field.rel.get_related_field().attname, instance)
- # Clear the cache, if it exists
- try:
- delattr(value, self.related.field.get_cache_name())
- except AttributeError:
- pass
+ # Since we already know what the related object is, seed the related
+ # object caches now, too. This avoids another db hit if you get the
+ # object you just set.
+ setattr(instance, self.cache_name, value)
+ setattr(value, self.related.field.get_cache_name(), instance)
class ReverseSingleRelatedObjectDescriptor(object):
# This class provides the functionality that makes the related-object
@@ -225,6 +240,17 @@ def __get__(self, instance, instance_type=None):
def __set__(self, instance, value):
if instance is None:
raise AttributeError, "%s must be accessed via instance" % self._field.name
+
+ # If null=True, we can assign null here, but otherwise the value needs
+ # to be an instance of the related class.
+ if value is None and self.field.null == False:
+ raise ValueError('Cannot assign None: "%s.%s" does not allow null values.' %
+ (instance._meta.object_name, self.field.name))
+ elif value is not None and not isinstance(value, self.field.rel.to):
+ raise ValueError('Cannot assign "%r": "%s.%s" must be a "%s" instance.' %
+ (value, instance._meta.object_name,
+ self.field.name, self.field.rel.to._meta.object_name))
+
# Set the value of the related field
try:
val = getattr(value, self.field.rel.get_related_field().attname)
@@ -232,11 +258,10 @@ def __set__(self, instance, value):
val = None
setattr(instance, self.field.attname, val)
- # Clear the cache, if it exists
- try:
- delattr(instance, self.field.get_cache_name())
- except AttributeError:
- pass
+ # Since we already know what the related object is, seed the related
+ # object cache now, too. This avoids another db hit if you get the
+ # object you just set.
+ setattr(instance, self.field.get_cache_name(), value)
class ForeignRelatedObjectsDescriptor(object):
# This class provides the functionality that makes the related-object
@@ -326,7 +351,7 @@ def __init__(self, model=None, core_filters=None, instance=None, symmetrical=Non
self.target_col_name = target_col_name
self._pk_val = self.instance._get_pk_val()
if self._pk_val is None:
- raise ValueError("%r instance needs to have a primary key value before a many-to-many relationship can be used." % model)
+ raise ValueError("%r instance needs to have a primary key value before a many-to-many relationship can be used." % instance.__class__.__name__)
def get_query_set(self):
return superclass.get_query_set(self).filter(**(self.core_filters))
View
10 django/db/models/options.py
@@ -56,8 +56,12 @@ def contribute_to_class(self, cls, name):
# Next, apply any overridden values from 'class Meta'.
if self.meta:
meta_attrs = self.meta.__dict__.copy()
- del meta_attrs['__module__']
- del meta_attrs['__doc__']
+ for name in self.meta.__dict__:
+ # Ignore any private attributes that Django doesn't care about.
+ # NOTE: We can't modify a dictionary's contents while looping
+ # over it, so we loop over the *original* dictionary instead.
+ if name.startswith('_'):
+ del meta_attrs[name]
for attr_name in DEFAULT_NAMES:
if attr_name in meta_attrs:
setattr(self, attr_name, meta_attrs.pop(attr_name))
@@ -98,7 +102,7 @@ def _prepare(self, model):
# field.
field = self.parents.value_for_index(0)
field.primary_key = True
- self.pk = field
+ self.setup_pk(field)
else:
auto = AutoField(verbose_name='ID', primary_key=True,
auto_created=True)
View
8 django/db/models/query.py
@@ -292,6 +292,8 @@ def update(self, **kwargs):
Updates all elements in the current QuerySet, setting all the given
fields to the appropriate values.
"""
+ assert self.query.can_filter(), \
+ "Cannot update a query once a slice has been taken."
query = self.query.clone(sql.UpdateQuery)
query.add_update_values(kwargs)
query.execute_sql(None)
@@ -306,6 +308,8 @@ def _update(self, values):
code (it requires too much poking around at model internals to be
useful at that level).
"""
+ assert self.query.can_filter(), \
+ "Cannot update a query once a slice has been taken."
query = self.query.clone(sql.UpdateQuery)
query.add_update_fields(values)
query.execute_sql(None)
@@ -509,7 +513,9 @@ def __init__(self, *args, **kwargs):
# names of the model fields to select.
def iterator(self):
- self.query.trim_extra_select(self.extra_names)
+ if (not self.extra_names and
+ len(self.field_names) != len(self.model._meta.fields)):
+ self.query.trim_extra_select(self.extra_names)
names = self.query.extra_select.keys() + self.field_names
for row in self.query.results_iter():
yield dict(zip(names, row))
View
16 django/db/models/sql/query.py
@@ -851,7 +851,7 @@ def join(self, connection, always_create=False, exclusions=(),
return alias
def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
- used=None, requested=None, restricted=None):
+ used=None, requested=None, restricted=None, nullable=None):
"""
Fill in the information needed for a select_related query. The current
depth is measured as the number of connections away from the root model<