summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Pellerin <jpellerin@gmail.com>2006-06-28 17:00:52 +0000
committerJason Pellerin <jpellerin@gmail.com>2006-06-28 17:00:52 +0000
commit54b6e969571576e9ec616df8b074f744009b35cc (patch)
treed7b65888ad5ddfd473e734a09132eb5dfd784f46
parent11848506657d82fd57560301eb0432a339e4844d (diff)
Merge trunk to [3216]
git-svn-id: http://code.djangoproject.com/svn/django/branches/multiple-db-support@3227 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/conf/locale/es_AR/LC_MESSAGES/django.mobin32307 -> 33953 bytes
-rw-r--r--django/conf/locale/es_AR/LC_MESSAGES/django.po359
-rw-r--r--django/conf/locale/es_AR/LC_MESSAGES/djangojs.mobin1474 -> 1566 bytes
-rw-r--r--django/conf/locale/es_AR/LC_MESSAGES/djangojs.po43
-rw-r--r--django/conf/locale/zh_CN/LC_MESSAGES/djangojs.po107
-rw-r--r--django/contrib/admin/views/doc.py16
-rw-r--r--django/contrib/comments/templates/comments/form.html8
-rw-r--r--django/contrib/comments/templates/comments/freeform.html4
-rw-r--r--django/contrib/syndication/feeds.py16
-rw-r--r--django/core/management.py52
-rw-r--r--django/db/models/base.py8
-rw-r--r--django/db/models/loading.py31
-rw-r--r--django/db/models/options.py5
-rw-r--r--docs/faq.txt14
-rw-r--r--docs/fastcgi.txt146
-rw-r--r--docs/modpython.txt6
-rw-r--r--docs/syndication_feeds.txt14
-rw-r--r--docs/templates_python.txt4
-rw-r--r--tests/modeltests/invalid_models/models.py118
-rw-r--r--tests/modeltests/m2m_recursive/models.py2
20 files changed, 654 insertions, 299 deletions
diff --git a/django/conf/locale/es_AR/LC_MESSAGES/django.mo b/django/conf/locale/es_AR/LC_MESSAGES/django.mo
index 463078025c..f550fca3db 100644
--- a/django/conf/locale/es_AR/LC_MESSAGES/django.mo
+++ b/django/conf/locale/es_AR/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/es_AR/LC_MESSAGES/django.po b/django/conf/locale/es_AR/LC_MESSAGES/django.po
index 8fbe5cb952..8af7c42e5e 100644
--- a/django/conf/locale/es_AR/LC_MESSAGES/django.po
+++ b/django/conf/locale/es_AR/LC_MESSAGES/django.po
@@ -8,10 +8,10 @@ msgid ""
msgstr ""
"Project-Id-Version: django\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2006-05-16 09:26-0300\n"
+"POT-Creation-Date: 2006-06-19 11:19-0300\n"
"PO-Revision-Date: 2006-05-16 10:05-0300\n"
"Last-Translator: Ramiro Morales <rm0@gmx.net>\n"
-"Language-Team: Spanish <en@li.org>\n"
+"Language-Team: Spanish <es@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-1\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -29,6 +29,10 @@ msgstr "tipo de contenido"
msgid "content types"
msgstr "tipos de contenido"
+#: contrib/auth/views.py:39
+msgid "Logged out"
+msgstr "Sesión cerrada"
+
#: contrib/auth/models.py:13 contrib/auth/models.py:26
msgid "name"
msgstr "nombre"
@@ -63,7 +67,7 @@ msgstr "nombre"
#: contrib/auth/models.py:57
msgid "last name"
-msgstr "apellido(s)"
+msgstr "apellido"
#: contrib/auth/models.py:58
msgid "e-mail address"
@@ -83,7 +87,7 @@ msgstr "es staff"
#: contrib/auth/models.py:60
msgid "Designates whether the user can log into this admin site."
-msgstr "Indica si el usuario puede entrar en este sitio de administración."
+msgstr "Indica si el usuario puede ingresar a este sitio de administración."
#: contrib/auth/models.py:61
msgid "active"
@@ -149,7 +153,7 @@ msgstr ""
"Su navegador Web aparenta no tener cookies activas. Las cookies son un "
"requerimiento para poder ingresar."
-#: contrib/auth/forms.py:36 contrib/auth/forms.py:41
+#: contrib/auth/forms.py:36 contrib/auth/forms.py:43
#: contrib/admin/views/decorators.py:9
msgid ""
"Please enter a correct username and password. Note that both fields are case-"
@@ -158,6 +162,10 @@ msgstr ""
"Por favor ingrese un nombre de usuario y una contraseña correctos. Note que "
"ambos campos son sensibles a mayúsculas/minúsculas."
+#: contrib/auth/forms.py:45
+msgid "This account is inactive."
+msgstr "Esta cuenta está inactiva"
+
#: contrib/redirects/models.py:7
msgid "redirect from"
msgstr "redirigir desde"
@@ -182,11 +190,11 @@ msgstr ""
"Esto puede ser bien una ruta absoluta (como antes) o una URL completa que "
"empiece con 'http://'."
-#: contrib/redirects/models.py:12
+#: contrib/redirects/models.py:13
msgid "redirect"
msgstr "redirección"
-#: contrib/redirects/models.py:13
+#: contrib/redirects/models.py:14
msgid "redirects"
msgstr "redirecciones"
@@ -247,7 +255,7 @@ msgstr "fecha/hora de envío"
msgid "is public"
msgstr "es público"
-#: contrib/comments/models.py:85 contrib/admin/views/doc.py:289
+#: contrib/comments/models.py:85 contrib/admin/views/doc.py:292
msgid "IP address"
msgstr "Dirección IP"
@@ -413,17 +421,20 @@ msgstr[1] ""
"%(text)s"
#: contrib/comments/views/comments.py:117
-#, python-format
+#, fuzzy, python-format
msgid ""
"This comment was posted by a sketchy user:\n"
"\n"
"%(text)s"
msgstr ""
+"Este comentario ha sido enviado por un usuario 'sketcky':\n"
+"\n"
+"%(text)s"
#: contrib/comments/views/comments.py:189
#: contrib/comments/views/comments.py:280
msgid "Only POSTs are allowed"
-msgstr "Sólo se admite POST"
+msgstr "Sólo se admiten POSTs"
#: contrib/comments/views/comments.py:193
#: contrib/comments/views/comments.py:284
@@ -484,7 +495,7 @@ msgstr "Olvidó su contraseña?"
#: contrib/admin/templates/admin/object_history.html:3
#: contrib/admin/templates/admin/change_list.html:5
#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/admin/base.html:23
+#: contrib/admin/templates/admin/base.html:24
#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/registration/password_change_done.html:3
#: contrib/admin/templates/registration/password_change_form.html:3
@@ -499,7 +510,7 @@ msgstr "Olvidó su contraseña?"
#: contrib/admin/templates/admin_doc/index.html:4
#: contrib/admin/templates/admin_doc/model_index.html:5
msgid "Log out"
-msgstr "Terminar sesión"
+msgstr "Cerrar sesión"
#: contrib/comments/templates/comments/form.html:12
msgid "Ratings"
@@ -519,7 +530,7 @@ msgstr "Opcional"
msgid "Post a photo"
msgstr "Enviar una foto"
-#: contrib/flatpages/models.py:7 contrib/admin/views/doc.py:300
+#: contrib/flatpages/models.py:7 contrib/admin/views/doc.py:303
msgid "URL"
msgstr "URL"
@@ -596,7 +607,7 @@ msgstr "nombre de dominio"
#: contrib/sites/models.py:11
msgid "display name"
-msgstr "nombre para mostrar"
+msgstr "nombre para visualizar"
#: contrib/sites/models.py:15
msgid "site"
@@ -616,9 +627,9 @@ msgstr ""
"<ul>\n"
#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88
-#: contrib/admin/filterspecs.py:143
+#: contrib/admin/filterspecs.py:143 contrib/admin/filterspecs.py:169
msgid "All"
-msgstr "Todo"
+msgstr "Todos/as"
#: contrib/admin/filterspecs.py:109
msgid "Any date"
@@ -680,7 +691,7 @@ msgstr "entrada de registro"
msgid "log entries"
msgstr "entradas de registro"
-#: contrib/admin/templatetags/admin_list.py:228
+#: contrib/admin/templatetags/admin_list.py:230
msgid "All dates"
msgstr "Todas las fechas"
@@ -752,12 +763,12 @@ msgstr "y"
#: contrib/admin/views/main.py:338
#, python-format
msgid "Changed %s."
-msgstr "Modificado %s."
+msgstr "Modifica %s."
#: contrib/admin/views/main.py:340
#, python-format
msgid "Deleted %s."
-msgstr "Eliminado %s."
+msgstr "Elimina %s."
#: contrib/admin/views/main.py:343
msgid "No fields changed."
@@ -802,82 +813,87 @@ msgstr "¿Está seguro?"
#: contrib/admin/views/main.py:533
#, python-format
msgid "Change history: %s"
-msgstr "Modificar histórico: %s"
+msgstr "Historia de modificaciones: %s"
-#: contrib/admin/views/main.py:565
+#: contrib/admin/views/main.py:567
#, python-format
msgid "Select %s"
msgstr "Seleccione %s"
-#: contrib/admin/views/main.py:565
+#: contrib/admin/views/main.py:567
#, python-format
msgid "Select %s to change"
-msgstr "Seleccione %s para modificar"
+msgstr "Seleccione %s a modificar"
+
+#: contrib/admin/views/main.py:743
+msgid "Database error"
+msgstr "Error de base de datos"
-#: contrib/admin/views/doc.py:277 contrib/admin/views/doc.py:286
-#: contrib/admin/views/doc.py:288 contrib/admin/views/doc.py:294
-#: contrib/admin/views/doc.py:295 contrib/admin/views/doc.py:297
+#: contrib/admin/views/doc.py:279 contrib/admin/views/doc.py:289
+#: contrib/admin/views/doc.py:291 contrib/admin/views/doc.py:297
+#: contrib/admin/views/doc.py:298 contrib/admin/views/doc.py:300
msgid "Integer"
msgstr "Entero"
-#: contrib/admin/views/doc.py:278
+#: contrib/admin/views/doc.py:280
msgid "Boolean (Either True or False)"
msgstr "Booleano (Verdadero o Falso)"
-#: contrib/admin/views/doc.py:279 contrib/admin/views/doc.py:296
+#: contrib/admin/views/doc.py:281 contrib/admin/views/doc.py:299
#, python-format
msgid "String (up to %(maxlength)s)"
msgstr "Cadena (máximo %(maxlength)s)"
-#: contrib/admin/views/doc.py:280
+#: contrib/admin/views/doc.py:282
msgid "Comma-separated integers"
msgstr "Enteros separados por comas"
-#: contrib/admin/views/doc.py:281
+#: contrib/admin/views/doc.py:283
msgid "Date (without time)"
msgstr "Fecha (sin hora)"
-#: contrib/admin/views/doc.py:282
+#: contrib/admin/views/doc.py:284
msgid "Date (with time)"
msgstr "Fecha (con hora)"
-#: contrib/admin/views/doc.py:283
+#: contrib/admin/views/doc.py:285
msgid "E-mail address"
msgstr "Dirección de correo electrónico"
-#: contrib/admin/views/doc.py:284 contrib/admin/views/doc.py:287
+#: contrib/admin/views/doc.py:286 contrib/admin/views/doc.py:287
+#: contrib/admin/views/doc.py:290
msgid "File path"
msgstr "Ruta de archivo"
-#: contrib/admin/views/doc.py:285
+#: contrib/admin/views/doc.py:288
msgid "Decimal number"
msgstr "Número decimal"
-#: contrib/admin/views/doc.py:291
+#: contrib/admin/views/doc.py:294
msgid "Boolean (Either True, False or None)"
msgstr "Booleano (Verdadero, Falso o Nulo)"
-#: contrib/admin/views/doc.py:292
+#: contrib/admin/views/doc.py:295
msgid "Relation to parent model"
msgstr "Relación con el modelo padre"
-#: contrib/admin/views/doc.py:293
+#: contrib/admin/views/doc.py:296
msgid "Phone number"
msgstr "Número de teléfono"
-#: contrib/admin/views/doc.py:298
+#: contrib/admin/views/doc.py:301
msgid "Text"
msgstr "Texto"
-#: contrib/admin/views/doc.py:299
+#: contrib/admin/views/doc.py:302
msgid "Time"
msgstr "Hora"
-#: contrib/admin/views/doc.py:301
+#: contrib/admin/views/doc.py:304
msgid "U.S. state (two uppercase letters)"
msgstr "Estado de los EEUU (dos letras mayúsculas)"
-#: contrib/admin/views/doc.py:302
+#: contrib/admin/views/doc.py:305
msgid "XML text"
msgstr "Texto XML"
@@ -900,7 +916,7 @@ msgstr "Hora:"
#: contrib/admin/templates/admin/object_history.html:3
#: contrib/admin/templates/admin/change_list.html:5
#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/admin/base.html:23
+#: contrib/admin/templates/admin/base.html:24
#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/registration/password_change_done.html:3
#: contrib/admin/templates/registration/password_change_form.html:3
@@ -911,7 +927,7 @@ msgstr "Documentación"
#: contrib/admin/templates/admin/object_history.html:3
#: contrib/admin/templates/admin/change_list.html:5
#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/admin/base.html:23
+#: contrib/admin/templates/admin/base.html:24
#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/registration/password_change_done.html:3
#: contrib/admin/templates/registration/password_change_form.html:3
@@ -932,8 +948,9 @@ msgstr "Cambiar contraseña"
#: contrib/admin/templates/admin/change_list.html:6
#: contrib/admin/templates/admin/500.html:4
#: contrib/admin/templates/admin/change_form.html:13
-#: contrib/admin/templates/admin/base.html:28
+#: contrib/admin/templates/admin/base.html:29
#: contrib/admin/templates/admin/delete_confirmation.html:6
+#: contrib/admin/templates/admin/invalid_setup.html:4
#: contrib/admin/templates/registration/password_change_done.html:4
#: contrib/admin/templates/registration/password_reset_form.html:4
#: contrib/admin/templates/registration/logged_out.html:4
@@ -946,7 +963,7 @@ msgstr "Inicio"
#: contrib/admin/templates/admin/object_history.html:5
#: contrib/admin/templates/admin/change_form.html:20
msgid "History"
-msgstr "Histórico"
+msgstr "Historia"
#: contrib/admin/templates/admin/object_history.html:18
msgid "Date/time"
@@ -962,15 +979,15 @@ msgstr "Acción"
#: contrib/admin/templates/admin/object_history.html:26
msgid "DATE_WITH_TIME_FULL"
-msgstr ""
+msgstr "j M Y P"
#: contrib/admin/templates/admin/object_history.html:36
msgid ""
"This object doesn't have a change history. It probably wasn't added via this "
"admin site."
msgstr ""
-"Este objeto no tiene histórico de cambios. Probablemente no fue añadido "
-"usando este sitio de administración."
+"Este objeto no tiene historia de modificaciones. Probablemente no fue "
+"añadido usando este sitio de administración."
#: contrib/admin/templates/admin/change_list.html:11
#, python-format
@@ -1007,6 +1024,22 @@ msgstr ""
msgid "Go"
msgstr "Buscar"
+#: contrib/admin/templates/admin/search_form.html:10
+#, python-format
+msgid "1 result"
+msgid_plural "%(counter)s results"
+msgstr[0] "un resultado"
+msgstr[1] "%(counter)s resultados"
+
+#: contrib/admin/templates/admin/search_form.html:10
+#, python-format
+msgid "%(full_result_count)s total"
+msgstr "total: %(full_result_count)s"
+
+#: contrib/admin/templates/admin/pagination.html:10
+msgid "Show all"
+msgstr "Mostrar todos/as"
+
#: contrib/admin/templates/admin/base_site.html:4
msgid "Django site admin"
msgstr "Sitio de administración de Django"
@@ -1018,7 +1051,7 @@ msgstr "Administración de Django"
#: contrib/admin/templates/admin/index.html:17
#, python-format
msgid "Models available in the %(name)s application."
-msgstr "Modelos disponibles en la aplciación %(name)s."
+msgstr "Modelos disponibles en la aplicación %(name)s."
#: contrib/admin/templates/admin/index.html:28
#: contrib/admin/templates/admin/change_form.html:15
@@ -1043,7 +1076,7 @@ msgstr "Mis acciones"
#: contrib/admin/templates/admin/index.html:57
msgid "None available"
-msgstr "Ninguno disponible"
+msgstr "Ninguna disponible"
#: contrib/admin/templates/admin/404.html:4
#: contrib/admin/templates/admin/404.html:8
@@ -1058,6 +1091,10 @@ msgstr "Lo sentimos, pero no se encuentra la página solicitada."
msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?"
msgstr "¿Ha <a href=\"/password_reset/\">olvidado su contraseña</a>?"
+#: contrib/admin/templates/admin/filters.html:4
+msgid "Filter"
+msgstr "Filtrar"
+
#: contrib/admin/templates/admin/change_form.html:21
msgid "View on site"
msgstr "Ver en el sitio"
@@ -1076,7 +1113,7 @@ msgstr "Ordenación"
msgid "Order:"
msgstr "Orden:"
-#: contrib/admin/templates/admin/base.html:23
+#: contrib/admin/templates/admin/base.html:24
msgid "Welcome,"
msgstr "Bienvenido,"
@@ -1125,6 +1162,16 @@ msgstr "Grabar y continuar editando"
msgid "Save"
msgstr "Grabar"
+#: contrib/admin/templates/admin/invalid_setup.html:8
+msgid ""
+"Something's wrong with your database installation. Make sure the appropriate "
+"database tables have been created, and make sure the database is readable by "
+"the appropriate user."
+msgstr ""
+"hay algún problema con su instalación de base de datos. Asegúrese de que las "
+"tablas de la misma hayan sido creadas, y asegúrese de que el usuario "
+"apropiado tenga permisos de escritura en la base de datos."
+
#: contrib/admin/templates/registration/password_change_done.html:4
#: contrib/admin/templates/registration/password_change_form.html:4
#: contrib/admin/templates/registration/password_change_form.html:6
@@ -1312,17 +1359,25 @@ msgid "As above, but opens the admin page in a new window."
msgstr ""
"Como antes, pero abre la página de administración en una nueva ventana."
-#: utils/translation.py:360
+#: utils/translation.py:363
msgid "DATE_FORMAT"
-msgstr ""
+msgstr "j N Y"
-#: utils/translation.py:361
+#: utils/translation.py:364
msgid "DATETIME_FORMAT"
-msgstr ""
+msgstr "j N Y P"
-#: utils/translation.py:362
+#: utils/translation.py:365
msgid "TIME_FORMAT"
-msgstr ""
+msgstr "P"
+
+#: utils/translation.py:381
+msgid "YEAR_MONTH_FORMAT"
+msgstr "F Y"
+
+#: utils/translation.py:382
+msgid "MONTH_DAY_FORMAT"
+msgstr "j \\de F"
#: utils/dates.py:6
msgid "Monday"
@@ -1386,7 +1441,7 @@ msgstr "Agosto"
#: utils/dates.py:15
msgid "September"
-msgstr "Septiembre"
+msgstr "Setiembre"
#: utils/dates.py:15
msgid "October"
@@ -1430,11 +1485,11 @@ msgstr ""
#: utils/dates.py:20
msgid "aug"
-msgstr ""
+msgstr "ago"
#: utils/dates.py:20
msgid "sep"
-msgstr ""
+msgstr "set"
#: utils/dates.py:20
msgid "oct"
@@ -1450,11 +1505,11 @@ msgstr "dic"
#: utils/dates.py:27
msgid "Jan."
-msgstr "Ene."
+msgstr "Enero"
#: utils/dates.py:27
msgid "Feb."
-msgstr "Feb."
+msgstr ""
#: utils/dates.py:28
msgid "Aug."
@@ -1462,15 +1517,15 @@ msgstr "Ago."
#: utils/dates.py:28
msgid "Sept."
-msgstr "Sept."
+msgstr "Set."
#: utils/dates.py:28
msgid "Oct."
-msgstr "Oct."
+msgstr ""
#: utils/dates.py:28
msgid "Nov."
-msgstr "Nov."
+msgstr ""
#: utils/dates.py:28
msgid "Dec."
@@ -1491,7 +1546,7 @@ msgstr[1] "meses"
#: utils/timesince.py:14
msgid "week"
msgid_plural "weeks"
-msgstr[0] "semmana"
+msgstr[0] "semana"
msgstr[1] "semanas"
#: utils/timesince.py:15
@@ -1546,7 +1601,7 @@ msgstr "Español"
#: conf/global_settings.py:45
msgid "Argentinean Spanish"
-msgstr ""
+msgstr "Español Argentino"
#: conf/global_settings.py:46
msgid "French"
@@ -1558,7 +1613,7 @@ msgstr "Gallego"
#: conf/global_settings.py:48
msgid "Hungarian"
-msgstr ""
+msgstr "Húngaro"
#: conf/global_settings.py:49
msgid "Hebrew"
@@ -1636,7 +1691,7 @@ msgid "%(optname)s with this %(fieldname)s already exists."
msgstr "Ya existe %(optname)s con este %(fieldname)s."
#: db/models/fields/__init__.py:114 db/models/fields/__init__.py:265
-#: db/models/fields/__init__.py:542 db/models/fields/__init__.py:553
+#: db/models/fields/__init__.py:545 db/models/fields/__init__.py:556
#: forms/__init__.py:346
msgid "This field is required."
msgstr "Este campo es obligatorio."
@@ -1653,11 +1708,11 @@ msgstr "Este valor debe ser True o False."
msgid "This field cannot be null."
msgstr "Este campo no puede ser nulo."
-#: db/models/fields/__init__.py:468 core/validators.py:132
+#: db/models/fields/__init__.py:471 core/validators.py:135
msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
msgstr "Introduzca una fecha/hora válida en formato YYYY-MM-DD HH:MM."
-#: db/models/fields/__init__.py:562
+#: db/models/fields/__init__.py:565
msgid "Enter a valid filename."
msgstr "Introduzca un nombre de achivo válido"
@@ -1688,43 +1743,48 @@ msgstr[1] ""
"Por favor, introduzca IDs de %(self)s válidos. Los valores %(value)r no son "
"válidos."
-#: forms/__init__.py:380
+#: forms/__init__.py:381
#, python-format
msgid "Ensure your text is less than %s character."
msgid_plural "Ensure your text is less than %s characters."
msgstr[0] "Asegúrese de que su texto tiene menos de %s carácter."
msgstr[1] "Asegúrese de que su texto tiene menos de %s caracteres."
-#: forms/__init__.py:385
+#: forms/__init__.py:386
msgid "Line breaks are not allowed here."
msgstr "No se permiten saltos de línea."
-#: forms/__init__.py:480 forms/__init__.py:551 forms/__init__.py:589
+#: forms/__init__.py:485 forms/__init__.py:558 forms/__init__.py:597
#, python-format
msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
msgstr "Seleccione una opción válida; '%(data)s' no está en %(choices)s."
-#: forms/__init__.py:645
+#: forms/__init__.py:659 core/validators.py:151 core/validators.py:379
+msgid "No file was submitted. Check the encoding type on the form."
+msgstr ""
+"No se envió un archivo. Verifique el tipo de codificación en el formulario."
+
+#: forms/__init__.py:661
msgid "The submitted file is empty."
msgstr "El archivo enviado está vacío."
-#: forms/__init__.py:699
+#: forms/__init__.py:717
msgid "Enter a whole number between -32,768 and 32,767."
msgstr "Introduzca un número entero entre -32,768 y 32,767."
-#: forms/__init__.py:708
+#: forms/__init__.py:727
msgid "Enter a positive number."
msgstr "Introduzca un número positivo."
-#: forms/__init__.py:717
+#: forms/__init__.py:737
msgid "Enter a whole number between 0 and 32,767."
msgstr "Introduzca un número entero entre 0 y 32,767."
-#: core/validators.py:60
+#: core/validators.py:63
msgid "This value must contain only letters, numbers and underscores."
msgstr "Este valor debe contener sólo letras, números y guiones bajos."
-#: core/validators.py:64
+#: core/validators.py:67
msgid ""
"This value must contain only letters, numbers, underscores, dashes or "
"slashes."
@@ -1732,59 +1792,59 @@ msgstr ""
"Este valor debe contener sólo letras, números, guiones bajos, barras (/) o "
"slashes."
-#: core/validators.py:72
+#: core/validators.py:75
msgid "Uppercase letters are not allowed here."
msgstr "No se admiten letras mayúsculas."
-#: core/validators.py:76
+#: core/validators.py:79
msgid "Lowercase letters are not allowed here."
msgstr "No se admiten letras minúsculas."
-#: core/validators.py:83
+#: core/validators.py:86
msgid "Enter only digits separated by commas."
msgstr "Introduzca sólo dígitos separados por comas."
-#: core/validators.py:95
+#: core/validators.py:98
msgid "Enter valid e-mail addresses separated by commas."
msgstr "Introduzca direcciones de correo válidas separadas por comas."
-#: core/validators.py:99
+#: core/validators.py:102
msgid "Please enter a valid IP address."
msgstr "Por favor introduzca una dirección IP válida."
-#: core/validators.py:103
+#: core/validators.py:106
msgid "Empty values are not allowed here."
msgstr "No se admiten valores vacíos."
-#: core/validators.py:107
+#: core/validators.py:110
msgid "Non-numeric characters aren't allowed here."
msgstr "No se admiten caracteres no numéricos."
-#: core/validators.py:111
+#: core/validators.py:114
msgid "This value can't be comprised solely of digits."
msgstr "Este valor no puede estar formado sólo por dígitos."
-#: core/validators.py:116
+#: core/validators.py:119
msgid "Enter a whole number."
msgstr "Introduzca un número entero."
-#: core/validators.py:120
+#: core/validators.py:123
msgid "Only alphabetical characters are allowed here."
msgstr "Sólo se admiten caracteres alfabéticos."
-#: core/validators.py:124
+#: core/validators.py:127
msgid "Enter a valid date in YYYY-MM-DD format."
msgstr "Introduzca una fecha válida en formato AAAA-MM-DD."
-#: core/validators.py:128
+#: core/validators.py:131
msgid "Enter a valid time in HH:MM format."
msgstr "Introduzca una hora válida en formato HH:MM."
-#: core/validators.py:136
+#: core/validators.py:139
msgid "Enter a valid e-mail address."
msgstr "Introduzca una dirección de correo electrónico válida"
-#: core/validators.py:148
+#: core/validators.py:155
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
@@ -1792,28 +1852,28 @@ msgstr ""
"Envíe una imagen válida. El archivo que ha enviado no era una imagen o se "
"trataba de una imagen corrupta."
-#: core/validators.py:155
+#: core/validators.py:162
#, python-format
msgid "The URL %s does not point to a valid image."
msgstr "La URL %s no apunta a una imagen válida."
-#: core/validators.py:159
+#: core/validators.py:166
#, python-format
msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
msgstr ""
"Los números de teléfono deben guardar el formato XXX-XXX-XXXX format. \"%s\" "
"no es válido."
-#: core/validators.py:167
+#: core/validators.py:174
#, python-format
msgid "The URL %s does not point to a valid QuickTime video."
msgstr "La URL %s no apunta a un vídeo QuickTime válido."
-#: core/validators.py:171
+#: core/validators.py:178
msgid "A valid URL is required."
msgstr "Se precisa una URL válida."
-#: core/validators.py:185
+#: core/validators.py:192
#, python-format
msgid ""
"Valid HTML is required. Specific errors are:\n"
@@ -1822,116 +1882,129 @@ msgstr ""
"Se precisa HTML válido. Los errores específicos son:\n"
"%s"
-#: core/validators.py:192
+#: core/validators.py:199
#, python-format
msgid "Badly formed XML: %s"
msgstr "XML mal formado: %s"
-#: core/validators.py:202
+#: core/validators.py:209
#, python-format
msgid "Invalid URL: %s"
msgstr "URL no válida: %s"
-#: core/validators.py:206 core/validators.py:208
+#: core/validators.py:213 core/validators.py:215
#, python-format
msgid "The URL %s is a broken link."
msgstr "La URL %s es un enlace roto."
-#: core/validators.py:214
+#: core/validators.py:221
msgid "Enter a valid U.S. state abbreviation."
msgstr "Introduzca una abreviatura válida de estado de los EEUU."
-#: core/validators.py:229
+#: core/validators.py:236
#, python-format
msgid "Watch your mouth! The word %s is not allowed here."
msgid_plural "Watch your mouth! The words %s are not allowed here."
msgstr[0] "¡Vigila tu boca! Aquí no admitimos la palabra %s."
msgstr[1] "¡Vigila tu boca! Aquí no admitimos las palabras %s."
-#: core/validators.py:236
+#: core/validators.py:243
#, python-format
msgid "This field must match the '%s' field."
msgstr "Este campo debe concordar con el campo '%s'."
-#: core/validators.py:255
+#: core/validators.py:262
msgid "Please enter something for at least one field."
msgstr "Por favor, introduzca algo en al menos un campo."
-#: core/validators.py:264 core/validators.py:275
+#: core/validators.py:271 core/validators.py:282
msgid "Please enter both fields or leave them both empty."
msgstr "Por favor, rellene ambos campos o deje ambos vacíos."
-#: core/validators.py:282
+#: core/validators.py:289
#, python-format
msgid "This field must be given if %(field)s is %(value)s"
msgstr "Se debe proporcionar este campo si %(field)s es %(value)s"
-#: core/validators.py:294
+#: core/validators.py:301
#, python-format
msgid "This field must be given if %(field)s is not %(value)s"
msgstr "Se debe proporcionar este campo si %(field)s no es %(value)s"
-#: core/validators.py:313
+#: core/validators.py:320
msgid "Duplicate values are not allowed."
msgstr "No se admiten valores duplicados."
-#: core/validators.py:336
+#: core/validators.py:343
#, python-format
msgid "This value must be a power of %s."
msgstr "Este valor debe ser una potencia de %s."
-#: core/validators.py:347
+#: core/validators.py:354
msgid "Please enter a valid decimal number."
msgstr "Por favor, introduzca un número decimal válido."
-#: core/validators.py:349
+#: core/validators.py:356
#, python-format
msgid "Please enter a valid decimal number with at most %s total digit."
msgid_plural ""
"Please enter a valid decimal number with at most %s total digits."
msgstr[0] ""
-"Por favor, introduzca un número decimal válido con con un máximo de %s "
+"Por favor, introduzca un número decimal válido con con un máximo de un "
"dígito en total."
msgstr[1] ""
"Por favor, introduzca un número decimal válido con un maximo de %s dígitos "
"en total."
-#: core/validators.py:352
+#: core/validators.py:359
+#, python-format
+msgid ""
+"Please enter a valid decimal number with a whole part of at most %s digit."
+msgid_plural ""
+"Please enter a valid decimal number with a whole part of at most %s digits."
+msgstr[0] ""
+"Por favor, introduzca un número decimal válido con un dígito entero como "
+"máximo."
+msgstr[1] ""
+"Por favor, introduzca un número decimal válido con un máximo de %s dígitos "
+"enteros."
+
+#: core/validators.py:362
#, python-format
msgid "Please enter a valid decimal number with at most %s decimal place."
msgid_plural ""
"Please enter a valid decimal number with at most %s decimal places."
msgstr[0] ""
-"Por favor, introduzca un número decimal válido con un máximo de %s "
-"posición decimal."
+"Por favor, introduzca un número decimal válido con un máximo de una posición "
+"decimal."
msgstr[1] ""
"Por favor, introduzca un número decimal válido con un máximo de %s "
"posiciones decimales."
-#: core/validators.py:362
+#: core/validators.py:372
#, python-format
msgid "Make sure your uploaded file is at least %s bytes big."
msgstr "Asegúrese de que el archivo que envía tiene al menos %s bytes."
-#: core/validators.py:363
+#: core/validators.py:373
#, python-format
msgid "Make sure your uploaded file is at most %s bytes big."
msgstr "Asegúrese de que el archivo que envía tiene como máximo %s bytes."
-#: core/validators.py:376
+#: core/validators.py:390
msgid "The format for this field is wrong."
msgstr "El formato de este campo es incorrecto."
-#: core/validators.py:391
+#: core/validators.py:405
msgid "This field is invalid."
msgstr "Este campo no es válido."
-#: core/validators.py:426
+#: core/validators.py:441
#, python-format
msgid "Could not retrieve anything from %s."
msgstr "No pude obtener nada de %s."
-#: core/validators.py:429
+#: core/validators.py:444
#, python-format
msgid ""
"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
@@ -1939,7 +2012,7 @@ msgstr ""
"La URL %(url)s devolvió la cabecera Content-Type '%(contenttype)s', que no "
"es válida."
-#: core/validators.py:462
+#: core/validators.py:477
#, python-format
msgid ""
"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "
@@ -1948,7 +2021,7 @@ msgstr ""
"Por favor, cierre la etiqueta %(tag)s de la línea %(line)s. (La línea "
"empieza por \"%(start)s\".)"
-#: core/validators.py:466
+#: core/validators.py:481
#, python-format
msgid ""
"Some text starting on line %(line)s is not allowed in that context. (Line "
@@ -1957,7 +2030,7 @@ msgstr ""
"Parte del texto que comienza en la línea %(line)s no está permitido en ese "
"contexto. (La línea empieza por \"%(start)s\".)"
-#: core/validators.py:471
+#: core/validators.py:486
#, python-format
msgid ""
"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%"
@@ -1966,7 +2039,7 @@ msgstr ""
"El \"%(attr)s\" de la línea %(line)s no es un atributo válido. (La línea "
"empieza por \"%(start)s\".)"
-#: core/validators.py:476
+#: core/validators.py:491
#, python-format
msgid ""
"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%"
@@ -1975,7 +2048,7 @@ msgstr ""
"La \"<%(tag)s>\" de la línea %(line)s no es una etiqueta válida. (La línea "
"empieza por \"%(start)s\".)"
-#: core/validators.py:480
+#: core/validators.py:495
#, python-format
msgid ""
"A tag on line %(line)s is missing one or more required attributes. (Line "
@@ -1984,7 +2057,7 @@ msgstr ""
"A una etiqueta de la línea %(line)s le faltan uno o más atributos "
"requeridos. (La línea empieza por \"%(start)s\".)"
-#: core/validators.py:485
+#: core/validators.py:500
#, python-format
msgid ""
"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line "
@@ -1993,10 +2066,23 @@ msgstr ""
"El atributo \"%(attr)s\" de la línea %(line)s tiene un valor que no es "
"válido. (La línea empieza por \"%(start)s\".)"
-#: template/defaultfilters.py:379
+#: template/defaultfilters.py:389
msgid "yes,no,maybe"
msgstr "si,no,tal vez"
+#, fuzzy
+#~ msgid "%(content_type_name)s"
+#~ msgstr "tipos de contenido"
+
+#, fuzzy
+#~ msgid "%(myname)s"
+#~ msgstr "Agregar %(name)s"
+
+#~ msgid "%(result_count)s result"
+#~ msgid_plural "%(counter)s results"
+#~ msgstr[0] "un resultado"
+#~ msgstr[1] "%(counter)s resultados"
+
#~ msgid "Comment"
#~ msgstr "Comentario"
@@ -2014,16 +2100,3 @@ msgstr "si,no,tal vez"
#~ msgid "packages"
#~ msgstr "paquetes"
-
-#, fuzzy
-#~ msgid ""
-#~ "Please enter a valid decimal number with a whole part of at most %s digit."
-#~ msgid_plural ""
-#~ "Please enter a valid decimal number with a whole part of at most %s "
-#~ "digits."
-#~ msgstr[0] ""
-#~ "Por favor, introduzca un número decimal válido con a lo más %s dígito en "
-#~ "total."
-#~ msgstr[1] ""
-#~ "Por favor, introduzca un número decimal válido con a lo más %s dígitos en "
-#~ "total."
diff --git a/django/conf/locale/es_AR/LC_MESSAGES/djangojs.mo b/django/conf/locale/es_AR/LC_MESSAGES/djangojs.mo
index e48292825b..f24c9a12d0 100644
--- a/django/conf/locale/es_AR/LC_MESSAGES/djangojs.mo
+++ b/django/conf/locale/es_AR/LC_MESSAGES/djangojs.mo
Binary files differ
diff --git a/django/conf/locale/es_AR/LC_MESSAGES/djangojs.po b/django/conf/locale/es_AR/LC_MESSAGES/djangojs.po
index e9578701d5..49d3856d3c 100644
--- a/django/conf/locale/es_AR/LC_MESSAGES/djangojs.po
+++ b/django/conf/locale/es_AR/LC_MESSAGES/djangojs.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Django JavaScript 1.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2005-12-09 11:51+0100\n"
+"POT-Creation-Date: 2006-06-19 12:15-0300\n"
"PO-Revision-Date: 2006-05-16 10:20-0300\n"
"Last-Translator: Ramiro Morales <rm0@gmx.net>\n"
"MIME-Version: 1.0\n"
@@ -22,7 +22,7 @@ msgstr "%s disponibles"
#: contrib/admin/media/js/SelectFilter2.js:41
msgid "Choose all"
-msgstr "Selecciona todos"
+msgstr "Seleccionar todos"
#: contrib/admin/media/js/SelectFilter2.js:46
msgid "Add"
@@ -43,9 +43,9 @@ msgstr "Haga sus elecciones y haga click en "
#: contrib/admin/media/js/SelectFilter2.js:59
msgid "Clear all"
-msgstr "Elimina todos"
+msgstr "Eliminar todos"
-#: contrib/admin/media/js/dateparse.js:26
+#: contrib/admin/media/js/dateparse.js:32
#: contrib/admin/media/js/calendar.js:24
msgid ""
"January February March April May June July August September October November "
@@ -54,7 +54,7 @@ msgstr ""
"Enero Febrero Marzo Abril Mayo Junio Julio Agosto Septiembre Octubre "
"Noviembre Diciembre"
-#: contrib/admin/media/js/dateparse.js:27
+#: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr "Domingo Lunes Martes Miércoles Jueves Viernes Sábado"
@@ -62,8 +62,17 @@ msgstr "Domingo Lunes Martes Miércoles Jueves Viernes Sábado"
msgid "S M T W T F S"
msgstr "D L M M J V S"
+#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
+#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
+msgid "Show"
+msgstr "Mostrar"
+
+#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
+msgid "Hide"
+msgstr "Ocultar"
+
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:89
msgid "Now"
msgstr "Ahora"
@@ -71,40 +80,40 @@ msgstr "Ahora"
msgid "Clock"
msgstr "Reloj"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:86
msgid "Choose a time"
msgstr "Elija una hora"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:90
msgid "Midnight"
msgstr "Medianoche"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:91
msgid "6 a.m."
msgstr "6 a.m."
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:92
msgid "Noon"
msgstr "Mediodía"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:96
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:187
msgid "Cancel"
msgstr "Cancelar"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:120
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:181
msgid "Today"
msgstr "Hoy"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:123
msgid "Calendar"
msgstr "Calendario"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Yesterday"
msgstr "Ayer"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
msgid "Tomorrow"
msgstr "Mañana"
diff --git a/django/conf/locale/zh_CN/LC_MESSAGES/djangojs.po b/django/conf/locale/zh_CN/LC_MESSAGES/djangojs.po
new file mode 100644
index 0000000000..1e9e7dbeb7
--- /dev/null
+++ b/django/conf/locale/zh_CN/LC_MESSAGES/djangojs.po
@@ -0,0 +1,107 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-03-21 18:43+0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <max@exoweb.net>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: contrib/admin/media/js/SelectFilter2.js:33
+msgid "Available %s"
+msgstr "å¯è¡Œ %s"
+
+#: contrib/admin/media/js/SelectFilter2.js:41
+msgid "Choose all"
+msgstr "全选"
+
+#: contrib/admin/media/js/SelectFilter2.js:46
+msgid "Add"
+msgstr "增加"
+
+#: contrib/admin/media/js/SelectFilter2.js:48
+msgid "Remove"
+msgstr "移出"
+
+#: contrib/admin/media/js/SelectFilter2.js:53
+msgid "Chosen %s"
+msgstr "选择 %s"
+
+#: contrib/admin/media/js/SelectFilter2.js:54
+msgid "Select your choice(s) and click "
+msgstr "挑选你的选择并且点击 "
+
+#: contrib/admin/media/js/SelectFilter2.js:59
+msgid "Clear all"
+msgstr "清除所有"
+
+#: contrib/admin/media/js/dateparse.js:32
+#: contrib/admin/media/js/calendar.js:24
+msgid ""
+"January February March April May June July August September October November "
+"December"
+msgstr "一月 二月 三月 四月 五月 六月 六月 七月 八月 乿œˆ åæœˆ å一月 å二月"
+
+#: contrib/admin/media/js/dateparse.js:33
+msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
+msgstr "星期天 星期一 星期二 星期三 星期四 星期五 星期六"
+
+#: contrib/admin/media/js/calendar.js:25
+msgid "S M T W T F S"
+msgstr "æ—¥ 月 ç« æ°´ 木 金 土"
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
+msgid "Now"
+msgstr "现在"
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
+msgid "Clock"
+msgstr "æ—¶é’Ÿ"
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
+msgid "Choose a time"
+msgstr "选择一个时间"
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
+msgid "Midnight"
+msgstr "åˆå¤œ"
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
+msgid "6 a.m."
+msgstr "上åˆ6点"
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
+msgid "Noon"
+msgstr "æ­£åˆ"
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
+msgid "Cancel"
+msgstr "å–æ¶ˆ"
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
+msgid "Today"
+msgstr "今天"
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
+msgid "Calendar"
+msgstr "日历"
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
+msgid "Yesterday"
+msgstr "昨天"
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
+msgid "Tomorrow"
+msgstr "明天"
diff --git a/django/contrib/admin/views/doc.py b/django/contrib/admin/views/doc.py
index e48e9800a7..f7ce2fa498 100644
--- a/django/contrib/admin/views/doc.py
+++ b/django/contrib/admin/views/doc.py
@@ -14,6 +14,10 @@ import inspect, os, re
# Exclude methods starting with these strings from documentation
MODEL_METHODS_EXCLUDE = ('_', 'add_', 'delete', 'save', 'set_')
+class GenericSite(object):
+ domain = 'example.com'
+ name = 'my site'
+
def doc_index(request):
if not utils.docutils_is_available:
return missing_docutils_page(request)
@@ -102,12 +106,16 @@ def view_index(request):
for settings_mod in settings_modules:
urlconf = __import__(settings_mod.ROOT_URLCONF, '', '', [''])
view_functions = extract_views_from_urlpatterns(urlconf.urlpatterns)
+ if Site._meta.installed:
+ site_obj = Site.objects.get(pk=settings_mod.SITE_ID)
+ else:
+ site_obj = GenericSite()
for (func, regex) in view_functions:
views.append({
'name': func.__name__,
'module': func.__module__,
'site_id': settings_mod.SITE_ID,
- 'site': Site.objects.get(pk=settings_mod.SITE_ID),
+ 'site': site_obj,
'url': simplify_regex(regex),
})
return render_to_response('admin_doc/view_index.html', {'views': views}, context_instance=RequestContext(request))
@@ -228,6 +236,10 @@ def template_detail(request, template):
templates = []
for site_settings_module in settings.ADMIN_FOR:
settings_mod = __import__(site_settings_module, '', '', [''])
+ if Site._meta.installed:
+ site_obj = Site.objects.get(pk=settings_mod.SITE_ID)
+ else:
+ site_obj = GenericSite()
for dir in settings_mod.TEMPLATE_DIRS:
template_file = os.path.join(dir, "%s.html" % template)
templates.append({
@@ -235,7 +247,7 @@ def template_detail(request, template):
'exists': os.path.exists(template_file),
'contents': lambda: os.path.exists(template_file) and open(template_file).read() or '',
'site_id': settings_mod.SITE_ID,
- 'site': Site.objects.get(pk=settings_mod.SITE_ID),
+ 'site': site_obj,
'order': list(settings_mod.TEMPLATE_DIRS).index(dir),
})
return render_to_response('admin_doc/template_detail.html', {
diff --git a/django/contrib/comments/templates/comments/form.html b/django/contrib/comments/templates/comments/form.html
index deb5540c92..3e171b1e67 100644
--- a/django/contrib/comments/templates/comments/form.html
+++ b/django/contrib/comments/templates/comments/form.html
@@ -3,7 +3,7 @@
<form {% if photos_optional or photos_required %}enctype="multipart/form-data" {% endif %}action="/comments/post/" method="post">
{% if user.is_anonymous %}
-<p>{% trans "Username:" %} <input type="text" name="username" id="id_username" /><br />{% trans "Password:" %} <input type="password" name="password" id="id_password" /> (<a href="/accounts/password_reset/">{% trans "Forgotten your password?" %}</a>)</p>
+<p><label for="id_username">{% trans "Username:" %}</label> <input type="text" name="username" id="id_username" /><br />{% trans "Password:" %} <input type="password" name="password" id="id_password" /> (<a href="/accounts/password_reset/">{% trans "Forgotten your password?" %}</a>)</p>
{% else %}
<p>{% trans "Username:" %} <strong>{{ user.username }}</strong> (<a href="/accounts/logout/">{% trans "Log out" %}</a>)</p>
{% endif %}
@@ -20,11 +20,13 @@
{% endif %}
{% if photos_optional or photos_required %}
-<p>{% trans "Post a photo" %} ({% if photos_required %}{% trans "Required" %}{% else %}{% trans "Optional" %}{% endif %}): <input type="file" name="photo" /></p>
+<p><label for="id_photo">{% trans "Post a photo" %}</label> ({% if photos_required %}{% trans "Required" %}{% else %}{% trans "Optional" %}{% endif %}):
+<input type="file" name="photo" id="id_photo" /></p>
<input type="hidden" name="photo_options" value="{{ photo_options }}" />
{% endif %}
-<p>{% trans "Comment:" %}<br /><textarea name="comment" id="id_comment" rows="10" cols="60"></textarea></p>
+<p><label for="id_comment">{% trans "Comment:" %}</label><br />
+<textarea name="comment" id="id_comment" rows="10" cols="60"></textarea></p>
<input type="hidden" name="options" value="{{ options }}" />
<input type="hidden" name="target" value="{{ target }}" />
diff --git a/django/contrib/comments/templates/comments/freeform.html b/django/contrib/comments/templates/comments/freeform.html
index 0c52bfab29..99a02b4d97 100644
--- a/django/contrib/comments/templates/comments/freeform.html
+++ b/django/contrib/comments/templates/comments/freeform.html
@@ -1,8 +1,8 @@
{% load i18n %}
{% if display_form %}
<form action="/comments/postfree/" method="post">
-<p>{% trans "Your name:" %} <input type="text" id="id_person_name" name="person_name" /></p>
-<p>{% trans "Comment:" %}<br /><textarea name="comment" id="id_comment" rows="10" cols="60"></textarea></p>
+<p><label for="id_person_name">{% trans "Your name:" %}</label> <input type="text" id="id_person_name" name="person_name" /></p>
+<p><label for="id_comment">{% trans "Comment:" %}</label><br /><textarea name="comment" id="id_comment" rows="10" cols="60"></textarea></p>
<input type="hidden" name="options" value="{{ options }}" />
<input type="hidden" name="target" value="{{ target }}" />
<input type="hidden" name="gonzo" value="{{ hash }}" />
diff --git a/django/contrib/syndication/feeds.py b/django/contrib/syndication/feeds.py
index 3deefc5866..e648c6c746 100644
--- a/django/contrib/syndication/feeds.py
+++ b/django/contrib/syndication/feeds.py
@@ -16,10 +16,14 @@ class Feed(object):
item_pubdate = None
item_enclosure_url = None
feed_type = feedgenerator.DefaultFeed
+ title_template = None
+ description_template = None
def __init__(self, slug, feed_url):
self.slug = slug
self.feed_url = feed_url
+ self.title_template_name = self.title_template or ('feeds/%s_title.html' % slug)
+ self.description_template_name = self.description_template or ('feeds/%s_description.html' % slug)
def item_link(self, item):
try:
@@ -77,13 +81,13 @@ class Feed(object):
)
try:
- title_template = loader.get_template('feeds/%s_title.html' % self.slug)
+ title_tmp = loader.get_template(self.title_template_name)
except TemplateDoesNotExist:
- title_template = Template('{{ obj }}')
+ title_tmp = Template('{{ obj }}')
try:
- description_template = loader.get_template('feeds/%s_description.html' % self.slug)
+ description_tmp = loader.get_template(self.description_template_name)
except TemplateDoesNotExist:
- description_template = Template('{{ obj }}')
+ description_tmp = Template('{{ obj }}')
for item in self.__get_dynamic_attr('items', obj):
link = add_domain(current_site.domain, self.__get_dynamic_attr('item_link', item))
@@ -102,9 +106,9 @@ class Feed(object):
else:
author_email = author_link = None
feed.add_item(
- title = title_template.render(Context({'obj': item, 'site': current_site})).decode('utf-8'),
+ title = title_tmp.render(Context({'obj': item, 'site': current_site})).decode('utf-8'),
link = link,
- description = description_template.render(Context({'obj': item, 'site': current_site})).decode('utf-8'),
+ description = description_tmp.render(Context({'obj': item, 'site': current_site})).decode('utf-8'),
unique_id = link,
enclosure = enc,
pubdate = self.__get_dynamic_attr('item_pubdate', item),
diff --git a/django/core/management.py b/django/core/management.py
index ea572729d9..ea210af88f 100644
--- a/django/core/management.py
+++ b/django/core/management.py
@@ -803,9 +803,9 @@ class ModelErrorCollection:
self.errors = []
self.outfile = outfile
- def add(self, opts, error):
- self.errors.append((opts, error))
- self.outfile.write(style.ERROR("%s.%s: %s\n" % (opts.app_label, opts.module_name, error)))
+ def add(self, context, error):
+ self.errors.append((context, error))
+ self.outfile.write(style.ERROR("%s: %s\n" % (context, error)))
def get_validation_errors(outfile, app=None):
"""
@@ -814,9 +814,14 @@ def get_validation_errors(outfile, app=None):
Returns number of errors.
"""
from django.db import models
+ from django.db.models.loading import get_app_errors
from django.db.models.fields.related import RelatedObject
e = ModelErrorCollection(outfile)
+
+ for (app_name, error) in get_app_errors().items():
+ e.add(app_name, error)
+
for cls in models.get_models(app):
opts = cls._meta
@@ -858,19 +863,30 @@ def get_validation_errors(outfile, app=None):
e.add(opts, "'%s' has relation with model %s, which has not been installed" % (f.name, rel_opts.object_name))
rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name()
+ rel_query_name = f.related_query_name()
for r in rel_opts.fields:
if r.name == rel_name:
- e.add(opts, "'%s' accessor name '%s.%s' clashes with another field. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
+ e.add(opts, "Accessor for field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
+ if r.name == rel_query_name:
+ e.add(opts, "Reverse query name for field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
for r in rel_opts.many_to_many:
if r.name == rel_name:
- e.add(opts, "'%s' accessor name '%s.%s' clashes with a m2m field. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
+ e.add(opts, "Accessor for field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
+ if r.name == rel_query_name:
+ e.add(opts, "Reverse query name for field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
for r in rel_opts.get_all_related_many_to_many_objects():
if r.get_accessor_name() == rel_name:
- e.add(opts, "'%s' accessor name '%s.%s' clashes with a related m2m field. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+ e.add(opts, "Accessor for field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+ if r.get_accessor_name() == rel_query_name:
+ e.add(opts, "Reverse query name for field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
for r in rel_opts.get_all_related_objects():
- if r.get_accessor_name() == rel_name and r.field is not f:
- e.add(opts, "'%s' accessor name '%s.%s' clashes with another related field. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+ if r.field is not f:
+ if r.get_accessor_name() == rel_name:
+ e.add(opts, "Accessor for field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+ if r.get_accessor_name() == rel_query_name:
+ e.add(opts, "Reverse query name for field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+
for i, f in enumerate(opts.many_to_many):
# Check to see if the related m2m field will clash with any
# existing fields, m2m fields, m2m related objects or related objects
@@ -879,18 +895,28 @@ def get_validation_errors(outfile, app=None):
e.add(opts, "'%s' has m2m relation with model %s, which has not been installed" % (f.name, rel_opts.object_name))
rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name()
+ rel_query_name = f.related_query_name()
for r in rel_opts.fields:
if r.name == rel_name:
- e.add(opts, "'%s' m2m accessor name '%s.%s' clashes with another field. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
+ e.add(opts, "Accessor for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
+ if r.name == rel_query_name:
+ e.add(opts, "Reverse query name for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
for r in rel_opts.many_to_many:
if r.name == rel_name:
- e.add(opts, "'%s' m2m accessor name '%s.%s' clashes with a m2m field. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
+ e.add(opts, "Accessor for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
+ if r.name == rel_query_name:
+ e.add(opts, "Reverse query name for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
for r in rel_opts.get_all_related_many_to_many_objects():
- if r.get_accessor_name() == rel_name and r.field is not f:
- e.add(opts, "'%s' m2m accessor name '%s.%s' clashes with a related m2m field. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+ if r.field is not f:
+ if r.get_accessor_name() == rel_name:
+ e.add(opts, "Accessor for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+ if r.get_accessor_name() == rel_query_name:
+ e.add(opts, "Reverse query name for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
for r in rel_opts.get_all_related_objects():
if r.get_accessor_name() == rel_name:
- e.add(opts, "'%s' m2m accessor name '%s.%s' clashes with another related field. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+ e.add(opts, "Accessor for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+ if r.get_accessor_name() == rel_query_name:
+ e.add(opts, "Reverse query name for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
# Check admin attribute.
if opts.admin is not None:
diff --git a/django/db/models/base.py b/django/db/models/base.py
index de42a5790b..73abd018ff 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -9,7 +9,7 @@ from django.db.models.query import orderlist2sql, delete_objects
from django.db.models.options import Options, AdminOptions
from django.db import connection, backend, transaction
from django.db.models import signals
-from django.db.models.loading import register_models
+from django.db.models.loading import register_models, get_model
from django.dispatch import dispatcher
from django.utils.datastructures import SortedDict
from django.utils.functional import curry
@@ -60,7 +60,11 @@ class ModelBase(type):
new_class._prepare()
register_models(new_class._meta.app_label, new_class)
- return new_class
+ # Because of the way imports happen (recursively), we may or may not be
+ # the first class for this model to register with the framework. There
+ # should only be one class for each model, so we must always return the
+ # registered version.
+ return get_model(new_class._meta.app_label, name)
class Model(object):
__metaclass__ = ModelBase
diff --git a/django/db/models/loading.py b/django/db/models/loading.py
index 4eafc22fb4..10ff3bb8d8 100644
--- a/django/db/models/loading.py
+++ b/django/db/models/loading.py
@@ -2,6 +2,8 @@
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
+import sys
+import os
__all__ = ('get_apps', 'get_app', 'get_models', 'get_model', 'register_models')
@@ -10,6 +12,9 @@ _app_list = [] # Cache of installed apps.
_app_models = {} # Dictionary of models against app label
# Each value is a dictionary of model name: model class
# Applabel and Model entry exists in cache when individual model is loaded.
+_app_errors = {} # Dictionary of errors that were experienced when loading the INSTALLED_APPS
+ # Key is the app_name of the model, value is the exception that was raised
+ # during model loading.
_loaded = False # Has the contents of settings.INSTALLED_APPS been loaded?
# i.e., has get_apps() been called?
@@ -22,11 +27,9 @@ def get_apps():
for app_name in settings.INSTALLED_APPS:
try:
load_app(app_name)
- except ImportError:
- pass # Assume this app doesn't have a models.py in it.
- # GOTCHA: It may have a models.py that raises ImportError.
- except AttributeError:
- pass # This app doesn't have a models.py in it.
+ except Exception, e:
+ # Problem importing the app
+ _app_errors[app_name] = e
return _app_list
def get_app(app_label):
@@ -39,10 +42,17 @@ def get_app(app_label):
def load_app(app_name):
"Loads the app with the provided fully qualified name, and returns the model module."
+ global _app_list
mod = __import__(app_name, '', '', ['models'])
if mod.models not in _app_list:
_app_list.append(mod.models)
return mod.models
+
+def get_app_errors():
+ "Returns the map of known problems with the INSTALLED_APPS"
+ global _app_errors
+ get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
+ return _app_errors
def get_models(app_mod=None):
"""
@@ -63,7 +73,6 @@ def get_model(app_label, model_name):
Returns the model matching the given app_label and case-insensitive model_name.
Returns None if no model is found.
"""
- get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
try:
model_dict = _app_models[app_label]
except KeyError:
@@ -83,4 +92,14 @@ def register_models(app_label, *models):
# in the _app_models dictionary
model_name = model._meta.object_name.lower()
model_dict = _app_models.setdefault(app_label, {})
+ if model_dict.has_key(model_name):
+ # The same model may be imported via different paths (e.g.
+ # appname.models and project.appname.models). We use the source
+ # filename as a means to detect identity.
+ fname1 = os.path.abspath(sys.modules[model.__module__].__file__)
+ fname2 = os.path.abspath(sys.modules[model_dict[model_name].__module__].__file__)
+ # Since the filename extension could be .py the first time and .pyc
+ # or .pyo the second time, ignore the extension when comparing.
+ if os.path.splitext(fname1)[0] == os.path.splitext(fname2)[0]:
+ continue
model_dict[model_name] = model
diff --git a/django/db/models/options.py b/django/db/models/options.py
index f8149bdf5c..46a321f170 100644
--- a/django/db/models/options.py
+++ b/django/db/models/options.py
@@ -87,7 +87,10 @@ class Options(object):
def __repr__(self):
return '<Options for %s>' % self.object_name
-
+
+ def __str__(self):
+ return "%s.%s" % (self.app_label, self.module_name)
+
def get_field(self, name, many_to_many=True):
"Returns the requested field by name. Raises FieldDoesNotExist on error."
to_search = many_to_many and (self.fields + self.many_to_many) or self.fields
diff --git a/docs/faq.txt b/docs/faq.txt
index adcdbaca59..37e15878f2 100644
--- a/docs/faq.txt
+++ b/docs/faq.txt
@@ -301,16 +301,18 @@ PostgreSQL fans, and MySQL_ and `SQLite 3`_ are also supported.
Do I have to use mod_python?
----------------------------
-Not if you just want to play around and develop things on your local computer.
-Django comes with its own Web server, and things should Just Work.
+Although we recommend mod_python for production use, you don't have to use it,
+thanks to the fact that Django uses an arrangement called WSGI_. Django can
+talk to any WSGI-enabled server. The most common non-mod_python deployment
+setup is FastCGI. See `How to use Django with FastCGI`_ for full information.
-For production use, though, we recommend mod_python. The Django developers have
-been running it on mod_python for several years, and it's quite stable.
+Also, see the `server arrangements wiki page`_ for other deployment strategies.
-However, if you don't want to use mod_python, you can use a different server,
-as long as that server has WSGI_ hooks. See the `server arrangements wiki page`_.
+If you just want to play around and develop things on your local computer, use
+the development Web server that comes with Django. Things should Just Work.
.. _WSGI: http://www.python.org/peps/pep-0333.html
+.. _How to use Django with FastCGI: http://www.djangoproject.com/documentation/fastcgi/
.. _server arrangements wiki page: http://code.djangoproject.com/wiki/ServerArrangements
How do I install mod_python on Windows?
diff --git a/docs/fastcgi.txt b/docs/fastcgi.txt
index 41b9561b6d..41d50d97a1 100644
--- a/docs/fastcgi.txt
+++ b/docs/fastcgi.txt
@@ -2,7 +2,7 @@
How to use Django with FastCGI
==============================
-Although the current preferred setup for running Django is Apache_ with
+Although the `current preferred setup`_ for running Django is Apache_ with
`mod_python`_, many people use shared hosting, on which FastCGI is the only
viable option. In some setups, FastCGI also allows better security -- and,
possibly, better performance -- than mod_python.
@@ -17,6 +17,7 @@ served with no startup time. Unlike mod_python (or `mod_perl`_), a FastCGI
process doesn't run inside the Web server process, but in a separate,
persistent process.
+.. _current preferred setup: http://www.djangoproject.com/documentation/modpython/
.. _Apache: http://httpd.apache.org/
.. _mod_python: http://www.modpython.org/
.. _mod_perl: http://perl.apache.org/
@@ -35,6 +36,16 @@ persistent process.
security benefit on shared systems, because it means you can secure your
code from other users.
+Prerequisite: flup
+==================
+
+Before you can start using FastCGI with Django, you'll need to install flup_,
+which is a Python library for dealing with FastCGI. Make sure to use the latest
+Subversion snapshot of flup, as some users have reported stalled pages with
+older flup versions.
+
+.. _flup: http://www.saddi.com/software/flup/
+
Starting your FastCGI server
============================
@@ -120,18 +131,53 @@ Apache setup
============
To use Django with Apache and FastCGI, you'll need Apache installed and
-configured, with mod_fastcgi installed and enabled. Consult the Apache
+configured, with `mod_fastcgi`_ installed and enabled. Consult the Apache
documentation for instructions.
-Add the following to your ``httpd.conf``::
+Once you've got that set up, point Apache at your Django FastCGI instance by
+editing the ``httpd.conf`` (Apache configuration) file. You'll need to do two
+things:
+
+ * Use the ``FastCGIExternalServer`` directive to specify the location of
+ your FastCGI server.
+ * Use ``mod_rewrite`` to point URLs at FastCGI as appropriate.
+
+.. _mod_fastcgi: http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html
+
+Specifying the location of the FastCGI server
+---------------------------------------------
+
+The ``FastCGIExternalServer`` directive tells Apache how to find your FastCGI
+server. As the `FastCGIExternalServer docs`_ explain, you can specify either a
+``socket`` or a ``host``. Here are examples of both::
- # Connect to FastCGI via a socket / named pipe
+ # Connect to FastCGI via a socket / named pipe.
FastCGIExternalServer /home/user/public_html/mysite.fcgi -socket /home/user/mysite.sock
- # Connect to FastCGI via a TCP host/port
- # FastCGIExternalServer /home/user/public_html/mysite.fcgi -host 127.0.0.1:3033
- <VirtualHost 64.92.160.91>
- ServerName mysite.com
+ # Connect to FastCGI via a TCP host/port.
+ FastCGIExternalServer /home/user/public_html/mysite.fcgi -host 127.0.0.1:3033
+
+In either case, the file ``/home/user/public_html/mysite.fcgi`` doesn't
+actually have to exist. It's just a URL used by the Web server internally -- a
+hook for signifying which requests at a URL should be handled by FastCGI. (More
+on this in the next section.)
+
+.. _FastCGIExternalServer docs: http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html#FastCgiExternalServer
+
+Using mod_rewrite to point URLs at FastCGI
+------------------------------------------
+
+The second step is telling Apache to use FastCGI for URLs that match a certain
+pattern. To do this, use the `mod_rewrite`_ module and rewrite URLs to
+``mysite.fcgi`` (or whatever you specified in the ``FastCGIExternalServer``
+directive, as explained in the previous section).
+
+In this example, we tell Apache to use FastCGI to handle any request that
+doesn't represent a file on the filesystem and doesn't start with ``/media/``.
+This is probably the most common case, if you're using Django's admin site::
+
+ <VirtualHost 12.34.56.78>
+ ServerName example.com
DocumentRoot /home/user/public_html
Alias /media /home/user/python/django/contrib/admin/media
RewriteEngine On
@@ -140,22 +186,18 @@ Add the following to your ``httpd.conf``::
RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L]
</VirtualHost>
-Note that while you have to specify a mysite.fcgi, that this file doesn't
-actually have to exist. It is just an internal URL to the webserver which
-signifies that any requests to that URL will go to the external FastCGI
-server.
+.. _mod_rewrite: http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html
-LigHTTPd Setup
+lighttpd setup
==============
-LigHTTPd is a light-weight asynchronous web-server, which is commonly used
-for serving static files. However, it supports FastCGI natively, and as such
-is a very good choice for serving both static and dynamic media, if your site
-does not have any apache-specific components.
+lighttpd is a lightweight Web server commonly used for serving static files. It
+supports FastCGI natively and, thus, is a good choice for serving both static
+and dynamic pages, if your site doesn't have any Apache-specific needs.
Make sure ``mod_fastcgi`` is in your modules list, somewhere after
-mod_rewrite and mod_access, but not after mod_accesslog. You'll probably
-want mod_alias as well, for serving admin media.
+``mod_rewrite`` and ``mod_access``, but not after ``mod_accesslog``. You'll
+probably want ``mod_alias`` as well, for serving admin media.
Add the following to your lighttpd config file::
@@ -165,7 +207,7 @@ Add the following to your lighttpd config file::
"main" => (
# Use host / port instead of socket for TCP fastcgi
# "host" => "127.0.0.1",
- # "port" => 3033,
+ # "port" => 3033,
"socket" => "/home/user/mysite.sock",
"check-local" => "disable",
)
@@ -181,14 +223,15 @@ Add the following to your lighttpd config file::
"^(/.*)$" => "/mysite.fcgi$1",
)
-Running multiple django sites on one LigHTTPd
+Running multiple Django sites on one lighttpd
---------------------------------------------
-LigHTTPd allows you to use what is called conditional configuration to allow
-configuration to be customized per-host. In order to specify multiple fastcgi
-sites, simply add a conditional block around your fastcgi config for each site::
+lighttpd lets you use "conditional configuration" to allow configuration to be
+customized per host. To specify multiple FastCGI sites, just add a conditional
+block around your FastCGI config for each site::
- $HTTP["host"] == "www.website1.com" {
+ # If the hostname is 'www.example1.com'...
+ $HTTP["host"] == "www.example1.com" {
server.document-root = "/foo/site1"
fastcgi.server = (
...
@@ -196,7 +239,8 @@ sites, simply add a conditional block around your fastcgi config for each site::
...
}
- $HTTP["host"] == "www.website2.com" {
+ # If the hostname is 'www.example2.com'...
+ $HTTP["host"] == "www.example2.com" {
server.document-root = "/foo/site2"
fastcgi.server = (
...
@@ -204,44 +248,44 @@ sites, simply add a conditional block around your fastcgi config for each site::
...
}
-You can also run multiple django installations on the same site simply by
-specifying multiple entries in the ``fastcgi.server`` directive, add one
-fastcgi host for each.
+You can also run multiple Django installations on the same site simply by
+specifying multiple entries in the ``fastcgi.server`` directive. Add one
+FastCGI host for each.
-Running Django on a shared-hosting provider
-===========================================
+Running Django on a shared-hosting provider with Apache
+=======================================================
-For many users on shared-hosting providers, you aren't able to run your own
-server daemons nor do they have access to the httpd.conf of their webserver.
-However, it is still possible to run Django using webserver-spawned processes.
+Many shared-hosting providers don't allow you to run your own server daemons or
+edit the ``httpd.conf`` file. In these cases, it's still possible to run Django
+using Web server-spawned processes.
.. admonition:: Note
- If you are using webserver-managed processes, there's no need for you
- to start the FastCGI server on your own. Apache will spawn a number
- of processes, scaling as it needs to.
+ If you're using Web server-spawned processes, as explained in this section,
+ there's no need for you to start the FastCGI server on your own. Apache
+ will spawn a number of processes, scaling as it needs to.
-In your web root directory, add this to a file named .htaccess ::
+In your Web root directory, add this to a file named ``.htaccess`` ::
AddHandler fastcgi-script .fcgi
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L]
-Now you must add a small shim script in order for apache to properly
-spawn your FastCGI program. Create a mysite.fcgi and place it in your
-web directory, making it executable ::
+Then, create a small script that tells Apache how to spawn your FastCGI
+program. Create a file ``mysite.fcgi`` and place it in your Web directory, and
+be sure to make it executable ::
#!/usr/bin/python
import sys, os
- # add a custom pythonpath
+ # Add a custom Python path.
sys.path.insert(0, "/home/user/python")
- # switch to the directory of your project. (optional)
+ # Switch to the directory of your project. (Optional.)
# os.chdir("/home/user/myproject")
- # change to the name of your app's settings module
+ # Set the DJANGO_SETTINGS_MODULE environment variable.
os.environ['DJANGO_SETTINGS_MODULE'] = "myproject.settings"
from django.core.servers.fastcgi import runfastcgi
@@ -250,13 +294,13 @@ web directory, making it executable ::
Restarting the spawned server
-----------------------------
-If you change the code of your site, to make apache re-load your django
-application, you do not need to restart the server. Simply re-upload or
-edit your ``mysite.fcgi`` in such a way that the timestamp on the file
-will change. When apache sees that the file has been updated, it will
-restart your django application for you.
+If you change any Python code on your site, you'll need to tell FastCGI the
+code has changed. But there's no need to restart Apache in this case. Rather,
+just reupload ``mysite.fcgi``, or edit the file, so that the timestamp on the
+file will change. When Apache sees the file has been updated, it will restart
+your Django application for you.
-If you have access to a command shell on a unix system, restarting the
-server can be done with the ``touch`` command::
+If you have access to a command shell on a Unix system, you can accomplish this
+easily by using the ``touch`` command::
touch mysite.fcgi
diff --git a/docs/modpython.txt b/docs/modpython.txt
index 0c0219e2e9..b88874d3d3 100644
--- a/docs/modpython.txt
+++ b/docs/modpython.txt
@@ -10,15 +10,17 @@ Python code into memory when the server starts. Code stays in memory throughout
the life of an Apache process, which leads to significant performance gains over
other server arrangements.
-Django requires Apache 2.x and mod_python 3.x.
+Django requires Apache 2.x and mod_python 3.x, and you should use Apache's
+`prefork MPM`_, as opposed to the `worker MPM`_.
-We recommend you use Apache's `prefork MPM`_, as opposed to the `worker MPM`_.
+You may also be interested in `How to use Django with FastCGI`_.
.. _Apache: http://httpd.apache.org/
.. _mod_python: http://www.modpython.org/
.. _mod_perl: http://perl.apache.org/
.. _prefork MPM: http://httpd.apache.org/docs/2.2/mod/prefork.html
.. _worker MPM: http://httpd.apache.org/docs/2.2/mod/worker.html
+.. _How to use Django with FastCGI: http://www.djangoproject.com/documentation/fastcgi/
Basic configuration
===================
diff --git a/docs/syndication_feeds.txt b/docs/syndication_feeds.txt
index 4f77c4ff21..c84785b20b 100644
--- a/docs/syndication_feeds.txt
+++ b/docs/syndication_feeds.txt
@@ -134,7 +134,9 @@ put into those elements.
If you don't create a template for either the title or description, the
framework will use the template ``"{{ obj }}"`` by default -- that is,
- the normal string representation of the object.
+ the normal string representation of the object. You can also change the
+ names of these two templates by specifying ``title_template`` and
+ ``description_template`` as attributes of your ``Feed`` class.
* To specify the contents of ``<link>``, you have two options. For each
item in ``items()``, Django first tries executing a
``get_absolute_url()`` method on that object. If that method doesn't
@@ -342,6 +344,16 @@ This example illustrates all possible attributes and methods for a ``Feed`` clas
feed_type = feedgenerator.Rss201rev2Feed
+ # TEMPLATE NAMES -- Optional. These should be strings representing
+ # names of Django templates that the system should use in rendering the
+ # title and description of your feed items. Both are optional.
+ # If you don't specify one, or either, Django will use the template
+ # 'feeds/SLUG_title.html' and 'feeds/SLUG_description.html', where SLUG
+ # is the slug you specify in the URL.
+
+ title_template = None
+ description_template = None
+
# TITLE -- One of the following three is required. The framework looks
# for them in this order.
diff --git a/docs/templates_python.txt b/docs/templates_python.txt
index 5e3038ebb4..2fa837e424 100644
--- a/docs/templates_python.txt
+++ b/docs/templates_python.txt
@@ -783,7 +783,7 @@ Our earlier ``current_time`` function could thus be written like this::
In Python 2.4, the decorator syntax also works::
- @simple_tag
+ @register.simple_tag
def do_current_time(token):
...
@@ -844,7 +844,7 @@ loader, we'd register the tag like this::
As always, Python 2.4 decorator syntax works as well, so we could have
written::
- @inclusion_tag('results.html')
+ @register.inclusion_tag('results.html')
def show_results(poll):
...
diff --git a/tests/modeltests/invalid_models/models.py b/tests/modeltests/invalid_models/models.py
index 1720dd96d3..eb305b4e92 100644
--- a/tests/modeltests/invalid_models/models.py
+++ b/tests/modeltests/invalid_models/models.py
@@ -17,17 +17,19 @@ class FieldErrors(models.Model):
class Target(models.Model):
tgt_safe = models.CharField(maxlength=10)
+ clash1 = models.CharField(maxlength=10)
+ clash2 = models.CharField(maxlength=10)
clash1_set = models.CharField(maxlength=10)
class Clash1(models.Model):
- src_safe = models.CharField(maxlength=10)
+ src_safe = models.CharField(maxlength=10, core=True)
foreign = models.ForeignKey(Target)
m2m = models.ManyToManyField(Target)
class Clash2(models.Model):
- src_safe = models.CharField(maxlength=10)
+ src_safe = models.CharField(maxlength=10, core=True)
foreign_1 = models.ForeignKey(Target, related_name='id')
foreign_2 = models.ForeignKey(Target, related_name='src_safe')
@@ -36,6 +38,7 @@ class Clash2(models.Model):
m2m_2 = models.ManyToManyField(Target, related_name='src_safe')
class Target2(models.Model):
+ clash3 = models.CharField(maxlength=10)
foreign_tgt = models.ForeignKey(Target)
clashforeign_set = models.ForeignKey(Target)
@@ -43,6 +46,8 @@ class Target2(models.Model):
clashm2m_set = models.ManyToManyField(Target)
class Clash3(models.Model):
+ src_safe = models.CharField(maxlength=10, core=True)
+
foreign_1 = models.ForeignKey(Target2, related_name='foreign_tgt')
foreign_2 = models.ForeignKey(Target2, related_name='m2m_tgt')
@@ -56,7 +61,8 @@ class ClashM2M(models.Model):
m2m = models.ManyToManyField(Target2)
class SelfClashForeign(models.Model):
- src_safe = models.CharField(maxlength=10)
+ src_safe = models.CharField(maxlength=10, core=True)
+ selfclashforeign = models.CharField(maxlength=10)
selfclashforeign_set = models.ForeignKey("SelfClashForeign")
foreign_1 = models.ForeignKey("SelfClashForeign", related_name='id')
@@ -64,11 +70,14 @@ class SelfClashForeign(models.Model):
class SelfClashM2M(models.Model):
src_safe = models.CharField(maxlength=10)
+ selfclashm2m = models.CharField(maxlength=10)
selfclashm2m_set = models.ManyToManyField("SelfClashM2M")
m2m_1 = models.ManyToManyField("SelfClashM2M", related_name='id')
m2m_2 = models.ManyToManyField("SelfClashM2M", related_name='src_safe')
+
+
error_log = """invalid_models.fielderrors: "charfield": CharFields require a "maxlength" attribute.
invalid_models.fielderrors: "floatfield": FloatFields require a "decimal_places" attribute.
invalid_models.fielderrors: "floatfield": FloatFields require a "max_digits" attribute.
@@ -78,42 +87,69 @@ invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tup
invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples.
invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples.
invalid_models.fielderrors: "index": "db_index" should be either None, True or False.
-invalid_models.clash1: 'foreign' accessor name 'Target.clash1_set' clashes with another field. Add a related_name argument to the definition for 'foreign'.
-invalid_models.clash1: 'foreign' accessor name 'Target.clash1_set' clashes with a related m2m field. Add a related_name argument to the definition for 'foreign'.
-invalid_models.clash1: 'm2m' m2m accessor name 'Target.clash1_set' clashes with another field. Add a related_name argument to the definition for 'm2m'.
-invalid_models.clash1: 'm2m' m2m accessor name 'Target.clash1_set' clashes with another related field. Add a related_name argument to the definition for 'm2m'.
-invalid_models.clash2: 'foreign_1' accessor name 'Target.id' clashes with another field. Add a related_name argument to the definition for 'foreign_1'.
-invalid_models.clash2: 'foreign_1' accessor name 'Target.id' clashes with a related m2m field. Add a related_name argument to the definition for 'foreign_1'.
-invalid_models.clash2: 'foreign_2' accessor name 'Target.src_safe' clashes with a related m2m field. Add a related_name argument to the definition for 'foreign_2'.
-invalid_models.clash2: 'm2m_1' m2m accessor name 'Target.id' clashes with another field. Add a related_name argument to the definition for 'm2m_1'.
-invalid_models.clash2: 'm2m_1' m2m accessor name 'Target.id' clashes with another related field. Add a related_name argument to the definition for 'm2m_1'.
-invalid_models.clash2: 'm2m_2' m2m accessor name 'Target.src_safe' clashes with another related field. Add a related_name argument to the definition for 'm2m_2'.
-invalid_models.clash3: 'foreign_1' accessor name 'Target2.foreign_tgt' clashes with another field. Add a related_name argument to the definition for 'foreign_1'.
-invalid_models.clash3: 'foreign_1' accessor name 'Target2.foreign_tgt' clashes with a related m2m field. Add a related_name argument to the definition for 'foreign_1'.
-invalid_models.clash3: 'foreign_2' accessor name 'Target2.m2m_tgt' clashes with a m2m field. Add a related_name argument to the definition for 'foreign_2'.
-invalid_models.clash3: 'foreign_2' accessor name 'Target2.m2m_tgt' clashes with a related m2m field. Add a related_name argument to the definition for 'foreign_2'.
-invalid_models.clash3: 'm2m_1' m2m accessor name 'Target2.foreign_tgt' clashes with another field. Add a related_name argument to the definition for 'm2m_1'.
-invalid_models.clash3: 'm2m_1' m2m accessor name 'Target2.foreign_tgt' clashes with another related field. Add a related_name argument to the definition for 'm2m_1'.
-invalid_models.clash3: 'm2m_2' m2m accessor name 'Target2.m2m_tgt' clashes with a m2m field. Add a related_name argument to the definition for 'm2m_2'.
-invalid_models.clash3: 'm2m_2' m2m accessor name 'Target2.m2m_tgt' clashes with another related field. Add a related_name argument to the definition for 'm2m_2'.
-invalid_models.clashforeign: 'foreign' accessor name 'Target2.clashforeign_set' clashes with another field. Add a related_name argument to the definition for 'foreign'.
-invalid_models.clashm2m: 'm2m' m2m accessor name 'Target2.clashm2m_set' clashes with a m2m field. Add a related_name argument to the definition for 'm2m'.
-invalid_models.target2: 'foreign_tgt' accessor name 'Target.target2_set' clashes with a related m2m field. Add a related_name argument to the definition for 'foreign_tgt'.
-invalid_models.target2: 'foreign_tgt' accessor name 'Target.target2_set' clashes with a related m2m field. Add a related_name argument to the definition for 'foreign_tgt'.
-invalid_models.target2: 'foreign_tgt' accessor name 'Target.target2_set' clashes with another related field. Add a related_name argument to the definition for 'foreign_tgt'.
-invalid_models.target2: 'clashforeign_set' accessor name 'Target.target2_set' clashes with a related m2m field. Add a related_name argument to the definition for 'clashforeign_set'.
-invalid_models.target2: 'clashforeign_set' accessor name 'Target.target2_set' clashes with a related m2m field. Add a related_name argument to the definition for 'clashforeign_set'.
-invalid_models.target2: 'clashforeign_set' accessor name 'Target.target2_set' clashes with another related field. Add a related_name argument to the definition for 'clashforeign_set'.
-invalid_models.target2: 'm2m_tgt' m2m accessor name 'Target.target2_set' clashes with a related m2m field. Add a related_name argument to the definition for 'm2m_tgt'.
-invalid_models.target2: 'm2m_tgt' m2m accessor name 'Target.target2_set' clashes with another related field. Add a related_name argument to the definition for 'm2m_tgt'.
-invalid_models.target2: 'm2m_tgt' m2m accessor name 'Target.target2_set' clashes with another related field. Add a related_name argument to the definition for 'm2m_tgt'.
-invalid_models.target2: 'clashm2m_set' m2m accessor name 'Target.target2_set' clashes with a related m2m field. Add a related_name argument to the definition for 'clashm2m_set'.
-invalid_models.target2: 'clashm2m_set' m2m accessor name 'Target.target2_set' clashes with another related field. Add a related_name argument to the definition for 'clashm2m_set'.
-invalid_models.target2: 'clashm2m_set' m2m accessor name 'Target.target2_set' clashes with another related field. Add a related_name argument to the definition for 'clashm2m_set'.
-invalid_models.selfclashforeign: 'selfclashforeign_set' accessor name 'SelfClashForeign.selfclashforeign_set' clashes with another field. Add a related_name argument to the definition for 'selfclashforeign_set'.
-invalid_models.selfclashforeign: 'foreign_1' accessor name 'SelfClashForeign.id' clashes with another field. Add a related_name argument to the definition for 'foreign_1'.
-invalid_models.selfclashforeign: 'foreign_2' accessor name 'SelfClashForeign.src_safe' clashes with another field. Add a related_name argument to the definition for 'foreign_2'.
-invalid_models.selfclashm2m: 'selfclashm2m_set' m2m accessor name 'SelfClashM2M.selfclashm2m_set' clashes with a m2m field. Add a related_name argument to the definition for 'selfclashm2m_set'.
-invalid_models.selfclashm2m: 'm2m_1' m2m accessor name 'SelfClashM2M.id' clashes with another field. Add a related_name argument to the definition for 'm2m_1'.
-invalid_models.selfclashm2m: 'm2m_2' m2m accessor name 'SelfClashM2M.src_safe' clashes with another field. Add a related_name argument to the definition for 'm2m_2'.
+invalid_models.clash1: Accessor for field 'foreign' clashes with field 'Target.clash1_set'. Add a related_name argument to the definition for 'foreign'.
+invalid_models.clash1: Accessor for field 'foreign' clashes with related m2m field 'Target.clash1_set'. Add a related_name argument to the definition for 'foreign'.
+invalid_models.clash1: Reverse query name for field 'foreign' clashes with field 'Target.clash1'. Add a related_name argument to the definition for 'foreign'.
+invalid_models.clash1: Accessor for m2m field 'm2m' clashes with field 'Target.clash1_set'. Add a related_name argument to the definition for 'm2m'.
+invalid_models.clash1: Accessor for m2m field 'm2m' clashes with related field 'Target.clash1_set'. Add a related_name argument to the definition for 'm2m'.
+invalid_models.clash1: Reverse query name for m2m field 'm2m' clashes with field 'Target.clash1'. Add a related_name argument to the definition for 'm2m'.
+invalid_models.clash2: Accessor for field 'foreign_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'.
+invalid_models.clash2: Accessor for field 'foreign_1' clashes with related m2m field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'.
+invalid_models.clash2: Reverse query name for field 'foreign_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'.
+invalid_models.clash2: Reverse query name for field 'foreign_1' clashes with related m2m field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'.
+invalid_models.clash2: Accessor for field 'foreign_2' clashes with related m2m field 'Target.src_safe'. Add a related_name argument to the definition for 'foreign_2'.
+invalid_models.clash2: Reverse query name for field 'foreign_2' clashes with related m2m field 'Target.src_safe'. Add a related_name argument to the definition for 'foreign_2'.
+invalid_models.clash2: Accessor for m2m field 'm2m_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'm2m_1'.
+invalid_models.clash2: Accessor for m2m field 'm2m_1' clashes with related field 'Target.id'. Add a related_name argument to the definition for 'm2m_1'.
+invalid_models.clash2: Reverse query name for m2m field 'm2m_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'm2m_1'.
+invalid_models.clash2: Reverse query name for m2m field 'm2m_1' clashes with related field 'Target.id'. Add a related_name argument to the definition for 'm2m_1'.
+invalid_models.clash2: Accessor for m2m field 'm2m_2' clashes with related field 'Target.src_safe'. Add a related_name argument to the definition for 'm2m_2'.
+invalid_models.clash2: Reverse query name for m2m field 'm2m_2' clashes with related field 'Target.src_safe'. Add a related_name argument to the definition for 'm2m_2'.
+invalid_models.clash3: Accessor for field 'foreign_1' clashes with field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'foreign_1'.
+invalid_models.clash3: Accessor for field 'foreign_1' clashes with related m2m field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'foreign_1'.
+invalid_models.clash3: Reverse query name for field 'foreign_1' clashes with field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'foreign_1'.
+invalid_models.clash3: Reverse query name for field 'foreign_1' clashes with related m2m field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'foreign_1'.
+invalid_models.clash3: Accessor for field 'foreign_2' clashes with m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'foreign_2'.
+invalid_models.clash3: Accessor for field 'foreign_2' clashes with related m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'foreign_2'.
+invalid_models.clash3: Reverse query name for field 'foreign_2' clashes with m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'foreign_2'.
+invalid_models.clash3: Reverse query name for field 'foreign_2' clashes with related m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'foreign_2'.
+invalid_models.clash3: Accessor for m2m field 'm2m_1' clashes with field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'm2m_1'.
+invalid_models.clash3: Accessor for m2m field 'm2m_1' clashes with related field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'm2m_1'.
+invalid_models.clash3: Reverse query name for m2m field 'm2m_1' clashes with field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'm2m_1'.
+invalid_models.clash3: Reverse query name for m2m field 'm2m_1' clashes with related field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'm2m_1'.
+invalid_models.clash3: Accessor for m2m field 'm2m_2' clashes with m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'm2m_2'.
+invalid_models.clash3: Accessor for m2m field 'm2m_2' clashes with related field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'm2m_2'.
+invalid_models.clash3: Reverse query name for m2m field 'm2m_2' clashes with m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'm2m_2'.
+invalid_models.clash3: Reverse query name for m2m field 'm2m_2' clashes with related field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'm2m_2'.
+invalid_models.clashforeign: Accessor for field 'foreign' clashes with field 'Target2.clashforeign_set'. Add a related_name argument to the definition for 'foreign'.
+invalid_models.clashm2m: Accessor for m2m field 'm2m' clashes with m2m field 'Target2.clashm2m_set'. Add a related_name argument to the definition for 'm2m'.
+invalid_models.target2: Accessor for field 'foreign_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'foreign_tgt'.
+invalid_models.target2: Accessor for field 'foreign_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'foreign_tgt'.
+invalid_models.target2: Accessor for field 'foreign_tgt' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'foreign_tgt'.
+invalid_models.target2: Accessor for field 'clashforeign_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashforeign_set'.
+invalid_models.target2: Accessor for field 'clashforeign_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashforeign_set'.
+invalid_models.target2: Accessor for field 'clashforeign_set' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'clashforeign_set'.
+invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'.
+invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'.
+invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'.
+invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'.
+invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'.
+invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'.
+invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'.
+invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'.
+invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'.
+invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'.
+invalid_models.selfclashforeign: Accessor for field 'selfclashforeign_set' clashes with field 'SelfClashForeign.selfclashforeign_set'. Add a related_name argument to the definition for 'selfclashforeign_set'.
+invalid_models.selfclashforeign: Reverse query name for field 'selfclashforeign_set' clashes with field 'SelfClashForeign.selfclashforeign'. Add a related_name argument to the definition for 'selfclashforeign_set'.
+invalid_models.selfclashforeign: Accessor for field 'foreign_1' clashes with field 'SelfClashForeign.id'. Add a related_name argument to the definition for 'foreign_1'.
+invalid_models.selfclashforeign: Reverse query name for field 'foreign_1' clashes with field 'SelfClashForeign.id'. Add a related_name argument to the definition for 'foreign_1'.
+invalid_models.selfclashforeign: Accessor for field 'foreign_2' clashes with field 'SelfClashForeign.src_safe'. Add a related_name argument to the definition for 'foreign_2'.
+invalid_models.selfclashforeign: Reverse query name for field 'foreign_2' clashes with field 'SelfClashForeign.src_safe'. Add a related_name argument to the definition for 'foreign_2'.
+invalid_models.selfclashm2m: Accessor for m2m field 'selfclashm2m_set' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'selfclashm2m_set'.
+invalid_models.selfclashm2m: Reverse query name for m2m field 'selfclashm2m_set' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'selfclashm2m_set'.
+invalid_models.selfclashm2m: Accessor for m2m field 'm2m_1' clashes with field 'SelfClashM2M.id'. Add a related_name argument to the definition for 'm2m_1'.
+invalid_models.selfclashm2m: Accessor for m2m field 'm2m_2' clashes with field 'SelfClashM2M.src_safe'. Add a related_name argument to the definition for 'm2m_2'.
+invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_1' clashes with field 'SelfClashM2M.id'. Add a related_name argument to the definition for 'm2m_1'.
+invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_2' clashes with field 'SelfClashM2M.src_safe'. Add a related_name argument to the definition for 'm2m_2'.
"""
+
diff --git a/tests/modeltests/m2m_recursive/models.py b/tests/modeltests/m2m_recursive/models.py
index c109b9cc2c..dace32d565 100644
--- a/tests/modeltests/m2m_recursive/models.py
+++ b/tests/modeltests/m2m_recursive/models.py
@@ -2,7 +2,7 @@
27. Many-to-many relationships between the same two tables
In this example, A Person can have many friends, who are also people. Friendship is a
-symmetrical relationshiup - if I am your friend, you are my friend.
+symmetrical relationship - if I am your friend, you are my friend.
A person can also have many idols - but while I may idolize you, you may not think
the same of me. 'Idols' is an example of a non-symmetrical m2m field. Only recursive