From 54b6e969571576e9ec616df8b074f744009b35cc Mon Sep 17 00:00:00 2001 From: Jason Pellerin Date: Wed, 28 Jun 2006 17:00:52 +0000 Subject: [PATCH] Merge trunk to [3216] git-svn-id: http://code.djangoproject.com/svn/django/branches/multiple-db-support@3227 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- .../conf/locale/es_AR/LC_MESSAGES/django.mo | Bin 32307 -> 33953 bytes .../conf/locale/es_AR/LC_MESSAGES/django.po | 359 +++++++++++------- .../conf/locale/es_AR/LC_MESSAGES/djangojs.mo | Bin 1474 -> 1566 bytes .../conf/locale/es_AR/LC_MESSAGES/djangojs.po | 43 ++- .../conf/locale/zh_CN/LC_MESSAGES/djangojs.po | 107 ++++++ django/contrib/admin/views/doc.py | 16 +- .../comments/templates/comments/form.html | 8 +- .../comments/templates/comments/freeform.html | 4 +- django/contrib/syndication/feeds.py | 16 +- django/core/management.py | 52 ++- django/db/models/base.py | 8 +- django/db/models/loading.py | 31 +- django/db/models/options.py | 5 +- docs/faq.txt | 14 +- docs/fastcgi.txt | 146 ++++--- docs/modpython.txt | 6 +- docs/syndication_feeds.txt | 14 +- docs/templates_python.txt | 4 +- tests/modeltests/invalid_models/models.py | 118 ++++-- tests/modeltests/m2m_recursive/models.py | 2 +- 20 files changed, 654 insertions(+), 299 deletions(-) create mode 100644 django/conf/locale/zh_CN/LC_MESSAGES/djangojs.po diff --git a/django/conf/locale/es_AR/LC_MESSAGES/django.mo b/django/conf/locale/es_AR/LC_MESSAGES/django.mo index 463078025c4ea3ef93f263d66f71850ad08cb3d8..f550fca3dbbe2777e53d0fce67ae582261486799 100644 GIT binary patch delta 10251 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 delta 8812 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\n" -"Language-Team: Spanish \n" +"Language-Team: Spanish \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 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 #: 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 #: 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 "" "
    \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 " #: 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/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/main.py:743 +msgid "Database error" +msgstr "Error de base de datos" + +#: 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 #: 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 #: 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 #: 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 #: 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 msgid "Have you forgotten your password?" msgstr "¿Ha olvidado su contraseñ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 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 #: 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 e48292825b3eedca8ce6e3fab7426846b4a39985..f24c9a12d0149e5c95d6f13e2fb1e178d2bbfb80 100644 GIT binary patch delta 674 zcmZ9}%_~Gv7{~E5Gk3g>!FZQ4$t)*xy@hOvB&8H9iHXs0Yi49&%5GLln(QQ{EJP{! z2V^VRQL>eVvay(*?@xz?(>&*MUgkc}J?Gw5ABT2dBhI0rwGth~3lSrZd~~#g-V3RkfbGuAu?nHSK(J)ARU*BmfVqBpzoi7NDkDqKP()?yUG zs02MYg#D<*8>l>4RN*{!a)<&d&lwMu<0Xdi2CJxV?ilF72fOiv^~~R}8cTLPNEH=o zq*J1HoX0NIiFZ(W3dqmw+xa2t0LR#k7pUhSv7h?pnE@|p!n~&5G(tyB(}wyAZ2w$2 zm_|ay^tqH&|5s5povN8o^8c;LF4SRz9jk`hLZ{*pyU1;uT0%FVrmNH~{I%kTZ_$}Z ztt5+6{*%C(w_SYqpVtk>6N7PgIO_I}xC8M--}Pz0@g*|RoVVg-O)MKtrjx5FjmOfd jjnwAS@78QG?X8=c<*jsXDO0?6uF9vqY%aq%9~}P%xO_(1 delta 597 zcmY+>%_~Gv7{~E5Z{B7w#!D%3?|yNf7e)e>bakL&Y5$b=gd6}-3QCB5&ym++Q<&_iR>h|JUoaG ztin(9;TMMR8*8xE`@0^&ddBTohXYuP@rp?dFrLN*oJIDR%`q>2CQeZW&QS%gPzTWQM_^}!oM7I!j(Nq$(e~Ck@aTyzM4b|8tYTu4KUp8i!moO6t7{oJF;Tu$; z2VBHwbZ^F_4v3@HCoAJA)V>+)#YG&!ZKNl2fokj;Im+Cjhx+cI75_q?g0+9q$Vg4< zAl)`Xs+bzlE%{U2&!PglZ422pd?TLgvG;CkK`~04MYonMcmP}vC%I32xIlZUyxk7F|U0IpW=8LONci`N438a1i D800*1 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 \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 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 , 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 \n" +"Language-Team: LANGUAGE \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 @@
    {% if user.is_anonymous %} -

    {% trans "Username:" %}
    {% trans "Password:" %} ({% trans "Forgotten your password?" %})

    +


    {% trans "Password:" %} ({% trans "Forgotten your password?" %})

    {% else %}

    {% trans "Username:" %} {{ user.username }} ({% trans "Log out" %})

    {% endif %} @@ -20,11 +20,13 @@ {% endif %} {% if photos_optional or photos_required %} -

    {% trans "Post a photo" %} ({% if photos_required %}{% trans "Required" %}{% else %}{% trans "Optional" %}{% endif %}):

    +

    ({% if photos_required %}{% trans "Required" %}{% else %}{% trans "Optional" %}{% endif %}): +

    {% endif %} -

    {% trans "Comment:" %}

    +


    +

    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 %} -

    {% trans "Your name:" %}

    -

    {% trans "Comment:" %}

    +

    +


    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 '' % 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: - # Connect to FastCGI via a socket / named pipe + * 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. 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 - - 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:: + + + 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] -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 ````, 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