diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index 332af199f8..a1dff3c815 100644
--- a/django/conf/global_settings.py
+++ b/django/conf/global_settings.py
@@ -203,6 +203,16 @@ DATETIME_FORMAT = 'N j, Y, P'
# http://www.djangoproject.com/documentation/templates/#now
TIME_FORMAT = 'P'
+# Default formatting for date objects when only the year and month are relevant.
+# See all available format strings here:
+# http://www.djangoproject.com/documentation/templates/#now
+YEAR_MONTH_FORMAT = 'F Y'
+
+# Default formatting for date objects when only the month and day are relevant.
+# See all available format strings here:
+# http://www.djangoproject.com/documentation/templates/#now
+MONTH_DAY_FORMAT = 'F j'
+
# Whether to enable Psyco, which optimizes Python code. Requires Psyco.
# http://psyco.sourceforge.net/
ENABLE_PSYCO = False
diff --git a/django/conf/locale/nl/LC_MESSAGES/django.mo b/django/conf/locale/nl/LC_MESSAGES/django.mo
index fe87810b97..abc387aeea 100644
Binary files a/django/conf/locale/nl/LC_MESSAGES/django.mo and b/django/conf/locale/nl/LC_MESSAGES/django.mo differ
diff --git a/django/conf/locale/nl/LC_MESSAGES/django.po b/django/conf/locale/nl/LC_MESSAGES/django.po
index b137909b3a..bba721b56a 100644
--- a/django/conf/locale/nl/LC_MESSAGES/django.po
+++ b/django/conf/locale/nl/LC_MESSAGES/django.po
@@ -72,7 +72,7 @@ msgstr "Dit veld mag niet leeg zijn."
#: db/models/fields/__init__.py:468 core/validators.py:132
msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
-msgstr "Geef geldige datum/tijd in JJJJ-MM-DD HH:MM formaat."
+msgstr "Geef geldige datum/tijd in JJJJ-MM-DD UU:MM formaat."
#: db/models/fields/__init__.py:562
msgid "Enter a valid filename."
@@ -116,7 +116,7 @@ msgstr "Frans"
#: conf/global_settings.py:46
msgid "Galician"
-msgstr "Galisisch"
+msgstr "Galicisch"
#: conf/global_settings.py:47
msgid "Hungarian"
@@ -176,7 +176,7 @@ msgstr "Zweeds"
#: conf/global_settings.py:61
msgid "Ukrainian"
-msgstr "Ukraiens"
+msgstr "Oekraïens"
#: conf/global_settings.py:62
msgid "Simplified Chinese"
@@ -220,11 +220,11 @@ msgstr "Geef een geldig IP adres op."
#: core/validators.py:103
msgid "Empty values are not allowed here."
-msgstr "Lege waarden niet toegestaan."
+msgstr "Lege waarden zijn hier niet toegestaan."
#: core/validators.py:107
msgid "Non-numeric characters aren't allowed here."
-msgstr "Niet-numerieke karakters niet toegestaan."
+msgstr "Niet-numerieke karakters zijn hier niet toegestaan."
#: core/validators.py:111
msgid "This value can't be comprised solely of digits."
@@ -244,7 +244,7 @@ msgstr "Geef een geldige datum in JJJJ-MM-DD formaat."
#: core/validators.py:128
msgid "Enter a valid time in HH:MM format."
-msgstr "Geef een geldige tijd in HH:MM formaat."
+msgstr "Geef een geldige tijd in UU:MM formaat."
#: core/validators.py:136
msgid "Enter a valid e-mail address."
@@ -321,7 +321,7 @@ msgstr "Dit veld moet overeenkomen met het '%s' veld."
#: core/validators.py:255
msgid "Please enter something for at least one field."
-msgstr "Geef in minimaal één veld een waarde."
+msgstr "Voer tenminste één veld in."
#: core/validators.py:264 core/validators.py:275
msgid "Please enter both fields or leave them both empty."
@@ -355,26 +355,26 @@ msgstr "Geef een geldig decimaal getal."
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] "Geef een geldig decimaal getal met maximaal %s cijfer."
-msgstr[1] "Geef een geldig decimaal getal met maximaal %s cijfers."
+msgstr[0] "Geef een geldig decimaal getal met hooguit %s cijfer."
+msgstr[1] "Geef een geldig decimaal getal met hooguit %s cijfers."
#: core/validators.py:352
#, 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] "Geef een decimaal getal met maximaal %s cijfer achter de komma."
-msgstr[1] "Geef een decimaal getal met maximaal %s cijfers achter de komma."
+msgstr[0] "Geef een decimaal getal met hooguit %s cijfer achter de komma."
+msgstr[1] "Geef een decimaal getal met hooguit %s cijfers achter de komma."
#: core/validators.py:362
#, python-format
msgid "Make sure your uploaded file is at least %s bytes big."
-msgstr "Zorg ervoor dat het bestand minimaal %s bytes groot is."
+msgstr "Zorg ervoor dat het bestand minstens %s bytes groot is."
#: core/validators.py:363
#, python-format
msgid "Make sure your uploaded file is at most %s bytes big."
-msgstr "Zorg ervoor dat het bestand maximaal %s bytes groot is."
+msgstr "Zorg ervoor dat het bestand hoogstens %s bytes groot is."
#: core/validators.py:376
msgid "The format for this field is wrong."
@@ -456,7 +456,7 @@ msgid ""
"Your Web browser doesn't appear to have cookies enabled. Cookies are "
"required for logging in."
msgstr ""
-"Het lijkt erop dat uw browser geen cookies accepteerd. Om u aan te melden "
+"Het lijkt erop dat uw browser geen cookies accepteerd. Om aan te melden "
"moeten cookies worden geaccepteerd."
#: contrib/auth/forms.py:36 contrib/auth/forms.py:41
@@ -465,7 +465,7 @@ msgid ""
"Please enter a correct username and password. Note that both fields are case-"
"sensitive."
msgstr ""
-"Geef een correcte gebruikersnaam en wachtwoord. Let op de velden zijn "
+"Voer een correcte gebruikersnaam en wachtwoord in. Let op, de velden zijn "
"hoofdletter-gevoelig."
#: contrib/auth/models.py:13 contrib/auth/models.py:26
@@ -522,7 +522,7 @@ msgstr "staf status"
#: contrib/auth/models.py:60
msgid "Designates whether the user can log into this admin site."
-msgstr "Bepaalt of de gebruiker kan inloggen op deze admin site"
+msgstr "Bepaalt of de gebruiker kan inloggen op deze admin site."
#: contrib/auth/models.py:61
msgid "active"
@@ -682,7 +682,7 @@ msgstr "Gebruikersnamen mogen geen '@' bevatten."
#: contrib/admin/views/decorators.py:84
#, python-format
msgid "Your e-mail address is not your username. Try '%s' instead."
-msgstr "Uw e-mail adres is niet uw gebruikersnaam. Probeer '%s' eens."
+msgstr "Uw e-mailadres is niet uw gebruikersnaam. Probeer '%s' eens."
#: contrib/admin/views/main.py:226
msgid "Site administration"
@@ -734,13 +734,13 @@ msgstr "Geen velden gewijzigd."
#: contrib/admin/views/main.py:346
#, python-format
msgid "The %(name)s \"%(obj)s\" was changed successfully."
-msgstr "Wijzigen %(name)s \"%(obj)s\" is geslaagd."
+msgstr "Het wijzigen van %(name)s \"%(obj)s\" is geslaagd."
#: contrib/admin/views/main.py:354
#, python-format
msgid ""
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
-msgstr "De %(name)s \"%(obj)s\" toegevoegd. U kunt het hieronder wijzigen."
+msgstr "De %(name)s \"%(obj)s\" was toegevoegd. U kunt het hieronder wijzigen."
#: contrib/admin/views/main.py:392
#, python-format
@@ -760,7 +760,7 @@ msgstr "Een of meer %(fieldname)s in %(name)s:"
#: contrib/admin/views/main.py:508
#, python-format
msgid "The %(name)s \"%(obj)s\" was deleted successfully."
-msgstr "Verwijdering %(name)s \"%(obj)s\" is geslaagd."
+msgstr "De verwijdering van %(name)s \"%(obj)s\" is geslaagd."
#: contrib/admin/views/main.py:511
msgid "Are you sure?"
@@ -769,7 +769,7 @@ msgstr "Weet u het zeker?"
#: contrib/admin/views/main.py:533
#, python-format
msgid "Change history: %s"
-msgstr "Wijzigingshistorie: %s"
+msgstr "Wijzigingsgeschiedenis: %s"
#: contrib/admin/views/main.py:565
#, python-format
@@ -794,7 +794,7 @@ msgstr "Boolean (True of False)"
#: contrib/admin/views/doc.py:279 contrib/admin/views/doc.py:296
#, python-format
msgid "String (up to %(maxlength)s)"
-msgstr "Karakterreeks (maximaal %(maxlength)s)"
+msgstr "Karakterreeks (hooguit %(maxlength)s)"
#: contrib/admin/views/doc.py:280
msgid "Comma-separated integers"
@@ -939,9 +939,9 @@ msgid ""
"objects, but your account doesn't have permission to delete the following "
"types of objects:"
msgstr ""
-"Verwijderen van %(object_name)s '%(object)s' zal ook gerelateerde objecten "
-"verwijderen. Echter u heeft geen rechten om de volgende typen objecten te "
-"verwijderen:"
+"Het verwijderen van %(object_name)s '%(object)s' zal ook gerelateerde "
+"objecten verwijderen. Echter u heeft geen rechten om de volgende typen "
+"objecten te verwijderen:"
#: contrib/admin/templates/admin/delete_confirmation.html:21
#, python-format
@@ -963,7 +963,7 @@ msgstr "Pagina niet gevonden"
#: contrib/admin/templates/admin/404.html:10
msgid "We're sorry, but the requested page could not be found."
-msgstr "De gevraagde pagina komt niet voor."
+msgstr "Onze excuses, maar de gevraagde pagina komt niet voor."
#: contrib/admin/templates/admin/change_form.html:15
#: contrib/admin/templates/admin/index.html:28
@@ -1073,8 +1073,8 @@ msgid ""
"This object doesn't have a change history. It probably wasn't added via this "
"admin site."
msgstr ""
-"Dit object heeft geen geschiedenis. Mogelijk niet via de admin site "
-"toegevoegd."
+"Dit object heeft geen wijzigingsgeschiedenis. Het is mogelijk niet via de "
+"admin site toegevoegd."
#: contrib/admin/templates/admin/500.html:4
msgid "Server error"
@@ -1093,9 +1093,8 @@ msgid ""
"There's been an error. It's been reported to the site administrators via e-"
"mail and should be fixed shortly. Thanks for your patience."
msgstr ""
-"Er is een fout opgetreden. Dit is inmiddels doorgegevens aan de "
-"sitebeheerder via e-mail en zal binnenkort worden gerepareerd. Bedankt voor "
-"uw geduld"
+"Er is een fout opgetreden. Dit is inmiddels doorgegeven aan de sitebeheerder "
+"via e-mail en zal spoedig worden gerepareerd. Bedankt voor uw geduld."
#: contrib/admin/templates/admin/search_form.html:8
msgid "Go"
@@ -1188,7 +1187,7 @@ msgstr "Bewerk dit object (nieuwe pagina)"
#: contrib/admin/templates/admin_doc/bookmarklets.html:29
msgid "As above, but opens the admin page in a new window."
-msgstr "Als boven, maar opent de beheerpagina in een nieuw venster."
+msgstr "Zoals hierboven, maar opent de beheerpagina in een nieuw venster."
#: contrib/admin/templates/widget/date_time.html:3
msgid "Date:"
@@ -1218,8 +1217,8 @@ msgid ""
"Forgotten your password? Enter your e-mail address below, and we'll reset "
"your password and e-mail the new one to you."
msgstr ""
-"Wachtwoord vergeten? Geef u e-mail adres op en we herstellen uw wachtwoord "
-"en zullen u het nieuwe wachtwoord per e-mail toesturen."
+"Uw wachtwoord vergeten? Geef uw e-mailadres op en er zal een nieuw "
+"wachtwoord worden toegekend en aan u worden toegezonden."
#: contrib/admin/templates/registration/password_reset_form.html:16
msgid "E-mail address:"
@@ -1231,7 +1230,7 @@ msgstr "Herstel mijn wachtwoord"
#: contrib/admin/templates/registration/password_reset_email.html:2
msgid "You're receiving this e-mail because you requested a password reset"
-msgstr "U krijgt een e-mail omdat u om een nieuw wachtwoord heeft gevraagd"
+msgstr "U krijgt deze e-mail omdat u om een nieuw wachtwoord heeft gevraagd"
#: contrib/admin/templates/registration/password_reset_email.html:3
#, python-format
@@ -1278,8 +1277,7 @@ msgid ""
"We've e-mailed a new password to the e-mail address you submitted. You "
"should be receiving it shortly."
msgstr ""
-"Een nieuw wachtwoord is per e-mail verstuurd. U zult het binnenkort "
-"ontvangen."
+"Een nieuw wachtwoord is per e-mail verstuurd. U zult het spoedig ontvangen."
#: contrib/admin/templates/registration/password_change_form.html:4
#: contrib/admin/templates/registration/password_change_form.html:6
@@ -1293,8 +1291,8 @@ msgid ""
"Please enter your old password, for security's sake, and then enter your new "
"password twice so we can verify you typed it in correctly."
msgstr ""
-"Geef voor de veiligheid uw oude wachtwoord op en twee keer een nieuw "
-"wachtwoord, zodat we kunnen controleren of er geen typefouten zijn gemaakt."
+"Vanwege de beveiliging moet u uw oude en twee keer een nieuw wachtwoord"
+"invoeren, zodat we kunnen controleren of er geen typefouten zijn gemaakt."
#: contrib/admin/templates/registration/password_change_form.html:17
msgid "Old password:"
@@ -1340,7 +1338,8 @@ msgstr "sites"
#: contrib/flatpages/models.py:8
msgid ""
"Example: '/about/contact/'. Make sure to have leading and trailing slashes."
-msgstr "Voorbeeld: '/about/contact/'. Zorg voor slashes aan begin en eind"
+msgstr ""
+"Voorbeeld: '/about/contact/'. Zorg voor slashes aan het begin en eind."
#: contrib/flatpages/models.py:9
msgid "title"
@@ -1373,8 +1372,8 @@ msgstr "registratie verplicht"
#: contrib/flatpages/models.py:14
msgid "If this is checked, only logged-in users will be able to view the page."
msgstr ""
-"Alleen ingelogde gebruikers kunnen deze pagina zien, indien dit is "
-"aangekruist."
+"Indien dit is aangekruist kunnen alleen ingelogde gebruikers deze pagina "
+"bekijken."
#: contrib/flatpages/models.py:18
msgid "flat page"
@@ -1405,8 +1404,8 @@ msgid ""
"This can be either an absolute path (as above) or a full URL starting with "
"'http://'."
msgstr ""
-"Dit kan een absoluut pad zijn (zoals boven) of een volledige URL beginnend "
-"met 'http://'."
+"Dit kan een absoluut pad (zoals hierboven) zijn of een volledige URL "
+"beginnend met 'http://'."
#: contrib/redirects/models.py:12
msgid "redirect"
@@ -1471,7 +1470,7 @@ msgstr "datum/tijd toegevoegd"
#: contrib/comments/models.py:84 contrib/comments/models.py:170
msgid "is public"
-msgstr "is publiek"
+msgstr "is openbaar"
#: contrib/comments/models.py:86
msgid "is removed"
@@ -1518,7 +1517,7 @@ msgstr "ip adres"
#: contrib/comments/models.py:173
msgid "approved by staff"
-msgstr "goegekeurd door de staf"
+msgstr "goedgekeurd door de staf"
#: contrib/comments/models.py:176
msgid "free comment"
@@ -1604,14 +1603,14 @@ msgstr "Ongeldige opmerkingen ID"
#: contrib/comments/views/karma.py:25
msgid "No voting for yourself"
-msgstr "Niet op jezelf stemmen"
+msgstr "Niet op uzelf stemmen"
#: contrib/comments/views/comments.py:28
msgid ""
"This rating is required because you've entered at least one other rating."
msgstr ""
-"Deze waardering is verplicht omdat je op zijn minst een andere waardering "
-"hebt ingevoerd."
+"Deze waardering is verplicht omdat u tenminste één andere waardering hebt "
+"ingevoerd."
#: contrib/comments/views/comments.py:112
#, python-format
@@ -1626,13 +1625,13 @@ msgid_plural ""
"\n"
"%(text)s"
msgstr[0] ""
-"Deze opmerking is gepost door een gebruiker welke minder dan %(count)s opmerking "
-"heeft gepost:\n"
+"Deze opmerking is gepost door een gebruiker die minder dan %(count)s "
+"opmerking heeft gepost:\n"
"\n"
"%(text)s"
msgstr[1] ""
-"Deze opmerking is gepost door een gebruiker welke minder dan %(count)s opmerkingen "
-"heeft gepost:\n"
+"Deze opmerking is gepost door een gebruiker die minder dan %(count)s "
+"opmerkingen heeft gepost:\n"
"\n"
"%(text)s"
@@ -1655,7 +1654,7 @@ msgstr "Alleen POSTs zijn toegestaan"
#: contrib/comments/views/comments.py:193
#: contrib/comments/views/comments.py:284
msgid "One or more of the required fields wasn't submitted"
-msgstr "Een of meerdere verplichte velden is niet ingevuld"
+msgstr "Een of meerdere verplichte velden zijn niet ingevuld"
#: contrib/comments/views/comments.py:197
#: contrib/comments/views/comments.py:286
@@ -1710,7 +1709,7 @@ msgstr "Concept opmerking"
#: contrib/comments/templates/comments/freeform.html:4
msgid "Your name:"
-msgstr "Uw gebruikernaam:"
+msgstr "Uw gebruikersnaam:"
#: contrib/sessions/models.py:35
msgid "session key"
@@ -1738,18 +1737,18 @@ msgstr "python model-class-naam"
#: contrib/contenttypes/models.py:28
msgid "content type"
-msgstr "inhoudtype"
+msgstr "inhoudstype"
#: contrib/contenttypes/models.py:29
msgid "content types"
-msgstr "inhoudtypen"
+msgstr "inhoudstypen"
#: forms/__init__.py:380
#, python-format
msgid "Ensure your text is less than %s character."
msgid_plural "Ensure your text is less than %s characters."
-msgstr[0] "Zorg ervoor dat uw tekst korter is dan %s teken."
-msgstr[1] "Zorg ervoor dat uw tekst korter is dan %S tekens."
+msgstr[0] "Zorg ervoor dat uw tekst korter is dan %s karakter."
+msgstr[1] "Zorg ervoor dat uw tekst korter is dan %s karakters."
#: forms/__init__.py:385
msgid "Line breaks are not allowed here."
@@ -1778,31 +1777,31 @@ msgstr "Geef een geheel getal op tussen 0 en 32.767."
#: utils/dates.py:6
msgid "Monday"
-msgstr "Maandag"
+msgstr "maandag"
#: utils/dates.py:6
msgid "Tuesday"
-msgstr "Dinsdag"
+msgstr "dinsdag"
#: utils/dates.py:6
msgid "Wednesday"
-msgstr "Woensdag"
+msgstr "woensdag"
#: utils/dates.py:6
msgid "Thursday"
-msgstr "Donderdag"
+msgstr "donderdag"
#: utils/dates.py:6
msgid "Friday"
-msgstr "Vrijdag"
+msgstr "vrijdag"
#: utils/dates.py:7
msgid "Saturday"
-msgstr "Zaterdag"
+msgstr "zaterdag"
#: utils/dates.py:7
msgid "Sunday"
-msgstr "Zondag"
+msgstr "zondag"
#: utils/dates.py:14
msgid "January"
@@ -1890,7 +1889,7 @@ msgstr "sep"
#: utils/dates.py:20
msgid "oct"
-msgstr "oct"
+msgstr "okt"
#: utils/dates.py:20
msgid "nov"
diff --git a/django/conf/urls/registration.py b/django/conf/urls/registration.py
index 2d733a898b..9b41e434f9 100644
--- a/django/conf/urls/registration.py
+++ b/django/conf/urls/registration.py
@@ -1,7 +1,7 @@
from django.conf.urls.defaults import *
urlpatterns = patterns('',
- (r'^login/$', 'django.contrib.auth.view.login'),
+ (r'^login/$', 'django.contrib.auth.views.login'),
(r'^logout/$', 'django.contrib.auth.views.logout'),
(r'^login_another/$', 'django.contrib.auth.views.logout_then_login'),
diff --git a/django/contrib/admin/media/css/changelists.css b/django/contrib/admin/media/css/changelists.css
index 2269c9fe20..fbcbe56f06 100644
--- a/django/contrib/admin/media/css/changelists.css
+++ b/django/contrib/admin/media/css/changelists.css
@@ -4,7 +4,7 @@
#changelist { position:relative; width:100%; }
#changelist table { width:100%; }
.change-list .filtered table { border-right:1px solid #ddd; }
-.change-list .filtered { min-height:400px; _height:400px; }
+.change-list .filtered { min-height:400px; }
.change-list .filtered { background:white url(../img/admin/changelist-bg.gif) top right repeat-y !important; }
.change-list .filtered table, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull { margin-right:160px !important; width:auto !important; }
.change-list .filtered table tbody th { padding-right:1em; }
@@ -27,7 +27,7 @@
#changelist-filter { position:absolute; top:0; right:0; z-index:1000; width:160px; border-left:1px solid #ddd; background:#efefef; margin:0; }
#changelist-filter h2 { font-size:11px; padding:2px 5px; border-bottom:1px solid #ddd; }
#changelist-filter h3 { font-size:12px; margin-bottom:0; }
-#changelist-filter ul { padding-left:0;margin-left:10px;_margin-right:-10px; }
+#changelist-filter ul { padding-left:0;margin-left:10px; }
#changelist-filter li { list-style-type:none; margin-left:0; padding-left:0; }
#changelist-filter a { color:#999; }
#changelist-filter a:hover { color:#036; }
diff --git a/django/contrib/admin/media/css/global.css b/django/contrib/admin/media/css/global.css
index 67e37324e5..a87931681c 100644
--- a/django/contrib/admin/media/css/global.css
+++ b/django/contrib/admin/media/css/global.css
@@ -86,7 +86,7 @@ textarea { vertical-align:top !important; }
input[type=text], input[type=password], textarea, select, .vTextField { border:1px solid #ccc; }
/* FORM BUTTONS */
-input[type=submit], input[type=button], .submit-row input { background:white url(../img/admin/nav-bg.gif) bottom repeat-x; padding:3px; color:black; }
+input[type=submit], input[type=button], .submit-row input { background:white url(../img/admin/nav-bg.gif) bottom repeat-x; padding:3px; color:black; border:1px solid #bbb; border-color:#ddd #aaa #aaa #ddd; }
input[type=submit]:active, input[type=button]:active { background-image:url(../img/admin/nav-bg-reverse.gif); background-position:top; }
input[type=submit].default, .submit-row input.default { border:2px solid #5b80b2; background:#7CA0C7 url(../img/admin/default-bg.gif) bottom repeat-x; font-weight:bold; color:white; }
input[type=submit].default:active { background-image:url(../img/admin/default-bg-reverse.gif); background-position:top; }
diff --git a/django/contrib/admin/media/css/layout.css b/django/contrib/admin/media/css/layout.css
index c8eb42650f..befe4fc1ca 100644
--- a/django/contrib/admin/media/css/layout.css
+++ b/django/contrib/admin/media/css/layout.css
@@ -3,13 +3,13 @@
#content { margin:10px 15px; }
#header { width:100%; }
#content-main { float:left; width:100%; }
-#content-related { float:right; width:220px; position:relative; margin-right:-230px; }
+#content-related { float:right; width:18em; position:relative; margin-right:-19em; }
#footer { clear:both; padding:10px; }
/* COLUMN TYPES */
-.colMS { margin-right:245px !important; }
-.colSM { margin-left:245px !important; }
-.colSM #content-related { float:left; margin-right:0; margin-left:-230px; }
+.colMS { margin-right:20em !important; }
+.colSM { margin-left:20em !important; }
+.colSM #content-related { float:left; margin-right:0; margin-left:-19em; }
.colSM #content-main { float:right; }
.popup .colM { width:95%; }
.subcol { float:left; width:46%; margin-right:15px; }
diff --git a/django/contrib/admin/media/css/patch-iewin.css b/django/contrib/admin/media/css/patch-iewin.css
index b2e6a4c560..2de1305e44 100644
--- a/django/contrib/admin/media/css/patch-iewin.css
+++ b/django/contrib/admin/media/css/patch-iewin.css
@@ -3,4 +3,6 @@
* html .colSM #content-related { margin-right:10px; margin-left:-115px; position:static; } /* put the left sidebars back on the page */
* html .form-row { height:1%; }
* html .dashboard #content { width:768px; } /* proper fixed width for dashboard in IE6 */
-* html .dashboard #content-main { width:535px; } /* proper fixed width for dashboard in IE6 */
\ No newline at end of file
+* html .dashboard #content-main { width:535px; } /* proper fixed width for dashboard in IE6 */
+* html #changelist-filter ul { margin-right:-10px; } /* fix right margin for changelist filters in IE6 */
+* html .change-list .filtered { height:400px; } /* IE ignores min-height, but treats height as if it were min-height */
\ No newline at end of file
diff --git a/django/contrib/admin/media/js/admin/RelatedObjectLookups.js b/django/contrib/admin/media/js/admin/RelatedObjectLookups.js
index cb84790f44..cf57fc4dfb 100644
--- a/django/contrib/admin/media/js/admin/RelatedObjectLookups.js
+++ b/django/contrib/admin/media/js/admin/RelatedObjectLookups.js
@@ -3,6 +3,8 @@
function showRelatedObjectLookupPopup(triggeringLink) {
var name = triggeringLink.id.replace(/^lookup_/, '');
+ // IE doesn't like periods in the window name, so convert temporarily.
+ name = name.replace(/\./g, '___');
var href;
if (triggeringLink.href.search(/\?/) >= 0) {
href = triggeringLink.href + '&pop=1';
@@ -15,11 +17,12 @@ function showRelatedObjectLookupPopup(triggeringLink) {
}
function dismissRelatedLookupPopup(win, chosenId) {
- var elem = document.getElementById(win.name);
+ var name = win.name.replace(/___/g, '.');
+ var elem = document.getElementById(name);
if (elem.className.indexOf('vRawIdAdminField') != -1 && elem.value) {
elem.value += ',' + chosenId;
} else {
- document.getElementById(win.name).value = chosenId;
+ document.getElementById(name).value = chosenId;
}
win.close();
}
diff --git a/django/contrib/admin/templates/admin/base.html b/django/contrib/admin/templates/admin/base.html
index 912a620010..a8c1c9c101 100644
--- a/django/contrib/admin/templates/admin/base.html
+++ b/django/contrib/admin/templates/admin/base.html
@@ -19,9 +19,9 @@
{% block branding %}{% endblock %}
- {% if not user.is_anonymous %}
+ {% if not user.is_anonymous %}{% if user.is_staff %}
- {% endif %}
+ {% endif %}{% endif %}
{% block nav-global %}{% endblock %}
diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py
index 8efef6b542..d5f8df9dfd 100644
--- a/django/contrib/admin/templatetags/admin_list.py
+++ b/django/contrib/admin/templatetags/admin_list.py
@@ -2,14 +2,15 @@ from django import template
from django.conf import settings
from django.contrib.admin.views.main import MAX_SHOW_ALL_ALLOWED, ALL_VAR
from django.contrib.admin.views.main import ORDER_VAR, ORDER_TYPE_VAR, PAGE_VAR, SEARCH_VAR
-from django.contrib.admin.views.main import IS_POPUP_VAR, EMPTY_CHANGELIST_VALUE, MONTHS
+from django.contrib.admin.views.main import IS_POPUP_VAR, EMPTY_CHANGELIST_VALUE
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.utils import dateformat
from django.utils.html import escape
from django.utils.text import capfirst
-from django.utils.translation import get_date_formats
+from django.utils.translation import get_date_formats, get_partial_date_formats
from django.template import Library
+import datetime
register = Library()
@@ -193,18 +194,19 @@ def date_hierarchy(cl):
year_lookup = cl.params.get(year_field)
month_lookup = cl.params.get(month_field)
day_lookup = cl.params.get(day_field)
+ year_month_format, month_day_format = get_partial_date_formats()
link = lambda d: cl.get_query_string(d, [field_generic])
if year_lookup and month_lookup and day_lookup:
- month_name = MONTHS[int(month_lookup)]
+ day = datetime.date(int(year_lookup), int(month_lookup), int(day_lookup))
return {
'show': True,
'back': {
'link': link({year_field: year_lookup, month_field: month_lookup}),
- 'title': "%s %s" % (month_name, year_lookup)
+ 'title': dateformat.format(day, year_month_format)
},
- 'choices': [{'title': "%s %s" % (month_name, day_lookup)}]
+ 'choices': [{'title': dateformat.format(day, month_day_format)}]
}
elif year_lookup and month_lookup:
days = cl.query_set.filter(**{year_field: year_lookup, month_field: month_lookup}).dates(field_name, 'day')
@@ -216,7 +218,7 @@ def date_hierarchy(cl):
},
'choices': [{
'link': link({year_field: year_lookup, month_field: month_lookup, day_field: day.day}),
- 'title': day.strftime('%B %d')
+ 'title': dateformat.format(day, month_day_format)
} for day in days]
}
elif year_lookup:
@@ -229,7 +231,7 @@ def date_hierarchy(cl):
},
'choices': [{
'link': link({year_field: year_lookup, month_field: month.month}),
- 'title': "%s %s" % (month.strftime('%B'), month.year)
+ 'title': dateformat.format(month, year_month_format)
} for month in months]
}
else:
diff --git a/django/contrib/admin/utils.py b/django/contrib/admin/utils.py
index c6c794c75e..0242b2f32e 100644
--- a/django/contrib/admin/utils.py
+++ b/django/contrib/admin/utils.py
@@ -81,12 +81,16 @@ ROLES = {
}
def create_reference_role(rolename, urlbase):
- def _role(name, rawtext, text, lineno, inliner, options={}, content=[]):
+ def _role(name, rawtext, text, lineno, inliner, options=None, content=None):
+ if options is None: options = {}
+ if content is None: content = []
node = docutils.nodes.reference(rawtext, text, refuri=(urlbase % (inliner.document.settings.link_base, text.lower())), **options)
return [node], []
docutils.parsers.rst.roles.register_canonical_role(rolename, _role)
-def default_reference_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
+def default_reference_role(name, rawtext, text, lineno, inliner, options=None, content=None):
+ if options is None: options = {}
+ if content is None: content = []
context = inliner.document.settings.default_reference_context
node = docutils.nodes.reference(rawtext, text, refuri=(ROLES[context] % (inliner.document.settings.link_base, text.lower())), **options)
return [node], []
diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py
index 8fe3c95178..af55587d23 100644
--- a/django/contrib/admin/views/main.py
+++ b/django/contrib/admin/views/main.py
@@ -579,7 +579,9 @@ class ChangeList(object):
filter_specs.append(spec)
return filter_specs, bool(filter_specs)
- def get_query_string(self, new_params={}, remove=[]):
+ def get_query_string(self, new_params=None, remove=None):
+ if new_params is None: new_params = {}
+ if remove is None: remove = []
p = self.params.copy()
for r in remove:
for k in p.keys():
diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py
index f5f622665c..ef81268e2a 100644
--- a/django/contrib/auth/forms.py
+++ b/django/contrib/auth/forms.py
@@ -35,6 +35,8 @@ class AuthenticationForm(forms.Manipulator):
self.user_cache = authenticate(username=username, password=password)
if self.user_cache is None:
raise validators.ValidationError, _("Please enter a correct username and password. Note that both fields are case-sensitive.")
+ elif not self.user_cache.is_active:
+ raise validators.ValidationError, _("This account is inactive.")
def get_user_id(self):
if self.user_cache:
diff --git a/tests/modeltests/repr/__init__.py b/django/contrib/humanize/__init__.py
similarity index 100%
rename from tests/modeltests/repr/__init__.py
rename to django/contrib/humanize/__init__.py
diff --git a/django/contrib/humanize/templatetags/__init__.py b/django/contrib/humanize/templatetags/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/django/contrib/humanize/templatetags/humanize.py b/django/contrib/humanize/templatetags/humanize.py
new file mode 100644
index 0000000000..b2d28a0ab4
--- /dev/null
+++ b/django/contrib/humanize/templatetags/humanize.py
@@ -0,0 +1,64 @@
+from django import template
+import re
+
+register = template.Library()
+
+def ordinal(value):
+ """
+ Converts an integer to its ordinal as a string. 1 is '1st', 2 is '2nd',
+ 3 is '3rd', etc. Works for any integer.
+ """
+ try:
+ value = int(value)
+ except ValueError:
+ return value
+ t = ('th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th')
+ if value % 100 in (11, 12, 13): # special case
+ return '%dth' % value
+ return '%d%s' % (value, t[value % 10])
+register.filter(ordinal)
+
+def intcomma(value):
+ """
+ Converts an integer to a string containing commas every three digits.
+ For example, 3000 becomes '3,000' and 45000 becomes '45,000'.
+ """
+ orig = str(value)
+ new = re.sub("^(-?\d+)(\d{3})", '\g<1>,\g<2>', str(value))
+ if orig == new:
+ return new
+ else:
+ return intcomma(new)
+register.filter(intcomma)
+
+def intword(value):
+ """
+ Converts a large integer to a friendly text representation. Works best for
+ numbers over 1 million. For example, 1000000 becomes '1.0 million', 1200000
+ becomes '1.2 million' and '1200000000' becomes '1.2 billion'.
+ """
+ value = int(value)
+ if value < 1000000:
+ return value
+ if value < 1000000000:
+ return '%.1f million' % (value / 1000000.0)
+ if value < 1000000000000:
+ return '%.1f billion' % (value / 1000000000.0)
+ if value < 1000000000000000:
+ return '%.1f trillion' % (value / 1000000000000.0)
+ return value
+register.filter(intword)
+
+def apnumber(value):
+ """
+ For numbers 1-9, returns the number spelled out. Otherwise, returns the
+ number. This follows Associated Press style.
+ """
+ try:
+ value = int(value)
+ except ValueError:
+ return value
+ if not 0 < value < 10:
+ return value
+ return ('one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine')[value-1]
+register.filter(apnumber)
diff --git a/django/core/management.py b/django/core/management.py
index f7bbf29227..931372cc5e 100644
--- a/django/core/management.py
+++ b/django/core/management.py
@@ -1055,7 +1055,9 @@ def run_shell(use_plain=False):
# Don't bother loading IPython, because the user wants plain Python.
raise ImportError
import IPython
- shell = IPython.Shell.IPShell()
+ # Explicitly pass an empty list as arguments, because otherwise IPython
+ # would use sys.argv from this script.
+ shell = IPython.Shell.IPShell(argv=[])
shell.mainloop()
except ImportError:
import code
@@ -1137,7 +1139,11 @@ def print_error(msg, cmd):
sys.stderr.write(style.ERROR('Error: %s' % msg) + '\nRun "%s --help" for help.\n' % cmd)
sys.exit(1)
-def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING):
+def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
+ # Use sys.argv if we've not passed in a custom argv
+ if argv is None:
+ argv = sys.argv
+
# Parse the command-line arguments. optparse handles the dirty work.
parser = DjangoOptionParser(usage=get_usage(action_mapping), version=get_version())
parser.add_option('--settings',
@@ -1146,7 +1152,7 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING):
help='Lets you manually add a directory the Python path, e.g. "/home/djangoprojects/myproject".')
parser.add_option('--plain', action='store_true', dest='plain',
help='Tells Django to use plain Python, not IPython, for "shell" command.')
- options, args = parser.parse_args()
+ options, args = parser.parse_args(argv[1:])
# Take care of options.
if options.settings:
@@ -1161,7 +1167,7 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING):
except IndexError:
parser.print_usage_and_exit()
if not action_mapping.has_key(action):
- print_error("Your action, %r, was invalid." % action, sys.argv[0])
+ print_error("Your action, %r, was invalid." % action, argv[0])
# Switch to English, because django-admin.py creates database content
# like permissions, and those shouldn't contain any translations.
@@ -1220,7 +1226,7 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING):
if action not in NO_SQL_TRANSACTION:
print style.SQL_KEYWORD("COMMIT;")
-def execute_manager(settings_mod):
+def execute_manager(settings_mod, argv=None):
# Add this project to sys.path so that it's importable in the conventional
# way. For example, if this file (manage.py) lives in a directory
# "myproject", this code would add "/path/to/myproject" to sys.path.
@@ -1247,4 +1253,4 @@ def execute_manager(settings_mod):
action_mapping['startapp'].args = startapp.args
# Run the django-admin.py command.
- execute_from_command_line(action_mapping)
+ execute_from_command_line(action_mapping, argv)
diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py
index db4967e1c5..91e999f802 100644
--- a/django/core/urlresolvers.py
+++ b/django/core/urlresolvers.py
@@ -23,6 +23,25 @@ def get_mod_func(callback):
dot = callback.rindex('.')
return callback[:dot], callback[dot+1:]
+def reverse_helper(regex, *args, **kwargs):
+ """
+ Does a "reverse" lookup -- returns the URL for the given args/kwargs.
+ The args/kwargs are applied to the given compiled regular expression.
+ For example:
+
+ >>> reverse_helper(re.compile('^places/(\d+)/$'), 3)
+ 'places/3/'
+ >>> reverse_helper(re.compile('^places/(?P\d+)/$'), id=3)
+ 'places/3/'
+ >>> reverse_helper(re.compile('^people/(?P\w\w)/(\w+)/$'), 'adrian', state='il')
+ 'people/il/adrian/'
+
+ Raises NoReverseMatch if the args/kwargs aren't valid for the regex.
+ """
+ # TODO: Handle nested parenthesis in the following regex.
+ result = re.sub(r'\(([^)]+)\)', MatchChecker(args, kwargs), regex.pattern)
+ return result.replace('^', '').replace('$', '')
+
class MatchChecker(object):
"Class used in reverse RegexURLPattern lookup."
def __init__(self, args, kwargs):
@@ -108,23 +127,7 @@ class RegexURLPattern:
return self.reverse_helper(*args, **kwargs)
def reverse_helper(self, *args, **kwargs):
- """
- Does a "reverse" lookup -- returns the URL for the given args/kwargs.
- The args/kwargs are applied to the regular expression in this
- RegexURLPattern. For example:
-
- >>> RegexURLPattern('^places/(\d+)/$').reverse_helper(3)
- 'places/3/'
- >>> RegexURLPattern('^places/(?P\d+)/$').reverse_helper(id=3)
- 'places/3/'
- >>> RegexURLPattern('^people/(?P\w\w)/(\w+)/$').reverse_helper('adrian', state='il')
- 'people/il/adrian/'
-
- Raises NoReverseMatch if the args/kwargs aren't valid for the RegexURLPattern.
- """
- # TODO: Handle nested parenthesis in the following regex.
- result = re.sub(r'\(([^)]+)\)', MatchChecker(args, kwargs), self.regex.pattern)
- return result.replace('^', '').replace('$', '')
+ return reverse_helper(self.regex, *args, **kwargs)
class RegexURLResolver(object):
def __init__(self, regex, urlconf_name):
@@ -182,9 +185,19 @@ class RegexURLResolver(object):
def reverse(self, viewname, *args, **kwargs):
for pattern in self.urlconf_module.urlpatterns:
- if pattern.callback == viewname:
+ if isinstance(pattern, RegexURLResolver):
+ try:
+ return pattern.reverse_helper(viewname, *args, **kwargs)
+ except NoReverseMatch:
+ continue
+ elif pattern.callback == viewname:
try:
return pattern.reverse_helper(*args, **kwargs)
except NoReverseMatch:
continue
raise NoReverseMatch
+
+ def reverse_helper(self, viewname, *args, **kwargs):
+ sub_match = self.reverse(viewname, *args, **kwargs)
+ result = reverse_helper(self.regex, *args, **kwargs)
+ return result + sub_match
diff --git a/django/core/validators.py b/django/core/validators.py
index 27505b7d5a..a2e9bfaf89 100644
--- a/django/core/validators.py
+++ b/django/core/validators.py
@@ -399,7 +399,8 @@ class AnyValidator:
as a validation error. The message is rather unspecific, so it's best to
specify one on instantiation.
"""
- def __init__(self, validator_list=[], error_message=gettext_lazy("This field is invalid.")):
+ def __init__(self, validator_list=None, error_message=gettext_lazy("This field is invalid.")):
+ if validator_list is None: validator_list = []
self.validator_list = validator_list
self.error_message = error_message
for v in validator_list:
diff --git a/django/db/backends/ado_mssql/base.py b/django/db/backends/ado_mssql/base.py
index c5a3b2cc33..b645b053bf 100644
--- a/django/db/backends/ado_mssql/base.py
+++ b/django/db/backends/ado_mssql/base.py
@@ -125,6 +125,9 @@ def get_limit_offset_sql(limit, offset=None):
def get_random_function_sql():
return "RAND()"
+def get_fulltext_search_sql(field_name):
+ raise NotImplementedError
+
def get_drop_foreignkey_sql():
return "DROP CONSTRAINT"
diff --git a/django/db/backends/dummy/base.py b/django/db/backends/dummy/base.py
index 89fec00c1d..985fe96469 100644
--- a/django/db/backends/dummy/base.py
+++ b/django/db/backends/dummy/base.py
@@ -33,5 +33,6 @@ get_date_extract_sql = complain
get_date_trunc_sql = complain
get_limit_offset_sql = complain
get_random_function_sql = complain
+get_fulltext_search_sql = complain
get_drop_foreignkey_sql = complain
OPERATOR_MAPPING = {}
diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py
index 6a53956cad..4a13450c67 100644
--- a/django/db/backends/mysql/base.py
+++ b/django/db/backends/mysql/base.py
@@ -152,6 +152,9 @@ def get_limit_offset_sql(limit, offset=None):
def get_random_function_sql():
return "RAND()"
+def get_fulltext_search_sql(field_name):
+ return 'MATCH (%s) AGAINST (%%s IN BOOLEAN MODE)' % field_name
+
def get_drop_foreignkey_sql():
return "DROP FOREIGN KEY"
diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py
index a7c866484e..e981805108 100644
--- a/django/db/backends/oracle/base.py
+++ b/django/db/backends/oracle/base.py
@@ -65,11 +65,13 @@ class FormatStylePlaceholderCursor(Database.Cursor):
This fixes it -- but note that if you want to use a literal "%s" in a query,
you'll need to use "%%s".
"""
- def execute(self, query, params=[]):
+ def execute(self, query, params=None):
+ if params is None: params = []
query = self.convert_arguments(query, len(params))
return Database.Cursor.execute(self, query, params)
- def executemany(self, query, params=[]):
+ def executemany(self, query, params=None):
+ if params is None: params = []
query = self.convert_arguments(query, len(params[0]))
return Database.Cursor.executemany(self, query, params)
@@ -106,6 +108,9 @@ def get_limit_offset_sql(limit, offset=None):
def get_random_function_sql():
return "DBMS_RANDOM.RANDOM"
+def get_fulltext_search_sql(field_name):
+ raise NotImplementedError
+
def get_drop_foreignkey_sql():
return "DROP FOREIGN KEY"
diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py
index a365434318..decb160ee9 100644
--- a/django/db/backends/postgresql/base.py
+++ b/django/db/backends/postgresql/base.py
@@ -102,6 +102,9 @@ def get_limit_offset_sql(limit, offset=None):
def get_random_function_sql():
return "RANDOM()"
+def get_fulltext_search_sql(field_name):
+ raise NotImplementedError
+
def get_drop_foreignkey_sql():
return "DROP CONSTRAINT"
diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py
index 13e7be7a98..697a33bb76 100644
--- a/django/db/backends/postgresql_psycopg2/base.py
+++ b/django/db/backends/postgresql_psycopg2/base.py
@@ -108,6 +108,9 @@ def get_limit_offset_sql(limit, offset=None):
def get_random_function_sql():
return "RANDOM()"
+def get_fulltext_search_sql(field_name):
+ raise NotImplementedError
+
def get_drop_foreignkey_sql():
return "DROP CONSTRAINT"
diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py
index 7c3018aed9..7b51967416 100644
--- a/django/db/backends/sqlite3/base.py
+++ b/django/db/backends/sqlite3/base.py
@@ -124,6 +124,9 @@ def get_limit_offset_sql(limit, offset=None):
def get_random_function_sql():
return "RANDOM()"
+def get_fulltext_search_sql(field_name):
+ raise NotImplementedError
+
def get_drop_foreignkey_sql():
return ""
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index b5245d6624..2f8a8651a1 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -162,7 +162,7 @@ class Field(object):
def get_db_prep_lookup(self, lookup_type, value):
"Returns field's value prepared for database lookup."
- if lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'ne', 'year', 'month', 'day'):
+ if lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'ne', 'year', 'month', 'day', 'search'):
return [value]
elif lookup_type in ('range', 'in'):
return value
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index 5f6ec83bb6..6e0fb6d2a8 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -198,7 +198,7 @@ class ForeignRelatedObjectsDescriptor(object):
setattr(obj, rel_field.name, None)
obj.save()
else:
- raise rel_field.rel.to.DoesNotExist, "'%s' is not related to '%s'." % (obj, instance)
+ raise rel_field.rel.to.DoesNotExist, "%r is not related to %r." % (obj, instance)
remove.alters_data = True
def clear(self):
@@ -712,7 +712,7 @@ class ManyToManyRel:
self.related_name = related_name
self.filter_interface = filter_interface
if limit_choices_to is None:
- limit_choices_to = {}
+ limit_choices_to = {}
self.limit_choices_to = limit_choices_to
self.edit_inline = False
self.raw_id_admin = raw_id_admin
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 3517d6bed5..4bd9b3b9fe 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -615,6 +615,8 @@ def get_where_clause(lookup_type, table_prefix, field_name, value):
return "%s = %%s" % backend.get_date_extract_sql(lookup_type, table_prefix + field_name)
elif lookup_type == 'isnull':
return "%s%s IS %sNULL" % (table_prefix, field_name, (not value and 'NOT ' or ''))
+ elif lookup_type == 'search':
+ return backend.get_fulltext_search_sql(table_prefix + field_name)
raise TypeError, "Got invalid lookup_type: %s" % repr(lookup_type)
def get_cached_row(klass, row, index_start):
diff --git a/django/forms/__init__.py b/django/forms/__init__.py
index b67e1d0f84..cea3d22310 100644
--- a/django/forms/__init__.py
+++ b/django/forms/__init__.py
@@ -367,7 +367,8 @@ class FormField:
class TextField(FormField):
input_type = "text"
- def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=[], member_name=None):
+ def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=None, member_name=None):
+ if validator_list is None: validator_list = []
self.field_name = field_name
self.length, self.maxlength = length, maxlength
self.is_required = is_required
@@ -404,7 +405,8 @@ class PasswordField(TextField):
input_type = "password"
class LargeTextField(TextField):
- def __init__(self, field_name, rows=10, cols=40, is_required=False, validator_list=[], maxlength=None):
+ def __init__(self, field_name, rows=10, cols=40, is_required=False, validator_list=None, maxlength=None):
+ if validator_list is None: validator_list = []
self.field_name = field_name
self.rows, self.cols, self.is_required = rows, cols, is_required
self.validator_list = validator_list[:]
@@ -422,7 +424,8 @@ class LargeTextField(TextField):
self.field_name, self.rows, self.cols, escape(data))
class HiddenField(FormField):
- def __init__(self, field_name, is_required=False, validator_list=[]):
+ def __init__(self, field_name, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
self.field_name, self.is_required = field_name, is_required
self.validator_list = validator_list[:]
@@ -452,7 +455,9 @@ class CheckboxField(FormField):
html2python = staticmethod(html2python)
class SelectField(FormField):
- def __init__(self, field_name, choices=[], size=1, is_required=False, validator_list=[], member_name=None):
+ def __init__(self, field_name, choices=None, size=1, is_required=False, validator_list=None, member_name=None):
+ if validator_list is None: validator_list = []
+ if choices is None: choices = []
self.field_name = field_name
# choices is a list of (value, human-readable key) tuples because order matters
self.choices, self.size, self.is_required = choices, size, is_required
@@ -488,7 +493,9 @@ class NullSelectField(SelectField):
html2python = staticmethod(html2python)
class RadioSelectField(FormField):
- def __init__(self, field_name, choices=[], ul_class='', is_required=False, validator_list=[], member_name=None):
+ def __init__(self, field_name, choices=None, ul_class='', is_required=False, validator_list=None, member_name=None):
+ if validator_list is None: validator_list = []
+ if choices is None: choices = []
self.field_name = field_name
# choices is a list of (value, human-readable key) tuples because order matters
self.choices, self.is_required = choices, is_required
@@ -552,7 +559,8 @@ class RadioSelectField(FormField):
class NullBooleanField(SelectField):
"This SelectField provides 'Yes', 'No' and 'Unknown', mapping results to True, False or None"
- def __init__(self, field_name, is_required=False, validator_list=[]):
+ def __init__(self, field_name, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
SelectField.__init__(self, field_name, choices=[('1', 'Unknown'), ('2', 'Yes'), ('3', 'No')],
is_required=is_required, validator_list=validator_list)
@@ -605,7 +613,9 @@ class CheckboxSelectMultipleField(SelectMultipleField):
back into the single list that validators, renderers and save() expect.
"""
requires_data_list = True
- def __init__(self, field_name, choices=[], validator_list=[]):
+ def __init__(self, field_name, choices=None, validator_list=None):
+ if validator_list is None: validator_list = []
+ if choices is None: choices = []
SelectMultipleField.__init__(self, field_name, choices, size=1, is_required=False, validator_list=validator_list)
def prepare(self, new_data):
@@ -636,7 +646,8 @@ class CheckboxSelectMultipleField(SelectMultipleField):
####################
class FileUploadField(FormField):
- def __init__(self, field_name, is_required=False, validator_list=[]):
+ def __init__(self, field_name, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
self.field_name, self.is_required = field_name, is_required
self.validator_list = [self.isNonEmptyFile] + validator_list
@@ -675,7 +686,8 @@ class ImageUploadField(FileUploadField):
####################
class IntegerField(TextField):
- def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=[], member_name=None):
+ def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=None, member_name=None):
+ if validator_list is None: validator_list = []
validator_list = [self.isInteger] + validator_list
if member_name is not None:
self.member_name = member_name
@@ -694,7 +706,8 @@ class IntegerField(TextField):
html2python = staticmethod(html2python)
class SmallIntegerField(IntegerField):
- def __init__(self, field_name, length=5, maxlength=5, is_required=False, validator_list=[]):
+ def __init__(self, field_name, length=5, maxlength=5, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
validator_list = [self.isSmallInteger] + validator_list
IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list)
@@ -703,7 +716,8 @@ class SmallIntegerField(IntegerField):
raise validators.CriticalValidationError, gettext("Enter a whole number between -32,768 and 32,767.")
class PositiveIntegerField(IntegerField):
- def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=[]):
+ def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
validator_list = [self.isPositive] + validator_list
IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list)
@@ -712,7 +726,8 @@ class PositiveIntegerField(IntegerField):
raise validators.CriticalValidationError, gettext("Enter a positive number.")
class PositiveSmallIntegerField(IntegerField):
- def __init__(self, field_name, length=5, maxlength=None, is_required=False, validator_list=[]):
+ def __init__(self, field_name, length=5, maxlength=None, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
validator_list = [self.isPositiveSmall] + validator_list
IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list)
@@ -721,7 +736,8 @@ class PositiveSmallIntegerField(IntegerField):
raise validators.CriticalValidationError, gettext("Enter a whole number between 0 and 32,767.")
class FloatField(TextField):
- def __init__(self, field_name, max_digits, decimal_places, is_required=False, validator_list=[]):
+ def __init__(self, field_name, max_digits, decimal_places, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
self.max_digits, self.decimal_places = max_digits, decimal_places
validator_list = [self.isValidFloat] + validator_list
TextField.__init__(self, field_name, max_digits+1, max_digits+1, is_required, validator_list)
@@ -746,7 +762,8 @@ class FloatField(TextField):
class DatetimeField(TextField):
"""A FormField that automatically converts its data to a datetime.datetime object.
The data should be in the format YYYY-MM-DD HH:MM:SS."""
- def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=[]):
+ def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
self.field_name = field_name
self.length, self.maxlength = length, maxlength
self.is_required = is_required
@@ -769,7 +786,8 @@ class DatetimeField(TextField):
class DateField(TextField):
"""A FormField that automatically converts its data to a datetime.date object.
The data should be in the format YYYY-MM-DD."""
- def __init__(self, field_name, is_required=False, validator_list=[]):
+ def __init__(self, field_name, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
validator_list = [self.isValidDate] + validator_list
TextField.__init__(self, field_name, length=10, maxlength=10,
is_required=is_required, validator_list=validator_list)
@@ -793,7 +811,8 @@ class DateField(TextField):
class TimeField(TextField):
"""A FormField that automatically converts its data to a datetime.time object.
The data should be in the format HH:MM:SS or HH:MM:SS.mmmmmm."""
- def __init__(self, field_name, is_required=False, validator_list=[]):
+ def __init__(self, field_name, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
validator_list = [self.isValidTime] + validator_list
TextField.__init__(self, field_name, length=8, maxlength=8,
is_required=is_required, validator_list=validator_list)
@@ -827,7 +846,8 @@ class TimeField(TextField):
class EmailField(TextField):
"A convenience FormField for validating e-mail addresses"
- def __init__(self, field_name, length=50, maxlength=75, is_required=False, validator_list=[]):
+ def __init__(self, field_name, length=50, maxlength=75, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
validator_list = [self.isValidEmail] + validator_list
TextField.__init__(self, field_name, length, maxlength=maxlength,
is_required=is_required, validator_list=validator_list)
@@ -840,7 +860,8 @@ class EmailField(TextField):
class URLField(TextField):
"A convenience FormField for validating URLs"
- def __init__(self, field_name, length=50, maxlength=200, is_required=False, validator_list=[]):
+ def __init__(self, field_name, length=50, maxlength=200, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
validator_list = [self.isValidURL] + validator_list
TextField.__init__(self, field_name, length=length, maxlength=maxlength,
is_required=is_required, validator_list=validator_list)
@@ -852,7 +873,8 @@ class URLField(TextField):
raise validators.CriticalValidationError, e.messages
class IPAddressField(TextField):
- def __init__(self, field_name, length=15, maxlength=15, is_required=False, validator_list=[]):
+ def __init__(self, field_name, length=15, maxlength=15, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
validator_list = [self.isValidIPAddress] + validator_list
TextField.__init__(self, field_name, length=length, maxlength=maxlength,
is_required=is_required, validator_list=validator_list)
@@ -873,7 +895,7 @@ class IPAddressField(TextField):
class FilePathField(SelectField):
"A SelectField whose choices are the files in a given directory."
- def __init__(self, field_name, path, match=None, recursive=False, is_required=False, validator_list=[]):
+ def __init__(self, field_name, path, match=None, recursive=False, is_required=False, validator_list=None):
import os
if match is not None:
import re
@@ -896,7 +918,8 @@ class FilePathField(SelectField):
class PhoneNumberField(TextField):
"A convenience FormField for validating phone numbers (e.g. '630-555-1234')"
- def __init__(self, field_name, is_required=False, validator_list=[]):
+ def __init__(self, field_name, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
validator_list = [self.isValidPhone] + validator_list
TextField.__init__(self, field_name, length=12, maxlength=12,
is_required=is_required, validator_list=validator_list)
@@ -909,7 +932,8 @@ class PhoneNumberField(TextField):
class USStateField(TextField):
"A convenience FormField for validating U.S. states (e.g. 'IL')"
- def __init__(self, field_name, is_required=False, validator_list=[]):
+ def __init__(self, field_name, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
validator_list = [self.isValidUSState] + validator_list
TextField.__init__(self, field_name, length=2, maxlength=2,
is_required=is_required, validator_list=validator_list)
@@ -929,7 +953,8 @@ class USStateField(TextField):
class CommaSeparatedIntegerField(TextField):
"A convenience FormField for validating comma-separated integer fields"
- def __init__(self, field_name, maxlength=None, is_required=False, validator_list=[]):
+ def __init__(self, field_name, maxlength=None, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
validator_list = [self.isCommaSeparatedIntegerList] + validator_list
TextField.__init__(self, field_name, length=20, maxlength=maxlength,
is_required=is_required, validator_list=validator_list)
diff --git a/django/template/__init__.py b/django/template/__init__.py
index 18dceff45c..b526863fbf 100644
--- a/django/template/__init__.py
+++ b/django/template/__init__.py
@@ -227,7 +227,8 @@ class Parser(object):
for lib in builtins:
self.add_library(lib)
- def parse(self, parse_until=[]):
+ def parse(self, parse_until=None):
+ if parse_until is None: parse_until = []
nodelist = self.create_nodelist()
while self.tokens:
token = self.next_token()
diff --git a/django/utils/datastructures.py b/django/utils/datastructures.py
index bc8fb07ef5..3d7c4275bb 100644
--- a/django/utils/datastructures.py
+++ b/django/utils/datastructures.py
@@ -42,7 +42,8 @@ class MergeDict:
class SortedDict(dict):
"A dictionary that keeps its keys in the order in which they're inserted."
- def __init__(self, data={}):
+ def __init__(self, data=None):
+ if data is None: data = {}
dict.__init__(self, data)
self.keyOrder = data.keys()
@@ -123,8 +124,9 @@ class MultiValueDict(dict):
def __copy__(self):
return self.__class__(dict.items(self))
- def __deepcopy__(self, memo={}):
+ def __deepcopy__(self, memo=None):
import copy
+ if memo is None: memo = {}
result = self.__class__()
memo[id(self)] = result
for key, value in dict.items(self):
diff --git a/django/utils/translation.py b/django/utils/translation.py
index 81cd8e2992..a73c43c257 100644
--- a/django/utils/translation.py
+++ b/django/utils/translation.py
@@ -221,10 +221,10 @@ def get_language_bidi():
False = left-to-right layout
True = right-to-left layout
"""
-
+
from django.conf import settings
return get_language() in settings.LANGUAGES_BIDI
-
+
def catalog():
"""
This function returns the current active catalog for further processing.
@@ -369,7 +369,22 @@ def get_date_formats():
datetime_format = settings.DATETIME_FORMAT
if time_format == 'TIME_FORMAT':
time_format = settings.TIME_FORMAT
- return (date_format, datetime_format, time_format)
+ return date_format, datetime_format, time_format
+
+def get_partial_date_formats():
+ """
+ This function checks whether translation files provide a translation for some
+ technical message ID to store partial date formats. If it doesn't contain
+ one, the formats provided in the settings will be used.
+ """
+ from django.conf import settings
+ year_month_format = _('YEAR_MONTH_FORMAT')
+ month_day_format = _('MONTH_DAY_FORMAT')
+ if year_month_format == 'YEAR_MONTH_FORMAT':
+ year_month_format = settings.YEAR_MONTH_FORMAT
+ if month_day_format == 'MONTH_DAY_FORMAT':
+ month_day_format = settings.MONTH_DAY_FORMAT
+ return year_month_format, month_day_format
def install():
"""
diff --git a/django/utils/xmlutils.py b/django/utils/xmlutils.py
index 6638573857..a1eb5fb753 100644
--- a/django/utils/xmlutils.py
+++ b/django/utils/xmlutils.py
@@ -5,8 +5,9 @@ Utilities for XML generation/parsing.
from xml.sax.saxutils import XMLGenerator
class SimplerXMLGenerator(XMLGenerator):
- def addQuickElement(self, name, contents=None, attrs={}):
+ def addQuickElement(self, name, contents=None, attrs=None):
"Convenience method for adding an element with no children"
+ if attrs is None: attrs = {}
self.startElement(name, attrs)
if contents is not None:
self.characters(contents)
diff --git a/django/views/generic/create_update.py b/django/views/generic/create_update.py
index f73aae26dd..0804cdf30b 100644
--- a/django/views/generic/create_update.py
+++ b/django/views/generic/create_update.py
@@ -9,7 +9,7 @@ from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
def create_object(request, model, template_name=None,
- template_loader=loader, extra_context={}, post_save_redirect=None,
+ template_loader=loader, extra_context=None, post_save_redirect=None,
login_required=False, follow=None, context_processors=None):
"""
Generic object-creation function.
@@ -19,6 +19,7 @@ def create_object(request, model, template_name=None,
form
the form wrapper for the object
"""
+ if extra_context is None: extra_context = {}
if login_required and request.user.is_anonymous():
return redirect_to_login(request.path)
@@ -71,7 +72,7 @@ def create_object(request, model, template_name=None,
def update_object(request, model, object_id=None, slug=None,
slug_field=None, template_name=None, template_loader=loader,
- extra_context={}, post_save_redirect=None,
+ extra_context=None, post_save_redirect=None,
login_required=False, follow=None, context_processors=None,
template_object_name='object'):
"""
@@ -84,6 +85,7 @@ def update_object(request, model, object_id=None, slug=None,
object
the original object being edited
"""
+ if extra_context is None: extra_context = {}
if login_required and request.user.is_anonymous():
return redirect_to_login(request.path)
@@ -143,7 +145,7 @@ def update_object(request, model, object_id=None, slug=None,
def delete_object(request, model, post_delete_redirect,
object_id=None, slug=None, slug_field=None, template_name=None,
- template_loader=loader, extra_context={},
+ template_loader=loader, extra_context=None,
login_required=False, context_processors=None, template_object_name='object'):
"""
Generic object-delete function.
@@ -157,6 +159,7 @@ def delete_object(request, model, post_delete_redirect,
object
the original object being deleted
"""
+ if extra_context is None: extra_context = {}
if login_required and request.user.is_anonymous():
return redirect_to_login(request.path)
diff --git a/django/views/generic/date_based.py b/django/views/generic/date_based.py
index 0fc657d2c1..7084cdfe5e 100644
--- a/django/views/generic/date_based.py
+++ b/django/views/generic/date_based.py
@@ -6,7 +6,7 @@ import datetime, time
def archive_index(request, queryset, date_field, num_latest=15,
template_name=None, template_loader=loader,
- extra_context={}, allow_empty=False, context_processors=None,
+ extra_context=None, allow_empty=False, context_processors=None,
mimetype=None):
"""
Generic top-level archive of date-based objects.
@@ -18,6 +18,7 @@ def archive_index(request, queryset, date_field, num_latest=15,
latest
Latest N (defaults to 15) objects by date
"""
+ if extra_context is None: extra_context = {}
model = queryset.model
queryset = queryset.filter(**{'%s__lte' % date_field: datetime.datetime.now()})
date_list = queryset.dates(date_field, 'year')[::-1]
@@ -44,7 +45,7 @@ def archive_index(request, queryset, date_field, num_latest=15,
return HttpResponse(t.render(c), mimetype=mimetype)
def archive_year(request, year, queryset, date_field, template_name=None,
- template_loader=loader, extra_context={}, allow_empty=False,
+ template_loader=loader, extra_context=None, allow_empty=False,
context_processors=None, template_object_name='object', mimetype=None,
make_object_list=False):
"""
@@ -60,6 +61,7 @@ def archive_year(request, year, queryset, date_field, template_name=None,
List of objects published in the given month
(Only available if make_object_list argument is True)
"""
+ if extra_context is None: extra_context = {}
model = queryset.model
now = datetime.datetime.now()
@@ -92,7 +94,7 @@ def archive_year(request, year, queryset, date_field, template_name=None,
def archive_month(request, year, month, queryset, date_field,
month_format='%b', template_name=None, template_loader=loader,
- extra_context={}, allow_empty=False, context_processors=None,
+ extra_context=None, allow_empty=False, context_processors=None,
template_object_name='object', mimetype=None):
"""
Generic monthly archive view.
@@ -108,6 +110,7 @@ def archive_month(request, year, month, queryset, date_field,
object_list:
list of objects published in the given month
"""
+ if extra_context is None: extra_context = {}
try:
date = datetime.date(*time.strptime(year+month, '%Y'+month_format)[:3])
except ValueError:
@@ -148,7 +151,7 @@ def archive_month(request, year, month, queryset, date_field,
def archive_week(request, year, week, queryset, date_field,
template_name=None, template_loader=loader,
- extra_context={}, allow_empty=True, context_processors=None,
+ extra_context=None, allow_empty=True, context_processors=None,
template_object_name='object', mimetype=None):
"""
Generic weekly archive view.
@@ -160,6 +163,7 @@ def archive_week(request, year, week, queryset, date_field,
object_list:
list of objects published in the given week
"""
+ if extra_context is None: extra_context = {}
try:
date = datetime.date(*time.strptime(year+'-0-'+week, '%Y-%w-%U')[:3])
except ValueError:
@@ -195,7 +199,7 @@ def archive_week(request, year, week, queryset, date_field,
def archive_day(request, year, month, day, queryset, date_field,
month_format='%b', day_format='%d', template_name=None,
- template_loader=loader, extra_context={}, allow_empty=False,
+ template_loader=loader, extra_context=None, allow_empty=False,
context_processors=None, template_object_name='object',
mimetype=None):
"""
@@ -212,6 +216,7 @@ def archive_day(request, year, month, day, queryset, date_field,
next_day
(datetime) the next day, or None if the current day is today
"""
+ if extra_context is None: extra_context = {}
try:
date = datetime.date(*time.strptime(year+month+day, '%Y'+month_format+day_format)[:3])
except ValueError:
@@ -261,7 +266,7 @@ def archive_today(request, **kwargs):
def object_detail(request, year, month, day, queryset, date_field,
month_format='%b', day_format='%d', object_id=None, slug=None,
slug_field=None, template_name=None, template_name_field=None,
- template_loader=loader, extra_context={}, context_processors=None,
+ template_loader=loader, extra_context=None, context_processors=None,
template_object_name='object', mimetype=None):
"""
Generic detail view from year/month/day/slug or year/month/day/id structure.
@@ -271,6 +276,7 @@ def object_detail(request, year, month, day, queryset, date_field,
object:
the object to be detailed
"""
+ if extra_context is None: extra_context = {}
try:
date = datetime.date(*time.strptime(year+month+day, '%Y'+month_format+day_format)[:3])
except ValueError:
diff --git a/django/views/generic/list_detail.py b/django/views/generic/list_detail.py
index 77b97ca711..bd0f17c56a 100644
--- a/django/views/generic/list_detail.py
+++ b/django/views/generic/list_detail.py
@@ -4,9 +4,9 @@ from django.core.xheaders import populate_xheaders
from django.core.paginator import ObjectPaginator, InvalidPage
from django.core.exceptions import ObjectDoesNotExist
-def object_list(request, queryset, paginate_by=None, allow_empty=False,
- template_name=None, template_loader=loader,
- extra_context={}, context_processors=None, template_object_name='object',
+def object_list(request, queryset, paginate_by=None, page=None,
+ allow_empty=False, template_name=None, template_loader=loader,
+ extra_context=None, context_processors=None, template_object_name='object',
mimetype=None):
"""
Generic list of objects.
@@ -34,10 +34,12 @@ def object_list(request, queryset, paginate_by=None, allow_empty=False,
hits
number of objects, total
"""
+ if extra_context is None: extra_context = {}
queryset = queryset._clone()
if paginate_by:
paginator = ObjectPaginator(queryset, paginate_by)
- page = request.GET.get('page', 1)
+ if not page:
+ page = request.GET.get('page', 1)
try:
page = int(page)
object_list = paginator.get_page(page - 1)
@@ -78,7 +80,7 @@ def object_list(request, queryset, paginate_by=None, allow_empty=False,
def object_detail(request, queryset, object_id=None, slug=None,
slug_field=None, template_name=None, template_name_field=None,
- template_loader=loader, extra_context={},
+ template_loader=loader, extra_context=None,
context_processors=None, template_object_name='object',
mimetype=None):
"""
@@ -89,6 +91,7 @@ def object_detail(request, queryset, object_id=None, slug=None,
object
the object
"""
+ if extra_context is None: extra_context = {}
model = queryset.model
if object_id:
queryset = queryset.filter(pk=object_id)
diff --git a/docs/add_ons.txt b/docs/add_ons.txt
index f7b3056ef0..9f5dc640da 100644
--- a/docs/add_ons.txt
+++ b/docs/add_ons.txt
@@ -45,6 +45,71 @@ See the `csrf documentation`_.
.. _csrf documentation: http://www.djangoproject.com/documentation/csrf/
+humanize
+========
+
+A set of Django template filters useful for adding a "human touch" to data.
+To activate these filters, add ``'django.contrib.english'`` to your
+``INSTALLED_APPS`` setting. Once you've done that, use ``{% load english %}``
+in a template, and you'll have access to these filters:
+
+apnumber
+--------
+
+For numbers 1-9, returns the number spelled out. Otherwise, returns the
+number. This follows Associated Press style.
+
+Examples:
+
+ * ``1`` becomes ``'one'``.
+ * ``2`` becomes ``'two'``.
+ * ``10`` becomes ``10``.
+
+You can pass in either an integer or a string representation of an integer.
+
+intcomma
+--------
+
+Converts an integer to a string containing commas every three digits.
+
+Examples:
+
+ * ``4500`` becomes ``'4,500'``.
+ * ``45000`` becomes ``'45,000'``.
+ * ``450000`` becomes ``'450,000'``.
+ * ``4500000`` becomes ``'4,500,000'``.
+
+You can pass in either an integer or a string representation of an integer.
+
+intword
+-------
+
+Converts a large integer to a friendly text representation. Works best for
+numbers over 1 million.
+
+Examples:
+
+ * ``1000000`` becomes ``'1.0 million'``.
+ * ``1200000`` becomes ``'1.2 million'``.
+ * ``1200000000`` becomes ``'1.2 billion'``.
+
+Values up to 1000000000000000 (one quadrillion) are supported.
+
+You can pass in either an integer or a string representation of an integer.
+
+ordinal
+-------
+
+Converts an integer to its ordinal as a string.
+
+Examples:
+
+ * ``1`` becomes ``'1st'``.
+ * ``2`` becomes ``'2nd'``.
+ * ``3`` becomes ``'3rd'``.
+
+You can pass in either an integer or a string representation of an integer.
+
flatpages
=========
diff --git a/docs/authentication.txt b/docs/authentication.txt
index 1be64c045a..c1a1f8494d 100644
--- a/docs/authentication.txt
+++ b/docs/authentication.txt
@@ -82,14 +82,14 @@ Methods
``user_permissions``. ``User`` objects can access their related
objects in the same way as any other `Django model`_::
- ``myuser.objects.groups = [group_list]``
- ``myuser.objects.groups.add(group, group,...)``
- ``myuser.objects.groups.remove(group, group,...)``
- ``myuser.objects.groups.clear()``
- ``myuser.objects.permissions = [permission_list]``
- ``myuser.objects.permissions.add(permission, permission, ...)``
- ``myuser.objects.permissions.remove(permission, permission, ...]``
- ``myuser.objects.permissions.clear()``
+ myuser.objects.groups = [group_list]
+ myuser.objects.groups.add(group, group,...)
+ myuser.objects.groups.remove(group, group,...)
+ myuser.objects.groups.clear()
+ myuser.objects.permissions = [permission_list]
+ myuser.objects.permissions.add(permission, permission, ...)
+ myuser.objects.permissions.remove(permission, permission, ...]
+ myuser.objects.permissions.clear()
In addition to those automatic API methods, ``User`` objects have the following
custom methods:
diff --git a/docs/db-api.txt b/docs/db-api.txt
index 4442a75125..3624620609 100644
--- a/docs/db-api.txt
+++ b/docs/db-api.txt
@@ -1035,6 +1035,15 @@ SQL equivalent::
SELECT ... WHERE pub_date IS NULL;
+search
+~~~~~~
+
+A boolean full-text search, taking advantage of full-text indexing. This is
+like ``contains`` but is significantly faster due to full-text indexing.
+
+Note this is only available in MySQL and requires direct manipulation of the
+database to add the full-text index.
+
Default lookups are exact
~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1578,3 +1587,23 @@ get_FOO_height() and get_FOO_width()
For every ``ImageField``, the object will have ``get_FOO_height()`` and
``get_FOO_width()`` methods, where ``FOO`` is the name of the field. This
returns the height (or width) of the image, as an integer, in pixels.
+
+Falling back to raw SQL
+=======================
+
+If you find yourself needing to write an SQL query that is too complex for
+Django's database-mapper to handle, you can fall back into raw-SQL statement
+mode.
+
+The preferred way to do this is by giving your model custom methods or custom
+manager methods that execute queries. Although there's nothing in Django that
+*requires* database queries to live in the model layer, this approach keeps all
+your data-access logic in one place, which is smart from an code-organization
+standpoint. For instructions, see `Executing custom SQL`_.
+
+Finally, it's important to note that the Django database layer is merely an
+interface to your database. You can access your database via other tools,
+programming languages or database frameworks; there's nothing Django-specific
+about your database.
+
+.. _Executing custom SQL: http://www.djangoproject.com/documentation/model_api/#executing-custom-sql
diff --git a/docs/django-admin.txt b/docs/django-admin.txt
index 90f5f5e4ed..3334ae4530 100644
--- a/docs/django-admin.txt
+++ b/docs/django-admin.txt
@@ -148,7 +148,11 @@ If you run this script as a user with normal privileges (recommended), you
might not have access to start a port on a low port number. Low port numbers
are reserved for the superuser (root).
-DO NOT USE THIS SERVER IN A PRODUCTION SETTING.
+DO NOT USE THIS SERVER IN A PRODUCTION SETTING. It has not gone through
+security audits or performance tests. (And that's how it's gonna stay. We're in
+the business of making Web frameworks, not Web servers, so improving this
+server to be able to handle a production environment is outside the scope of
+Django.)
The development server automatically reloads Python code for each request, as
needed. You don't need to restart the server for code changes to take effect.
diff --git a/docs/faq.txt b/docs/faq.txt
index d63c02550e..a2c069f0ca 100644
--- a/docs/faq.txt
+++ b/docs/faq.txt
@@ -112,7 +112,7 @@ Lawrence, Kansas, USA.
.. _`Simon Willison`: http://simon.incutio.com/
.. _`simon.incutio.com`: http://simon.incutio.com/
.. _`Jacob Kaplan-Moss`: http://www.jacobian.org/
-.. _`Wilson Miner`: http://www.wilsonminer.com/live/
+.. _`Wilson Miner`: http://www.wilsonminer.com/
Which sites use Django?
-----------------------
diff --git a/docs/generic_views.txt b/docs/generic_views.txt
index 317828a2b2..d14fe12418 100644
--- a/docs/generic_views.txt
+++ b/docs/generic_views.txt
@@ -641,8 +641,10 @@ A page representing a list of objects.
* ``paginate_by``: An integer specifying how many objects should be
displayed per page. If this is given, the view will paginate objects with
- ``paginate_by`` objects per page. The view will expect a ``page`` query
- string (GET) parameter containing a zero-indexed page number.
+ ``paginate_by`` objects per page. The view will expect either a ``page``
+ query string parameter (via ``GET``) containing a zero-indexed page
+ number, or a ``page`` variable specified in the URLconf. See
+ "Notes on pagination" below.
* ``template_name``: The full name of a template to use in rendering the
page. This lets you override the default template name (see below).
@@ -711,6 +713,25 @@ If the results are paginated, the context will contain these extra variables:
* ``hits``: The total number of objects across *all* pages, not just this
page.
+Notes on pagination
+~~~~~~~~~~~~~~~~~~~
+
+If ``paginate_by`` is specified, Django will paginate the results. You can
+specify the page number in the URL in one of two ways:
+
+ * Use the ``page`` parameter in the URLconf. For example, this is what
+ your URLconf might look like::
+
+ (r'^objects/page(?P[0-9]+)/$', 'object_list', dict(info_dict))
+
+ * Pass the page number via the ``page`` query-string parameter. For
+ example, a URL would look like this:
+
+ /objects/?page=3
+
+In both cases, ``page`` is 1-based, not 0-based, so the first page would be
+represented as page ``1``.
+
``django.views.generic.list_detail.object_detail``
--------------------------------------------------
diff --git a/docs/model-api.txt b/docs/model-api.txt
index 9cc5b8f203..c6707a691b 100644
--- a/docs/model-api.txt
+++ b/docs/model-api.txt
@@ -1239,6 +1239,12 @@ The above code results in an admin change list page that looks like this:
(This example also has ``search_fields`` defined. See below.)
+``list_per_page``
+-----------------
+
+Set ``list_per_page`` to control how many items appear on each paginated admin
+change list page. By default, this is set to ``100``.
+
``list_select_related``
-----------------------
diff --git a/docs/settings.txt b/docs/settings.txt
index 26d5930f21..553736b280 100644
--- a/docs/settings.txt
+++ b/docs/settings.txt
@@ -291,7 +291,7 @@ The default formatting to use for date fields on Django admin change-list
pages -- and, possibly, by other parts of the system. See
`allowed date format strings`_.
-See also DATETIME_FORMAT and TIME_FORMAT.
+See also DATETIME_FORMAT, TIME_FORMAT, YEAR_MONTH_FORMAT and MONTH_DAY_FORMAT.
.. _allowed date format strings: http://www.djangoproject.com/documentation/templates/#now
@@ -304,7 +304,7 @@ The default formatting to use for datetime fields on Django admin change-list
pages -- and, possibly, by other parts of the system. See
`allowed date format strings`_.
-See also DATE_FORMAT and TIME_FORMAT.
+See also DATE_FORMAT, DATETIME_FORMAT, TIME_FORMAT, YEAR_MONTH_FORMAT and MONTH_DAY_FORMAT.
.. _allowed date format strings: http://www.djangoproject.com/documentation/templates/#now
@@ -532,6 +532,23 @@ Default::
A tuple of middleware classes to use. See the `middleware docs`_.
+MONTH_DAY_FORMAT
+----------------
+
+Default: ``'F j'``
+
+The default formatting to use for date fields on Django admin change-list
+pages -- and, possibly, by other parts of the system -- in cases when only the
+month and day are displayed.
+
+For example, when a Django admin change-list page is being filtered by a date
+drilldown, the header for a given day displays the day and month. Different
+locales have different formats. For example, U.S. English would say
+"January 1," whereas Spanish might say "1 Enero."
+
+See `allowed date format strings`_. See also DATE_FORMAT, DATETIME_FORMAT,
+TIME_FORMAT and YEAR_MONTH_FORMAT.
+
PREPEND_WWW
-----------
@@ -696,7 +713,8 @@ The default formatting to use for time fields on Django admin change-list
pages -- and, possibly, by other parts of the system. See
`allowed date format strings`_.
-See also DATE_FORMAT and DATETIME_FORMAT.
+See also DATE_FORMAT, DATETIME_FORMAT, TIME_FORMAT, YEAR_MONTH_FORMAT and
+MONTH_DAY_FORMAT.
.. _allowed date format strings: http://www.djangoproject.com/documentation/templates/#now
@@ -720,6 +738,23 @@ A boolean that specifies whether to output the "Etag" header. This saves
bandwidth but slows down performance. This is only used if ``CommonMiddleware``
is installed (see the `middleware docs`_).
+YEAR_MONTH_FORMAT
+-----------------
+
+Default: ``'F Y'``
+
+The default formatting to use for date fields on Django admin change-list
+pages -- and, possibly, by other parts of the system -- in cases when only the
+year and month are displayed.
+
+For example, when a Django admin change-list page is being filtered by a date
+drilldown, the header for a given month displays the month and the year.
+Different locales have different formats. For example, U.S. English would say
+"January 2006," whereas another locale might say "2006/January."
+
+See `allowed date format strings`_. See also DATE_FORMAT, DATETIME_FORMAT,
+TIME_FORMAT and MONTH_DAY_FORMAT.
+
.. _cache docs: http://www.djangoproject.com/documentation/cache/
.. _middleware docs: http://www.djangoproject.com/documentation/middleware/
.. _session docs: http://www.djangoproject.com/documentation/sessions/
diff --git a/docs/templates.txt b/docs/templates.txt
index 8d5a383b8c..c191b409f4 100644
--- a/docs/templates.txt
+++ b/docs/templates.txt
@@ -1091,3 +1091,27 @@ Value Argument Outputs
``None`` ``"yeah,no"`` ``"no"`` (converts None to False
if no mapping for None is given)
========== ====================== ==================================
+
+Other tags and filter libraries
+===============================
+
+Django comes with a couple of other template-tag libraries that you have to
+enable explicitly in your ``INSTALLED_APPS`` setting and enable in your
+template with the ``{% load %}`` tag.
+
+django.contrib.humanize
+-----------------------
+
+A set of Django template filters useful for adding a "human touch" to data. See
+the `humanize documentation`_.
+
+.. _humanize documentation: http://www.djangoproject.com/documentation/add_ons/#humanize
+
+django.contrib.markup
+---------------------
+
+A collection of template filters that implement these common markup languages:
+
+ * Textile
+ * Markdown
+ * ReST (ReStructured Text)
diff --git a/docs/templates_python.txt b/docs/templates_python.txt
index 6c33052792..dea5bcbee6 100644
--- a/docs/templates_python.txt
+++ b/docs/templates_python.txt
@@ -368,6 +368,11 @@ Generally, you'll store templates in files on your filesystem rather than using
the low-level ``Template`` API yourself. Save templates in a directory
specified as a **template directory**.
+Django searches for template directories in a number of places, depending on
+your template-loader settings (see "Loader types" below), but the most basic
+way of specifying template directories is by using the ``TEMPLATE_DIRS``
+setting.
+
The TEMPLATE_DIRS setting
~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/setup.py b/setup.py
index a872eb10cc..90448b1ddf 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@ from setuptools import setup, find_packages
setup(
name = "Django",
- version = "0.91",
+ version = "0.95",
url = 'http://www.djangoproject.com/',
author = 'Lawrence Journal-World',
author_email = 'holovaty@gmail.com',
@@ -52,6 +52,7 @@ setup(
'media/img/admin/*.png',
'media/js/*.js',
'media/js/admin/*js'],
+ 'django.contrib.comments': ['templates/comments/*.html'],
},
scripts = ['django/bin/django-admin.py'],
zip_safe = False,
diff --git a/tests/modeltests/basic/models.py b/tests/modeltests/basic/models.py
index f60c3777e7..a4de0f9a81 100644
--- a/tests/modeltests/basic/models.py
+++ b/tests/modeltests/basic/models.py
@@ -9,9 +9,10 @@ from django.db import models
class Article(models.Model):
headline = models.CharField(maxlength=100, default='Default headline')
pub_date = models.DateTimeField()
-
- def __repr__(self):
+
+ def __str__(self):
return self.headline
+
API_TESTS = """
# No articles are in the system yet.
@@ -39,34 +40,34 @@ datetime.datetime(2005, 7, 28, 0, 0)
>>> a.headline = 'Area woman programs in Python'
>>> a.save()
-# Article.objects.all() returns all the articles in the database.
+# Article.objects.all() returns all the articles in the database.
>>> Article.objects.all()
-[Area woman programs in Python]
+[]
# Django provides a rich database lookup API.
>>> Article.objects.get(id__exact=1)
-Area woman programs in Python
+
>>> Article.objects.get(headline__startswith='Area woman')
-Area woman programs in Python
+
>>> Article.objects.get(pub_date__year=2005)
-Area woman programs in Python
+
>>> Article.objects.get(pub_date__year=2005, pub_date__month=7)
-Area woman programs in Python
+
>>> Article.objects.get(pub_date__year=2005, pub_date__month=7, pub_date__day=28)
-Area woman programs in Python
+
# The "__exact" lookup type can be omitted, as a shortcut.
>>> Article.objects.get(id=1)
-Area woman programs in Python
+
>>> Article.objects.get(headline='Area woman programs in Python')
-Area woman programs in Python
+
>>> Article.objects.filter(pub_date__year=2005)
-[Area woman programs in Python]
+[]
>>> Article.objects.filter(pub_date__year=2004)
[]
>>> Article.objects.filter(pub_date__year=2005, pub_date__month=7)
-[Area woman programs in Python]
+[]
# Django raises an Article.DoesNotExist exception for get() if the parameters
# don't match any object.
@@ -84,7 +85,7 @@ DoesNotExist: Article matching query does not exist.
# shortcut for primary-key exact lookups.
# The following is identical to articles.get(id=1).
>>> Article.objects.get(pk=1)
-Area woman programs in Python
+
# Model instances of the same type and same ID are considered equal.
>>> a = Article.objects.get(pk=1)
@@ -222,7 +223,7 @@ datetime.datetime(2005, 7, 28, 0, 0)
>>> s1 = Article.objects.filter(id__exact=1)
>>> s2 = Article.objects.filter(id__exact=2)
>>> s1 | s2
-[Area woman programs in Python, Second article]
+[, ]
>>> s1 & s2
[]
@@ -232,34 +233,34 @@ datetime.datetime(2005, 7, 28, 0, 0)
# You can get items using index and slice notation.
>>> Article.objects.all()[0]
-Area woman programs in Python
+
>>> Article.objects.all()[1:3]
-[Second article, Third article]
+[, ]
>>> s3 = Article.objects.filter(id__exact=3)
>>> (s1 | s2 | s3)[::2]
-[Area woman programs in Python, Third article]
+[, ]
# Slices (without step) are lazy:
>>> Article.objects.all()[0:5].filter()
-[Area woman programs in Python, Second article, Third article, Fourth article, Article 6]
+[, , , , ]
# Slicing again works:
>>> Article.objects.all()[0:5][0:2]
-[Area woman programs in Python, Second article]
+[, ]
>>> Article.objects.all()[0:5][:2]
-[Area woman programs in Python, Second article]
+[, ]
>>> Article.objects.all()[0:5][4:]
-[Article 6]
+[]
>>> Article.objects.all()[0:5][5:]
[]
# Some more tests!
>>> Article.objects.all()[2:][0:2]
-[Third article, Fourth article]
+[, ]
>>> Article.objects.all()[2:][:2]
-[Third article, Fourth article]
+[, ]
>>> Article.objects.all()[2:][2:3]
-[Article 6]
+[]
# Note that you can't use 'offset' without 'limit' (on some dbs), so this doesn't work:
>>> Article.objects.all()[2:]
@@ -308,10 +309,10 @@ AttributeError: Manager isn't accessible via Article instances
# Bulk delete test: How many objects before and after the delete?
>>> Article.objects.all()
-[Area woman programs in Python, Second article, Third article, Fourth article, Article 6, Default headline, Article 7, Updated article 8]
+[, , , , , , , ]
>>> Article.objects.filter(id__lte=4).delete()
>>> Article.objects.all()
-[Article 6, Default headline, Article 7, Updated article 8]
+[, , , ]
"""
diff --git a/tests/modeltests/choices/models.py b/tests/modeltests/choices/models.py
index 38dcb934c5..881fb29fd2 100644
--- a/tests/modeltests/choices/models.py
+++ b/tests/modeltests/choices/models.py
@@ -20,7 +20,7 @@ class Person(models.Model):
name = models.CharField(maxlength=20)
gender = models.CharField(maxlength=1, choices=GENDER_CHOICES)
- def __repr__(self):
+ def __str__(self):
return self.name
API_TESTS = """
diff --git a/tests/modeltests/custom_columns/models.py b/tests/modeltests/custom_columns/models.py
index 4958517e69..7d8c52d137 100644
--- a/tests/modeltests/custom_columns/models.py
+++ b/tests/modeltests/custom_columns/models.py
@@ -12,7 +12,7 @@ class Person(models.Model):
first_name = models.CharField(maxlength=30, db_column='firstname')
last_name = models.CharField(maxlength=30, db_column='last')
- def __repr__(self):
+ def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
API_TESTS = """
@@ -24,13 +24,13 @@ API_TESTS = """
1
>>> Person.objects.all()
-[John Smith]
+[]
>>> Person.objects.filter(first_name__exact='John')
-[John Smith]
+[]
>>> Person.objects.get(first_name__exact='John')
-John Smith
+
>>> Person.objects.filter(firstname__exact='John')
Traceback (most recent call last):
diff --git a/tests/modeltests/custom_managers/models.py b/tests/modeltests/custom_managers/models.py
index ceecea2fc6..1c4e91b526 100644
--- a/tests/modeltests/custom_managers/models.py
+++ b/tests/modeltests/custom_managers/models.py
@@ -23,7 +23,7 @@ class Person(models.Model):
fun = models.BooleanField()
objects = PersonManager()
- def __repr__(self):
+ def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
# An example of a custom manager that sets get_query_set().
@@ -39,7 +39,7 @@ class Book(models.Model):
published_objects = PublishedBookManager()
authors = models.ManyToManyField(Person, related_name='books')
- def __repr__(self):
+ def __str__(self):
return self.title
# An example of providing multiple custom managers.
@@ -55,7 +55,7 @@ class Car(models.Model):
cars = models.Manager()
fast_cars = FastCarManager()
- def __repr__(self):
+ def __str__(self):
return self.name
API_TESTS = """
@@ -64,7 +64,7 @@ API_TESTS = """
>>> p2 = Person(first_name='Droopy', last_name='Dog', fun=False)
>>> p2.save()
>>> Person.objects.get_fun_people()
-[Bugs Bunny]
+[]
# The RelatedManager used on the 'books' descriptor extends the default manager
>>> from modeltests.custom_managers.models import PublishedBookManager
@@ -89,19 +89,19 @@ AttributeError: type object 'Book' has no attribute 'objects'
True
>>> Book.published_objects.all()
-[How to program]
+[]
>>> c1 = Car(name='Corvette', mileage=21, top_speed=180)
>>> c1.save()
>>> c2 = Car(name='Neon', mileage=31, top_speed=100)
>>> c2.save()
>>> Car.cars.order_by('name')
-[Corvette, Neon]
+[, ]
>>> Car.fast_cars.all()
-[Corvette]
+[]
# Each model class gets a "_default_manager" attribute, which is a reference
# to the first manager defined in the class. In this case, it's "cars".
>>> Car._default_manager.order_by('name')
-[Corvette, Neon]
+[, ]
"""
diff --git a/tests/modeltests/custom_methods/models.py b/tests/modeltests/custom_methods/models.py
index 6cc3fe8548..e314d97264 100644
--- a/tests/modeltests/custom_methods/models.py
+++ b/tests/modeltests/custom_methods/models.py
@@ -11,16 +11,16 @@ class Article(models.Model):
headline = models.CharField(maxlength=100)
pub_date = models.DateField()
- def __repr__(self):
+ def __str__(self):
return self.headline
def was_published_today(self):
return self.pub_date == datetime.date.today()
- def get_articles_from_same_day_1(self):
+ def articles_from_same_day_1(self):
return Article.objects.filter(pub_date=self.pub_date).exclude(id=self.id)
- def get_articles_from_same_day_2(self):
+ def articles_from_same_day_2(self):
"""
Verbose version of get_articles_from_same_day_1, which does a custom
database query for the sake of demonstration.
@@ -47,12 +47,12 @@ API_TESTS = """
# Test the custom methods.
>>> a.was_published_today()
False
->>> a.get_articles_from_same_day_1()
-[Beatles reunite]
->>> a.get_articles_from_same_day_2()
-[Beatles reunite]
->>> b.get_articles_from_same_day_1()
-[Area man programs in Python]
->>> b.get_articles_from_same_day_2()
-[Area man programs in Python]
+>>> a.articles_from_same_day_1()
+[]
+>>> a.articles_from_same_day_2()
+[]
+>>> b.articles_from_same_day_1()
+[]
+>>> b.articles_from_same_day_2()
+[]
"""
diff --git a/tests/modeltests/custom_pk/models.py b/tests/modeltests/custom_pk/models.py
index fed2c25515..6193852adf 100644
--- a/tests/modeltests/custom_pk/models.py
+++ b/tests/modeltests/custom_pk/models.py
@@ -14,7 +14,7 @@ class Employee(models.Model):
class Meta:
ordering = ('last_name', 'first_name')
- def __repr__(self):
+ def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
class Business(models.Model):
@@ -23,24 +23,24 @@ class Business(models.Model):
class Meta:
verbose_name_plural = 'businesses'
- def __repr__(self):
+ def __str__(self):
return self.name
API_TESTS = """
>>> dan = Employee(employee_code='ABC123', first_name='Dan', last_name='Jones')
>>> dan.save()
>>> Employee.objects.all()
-[Dan Jones]
+[]
>>> fran = Employee(employee_code='XYZ456', first_name='Fran', last_name='Bones')
>>> fran.save()
>>> Employee.objects.all()
-[Fran Bones, Dan Jones]
+[, ]
>>> Employee.objects.get(pk='ABC123')
-Dan Jones
+
>>> Employee.objects.get(pk='XYZ456')
-Fran Bones
+
>>> Employee.objects.get(pk='foo')
Traceback (most recent call last):
...
@@ -48,43 +48,43 @@ DoesNotExist: Employee matching query does not exist.
# Use the name of the primary key, rather than pk.
>>> Employee.objects.get(employee_code__exact='ABC123')
-Dan Jones
+
# Fran got married and changed her last name.
>>> fran = Employee.objects.get(pk='XYZ456')
>>> fran.last_name = 'Jones'
>>> fran.save()
>>> Employee.objects.filter(last_name__exact='Jones')
-[Dan Jones, Fran Jones]
+[, ]
>>> Employee.objects.in_bulk(['ABC123', 'XYZ456'])
-{'XYZ456': Fran Jones, 'ABC123': Dan Jones}
+{'XYZ456': , 'ABC123': }
>>> b = Business(name='Sears')
>>> b.save()
>>> b.employees.add(dan, fran)
>>> b.employees.all()
-[Dan Jones, Fran Jones]
+[, ]
>>> fran.business_set.all()
-[Sears]
+[]
>>> Business.objects.in_bulk(['Sears'])
-{'Sears': Sears}
+{'Sears': }
>>> Business.objects.filter(name__exact='Sears')
-[Sears]
+[]
>>> Business.objects.filter(pk='Sears')
-[Sears]
+[]
# Queries across tables, involving primary key
>>> Employee.objects.filter(business__name__exact='Sears')
-[Dan Jones, Fran Jones]
+[, ]
>>> Employee.objects.filter(business__pk='Sears')
-[Dan Jones, Fran Jones]
+[, ]
>>> Business.objects.filter(employees__employee_code__exact='ABC123')
-[Sears]
+[]
>>> Business.objects.filter(employees__pk='ABC123')
-[Sears]
+[]
>>> Business.objects.filter(employees__first_name__startswith='Fran')
-[Sears]
+[]
"""
diff --git a/tests/modeltests/get_latest/models.py b/tests/modeltests/get_latest/models.py
index 0af2146c64..42e7a14ec7 100644
--- a/tests/modeltests/get_latest/models.py
+++ b/tests/modeltests/get_latest/models.py
@@ -17,7 +17,7 @@ class Article(models.Model):
class Meta:
get_latest_by = 'pub_date'
- def __repr__(self):
+ def __str__(self):
return self.headline
class Person(models.Model):
@@ -26,7 +26,7 @@ class Person(models.Model):
# Note that this model doesn't have "get_latest_by" set.
- def __repr__(self):
+ def __str__(self):
return self.name
API_TESTS = """
@@ -49,19 +49,19 @@ DoesNotExist: Article matching query does not exist.
# Get the latest Article.
>>> Article.objects.latest()
-Article 4
+
# Get the latest Article that matches certain filters.
>>> Article.objects.filter(pub_date__lt=datetime(2005, 7, 27)).latest()
-Article 1
+
# Pass a custom field name to latest() to change the field that's used to
# determine the latest object.
>>> Article.objects.latest('expire_date')
-Article 1
+
>>> Article.objects.filter(pub_date__gt=datetime(2005, 7, 26)).latest('expire_date')
-Article 3
+
# You can still use latest() with a model that doesn't have "get_latest_by"
# set -- just pass in the field name manually.
@@ -75,5 +75,5 @@ Traceback (most recent call last):
AssertionError: latest() requires either a field_name parameter or 'get_latest_by' in the model
>>> Person.objects.latest('birthday')
-Stephanie
+
"""
diff --git a/tests/modeltests/lookup/models.py b/tests/modeltests/lookup/models.py
index 4b8454f855..9ac53b1677 100644
--- a/tests/modeltests/lookup/models.py
+++ b/tests/modeltests/lookup/models.py
@@ -12,7 +12,7 @@ class Article(models.Model):
class Meta:
ordering = ('-pub_date', 'headline')
- def __repr__(self):
+ def __str__(self):
return self.headline
API_TESTS = """
@@ -61,9 +61,9 @@ Article 4
# in_bulk() takes a list of IDs and returns a dictionary mapping IDs
# to objects.
>>> Article.objects.in_bulk([1, 2])
-{1: Article 1, 2: Article 2}
+{1: , 2: }
>>> Article.objects.in_bulk([3])
-{3: Article 3}
+{3: }
>>> Article.objects.in_bulk([1000])
{}
>>> Article.objects.in_bulk([])
@@ -125,55 +125,55 @@ True
# In the case of identical date values, these methods will use the ID as a
# fallback check. This guarantees that no records are skipped or duplicated.
>>> a1.get_next_by_pub_date()
-Article 2
+
>>> a2.get_next_by_pub_date()
-Article 3
+
>>> a3.get_next_by_pub_date()
-Article 7
+
>>> a4.get_next_by_pub_date()
-Article 6
+
>>> a5.get_next_by_pub_date()
Traceback (most recent call last):
...
DoesNotExist: Article matching query does not exist.
>>> a6.get_next_by_pub_date()
-Article 5
+
>>> a7.get_next_by_pub_date()
-Article 4
+
>>> a7.get_previous_by_pub_date()
-Article 3
+
>>> a6.get_previous_by_pub_date()
-Article 4
+
>>> a5.get_previous_by_pub_date()
-Article 6
+
>>> a4.get_previous_by_pub_date()
-Article 7
+
>>> a3.get_previous_by_pub_date()
-Article 2
+
>>> a2.get_previous_by_pub_date()
-Article 1
+
# Underscores and percent signs have special meaning in the underlying
# database library, but Django handles the quoting of them automatically.
>>> a8 = Article(headline='Article_ with underscore', pub_date=datetime(2005, 11, 20))
>>> a8.save()
>>> Article.objects.filter(headline__startswith='Article')
-[Article_ with underscore, Article 5, Article 6, Article 4, Article 2, Article 3, Article 7, Article 1]
+[, , , , , , , ]
>>> Article.objects.filter(headline__startswith='Article_')
-[Article_ with underscore]
+[]
>>> a9 = Article(headline='Article% with percent sign', pub_date=datetime(2005, 11, 21))
>>> a9.save()
>>> Article.objects.filter(headline__startswith='Article')
-[Article% with percent sign, Article_ with underscore, Article 5, Article 6, Article 4, Article 2, Article 3, Article 7, Article 1]
+[, , , , , , , , ]
>>> Article.objects.filter(headline__startswith='Article%')
-[Article% with percent sign]
+[]
# exclude() is the opposite of filter() when doing lookups:
>>> Article.objects.filter(headline__contains='Article').exclude(headline__contains='with')
-[Article 5, Article 6, Article 4, Article 2, Article 3, Article 7, Article 1]
+[, , , , , , ]
>>> Article.objects.exclude(headline__startswith="Article_")
-[Article% with percent sign, Article 5, Article 6, Article 4, Article 2, Article 3, Article 7, Article 1]
+[, , , , , , , ]
>>> Article.objects.exclude(headline="Article 7")
-[Article% with percent sign, Article_ with underscore, Article 5, Article 6, Article 4, Article 2, Article 3, Article 1]
+[, , , , , , , ]
"""
diff --git a/tests/modeltests/m2m_intermediary/models.py b/tests/modeltests/m2m_intermediary/models.py
index 869b188521..848d035c39 100644
--- a/tests/modeltests/m2m_intermediary/models.py
+++ b/tests/modeltests/m2m_intermediary/models.py
@@ -16,14 +16,14 @@ class Reporter(models.Model):
first_name = models.CharField(maxlength=30)
last_name = models.CharField(maxlength=30)
- def __repr__(self):
+ def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
class Article(models.Model):
headline = models.CharField(maxlength=100)
pub_date = models.DateField()
- def __repr__(self):
+ def __str__(self):
return self.headline
class Writer(models.Model):
@@ -31,8 +31,8 @@ class Writer(models.Model):
article = models.ForeignKey(Article)
position = models.CharField(maxlength=100)
- def __repr__(self):
- return '%r (%s)' % (self.reporter, self.position)
+ def __str__(self):
+ return '%s (%s)' % (self.reporter, self.position)
API_TESTS = """
# Create a few Reporters.
@@ -54,15 +54,15 @@ API_TESTS = """
# Play around with the API.
>>> a.writer_set.select_related().order_by('-position')
-[John Smith (Main writer), Jane Doe (Contributor)]
+[, ]
>>> w1.reporter
-John Smith
+
>>> w2.reporter
-Jane Doe
+
>>> w1.article
-This is a test
+
>>> w2.article
-This is a test
+
>>> r1.writer_set.all()
-[John Smith (Main writer)]
+[]
"""
diff --git a/tests/modeltests/m2m_multiple/models.py b/tests/modeltests/m2m_multiple/models.py
index 3fec427c1d..e4fef75f19 100644
--- a/tests/modeltests/m2m_multiple/models.py
+++ b/tests/modeltests/m2m_multiple/models.py
@@ -14,7 +14,7 @@ class Category(models.Model):
class Meta:
ordering = ('name',)
- def __repr__(self):
+ def __str__(self):
return self.name
class Article(models.Model):
@@ -25,7 +25,7 @@ class Article(models.Model):
class Meta:
ordering = ('pub_date',)
- def __repr__(self):
+ def __str__(self):
return self.headline
API_TESTS = """
@@ -51,29 +51,29 @@ API_TESTS = """
>>> a2.secondary_categories.add(c4)
>>> a1.primary_categories.all()
-[Crime, News]
+[, ]
>>> a2.primary_categories.all()
-[News, Sports]
+[, ]
>>> a1.secondary_categories.all()
-[Life]
+[]
>>> c1.primary_article_set.all()
-[Area man runs]
+[]
>>> c1.secondary_article_set.all()
[]
>>> c2.primary_article_set.all()
-[Area man steals, Area man runs]
+[, ]
>>> c2.secondary_article_set.all()
[]
>>> c3.primary_article_set.all()
-[Area man steals]
+[]
>>> c3.secondary_article_set.all()
[]
>>> c4.primary_article_set.all()
[]
>>> c4.secondary_article_set.all()
-[Area man steals, Area man runs]
+[, ]
"""
diff --git a/tests/modeltests/m2m_recursive/models.py b/tests/modeltests/m2m_recursive/models.py
index 877a41fd14..c109b9cc2c 100644
--- a/tests/modeltests/m2m_recursive/models.py
+++ b/tests/modeltests/m2m_recursive/models.py
@@ -19,7 +19,7 @@ class Person(models.Model):
friends = models.ManyToManyField('self')
idols = models.ManyToManyField('self', symmetrical=False, related_name='stalkers')
- def __repr__(self):
+ def __str__(self):
return self.name
API_TESTS = """
@@ -41,37 +41,37 @@ API_TESTS = """
# Who is friends with Anne?
>>> a.friends.all()
-[Bill, Chuck, David]
+[, , ]
# Who is friends with Bill?
>>> b.friends.all()
-[Anne]
+[]
# Who is friends with Chuck?
>>> c.friends.all()
-[Anne, David]
+[, ]
# Who is friends with David?
>>> d.friends.all()
-[Anne, Chuck]
+[, ]
# Bill is already friends with Anne - add Anne again, but in the reverse direction
>>> b.friends.add(a)
# Who is friends with Anne?
>>> a.friends.all()
-[Bill, Chuck, David]
+[, , ]
# Who is friends with Bill?
>>> b.friends.all()
-[Anne]
+[]
# Remove Anne from Bill's friends
>>> b.friends.remove(a)
# Who is friends with Anne?
>>> a.friends.all()
-[Chuck, David]
+[, ]
# Who is friends with Bill?
>>> b.friends.all()
@@ -87,11 +87,11 @@ API_TESTS = """
# Reverse relationships should also be gone
# Who is friends with Chuck?
>>> c.friends.all()
-[David]
+[]
# Who is friends with David?
>>> d.friends.all()
-[Chuck]
+[]
# Add some idols in the direction of field definition
@@ -106,27 +106,27 @@ API_TESTS = """
# Who are Anne's idols?
>>> a.idols.all()
-[Bill, Chuck, David]
+[, , ]
# Who is stalking Anne?
>>> a.stalkers.all()
-[Bill]
+[]
# Who are Bill's idols?
>>> b.idols.all()
-[Anne]
+[]
# Who is stalking Bill?
>>> b.stalkers.all()
-[Anne]
+[]
# Who are Chuck's idols?
>>> c.idols.all()
-[David]
+[]
# Who is stalking Chuck?
>>> c.stalkers.all()
-[Anne]
+[]
# Who are David's idols?
>>> d.idols.all()
@@ -134,40 +134,40 @@ API_TESTS = """
# Who is stalking David
>>> d.stalkers.all()
-[Anne, Chuck]
+[, ]
# Bill is already being stalked by Anne - add Anne again, but in the reverse direction
>>> b.stalkers.add(a)
# Who are Anne's idols?
>>> a.idols.all()
-[Bill, Chuck, David]
+[, , ]
# Who is stalking Anne?
-[Bill]
+[]
# Who are Bill's idols
>>> b.idols.all()
-[Anne]
+[]
# Who is stalking Bill?
>>> b.stalkers.all()
-[Anne]
+[]
# Remove Anne from Bill's list of stalkers
>>> b.stalkers.remove(a)
# Who are Anne's idols?
>>> a.idols.all()
-[Chuck, David]
+[, ]
# Who is stalking Anne?
>>> a.stalkers.all()
-[Bill]
+[]
# Who are Bill's idols?
>>> b.idols.all()
-[Anne]
+[]
# Who is stalking Bill?
>>> b.stalkers.all()
@@ -187,6 +187,6 @@ API_TESTS = """
# Who is friends with David?
>>> d.stalkers.all()
-[Chuck]
+[]
"""
diff --git a/tests/modeltests/m2o_recursive/models.py b/tests/modeltests/m2o_recursive/models.py
index e7996bc15f..44881b5a2f 100644
--- a/tests/modeltests/m2o_recursive/models.py
+++ b/tests/modeltests/m2o_recursive/models.py
@@ -16,7 +16,7 @@ class Category(models.Model):
name = models.CharField(maxlength=20)
parent = models.ForeignKey('self', null=True, related_name='child_set')
- def __repr__(self):
+ def __str__(self):
return self.name
API_TESTS = """
@@ -27,14 +27,14 @@ API_TESTS = """
>>> c.save()
>>> r.child_set.all()
-[Child category]
+[]
>>> r.child_set.get(name__startswith='Child')
-Child category
+
>>> print r.parent
None
>>> c.child_set.all()
[]
>>> c.parent
-Root category
+
"""
diff --git a/tests/modeltests/m2o_recursive2/models.py b/tests/modeltests/m2o_recursive2/models.py
index 40b842dc92..93185c6a4c 100644
--- a/tests/modeltests/m2o_recursive2/models.py
+++ b/tests/modeltests/m2o_recursive2/models.py
@@ -14,7 +14,7 @@ class Person(models.Model):
mother = models.ForeignKey('self', null=True, related_name='mothers_child_set')
father = models.ForeignKey('self', null=True, related_name='fathers_child_set')
- def __repr__(self):
+ def __str__(self):
return self.full_name
API_TESTS = """
@@ -29,13 +29,13 @@ API_TESTS = """
>>> kid.save()
>>> kid.mother
-Jane Smith
+
>>> kid.father
-John Smith Senior
+
>>> dad.fathers_child_set.all()
-[John Smith Junior]
+[]
>>> mom.mothers_child_set.all()
-[John Smith Junior]
+[]
>>> kid.mothers_child_set.all()
[]
>>> kid.fathers_child_set.all()
diff --git a/tests/modeltests/manipulators/models.py b/tests/modeltests/manipulators/models.py
index cf833cc468..f7b20d52ac 100644
--- a/tests/modeltests/manipulators/models.py
+++ b/tests/modeltests/manipulators/models.py
@@ -10,7 +10,7 @@ class Musician(models.Model):
first_name = models.CharField(maxlength=30)
last_name = models.CharField(maxlength=30)
- def __repr__(self):
+ def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
class Album(models.Model):
@@ -18,7 +18,7 @@ class Album(models.Model):
musician = models.ForeignKey(Musician)
release_date = models.DateField(blank=True, null=True)
- def __repr__(self):
+ def __str__(self):
return self.name
API_TESTS = """
@@ -35,7 +35,7 @@ API_TESTS = """
# Verify it worked.
>>> Musician.objects.all()
-[Ella Fitzgerald]
+[]
>>> [m1] == list(Musician.objects.all())
True
@@ -69,9 +69,9 @@ True
# Verify it worked.
>>> Album.objects.all()
-[Ella and Basie]
+[]
>>> Album.objects.get().musician
-Ella Fitzgerald
+
# Create an Album with a release_date.
>>> data = MultiValueDict({'name': ['Ultimate Ella'], 'musician': ['1'], 'release_date': ['2005-02-13']})
@@ -82,10 +82,10 @@ Ella Fitzgerald
# Verify it worked.
>>> Album.objects.order_by('name')
-[Ella and Basie, Ultimate Ella]
+[, ]
>>> a2 = Album.objects.get(pk=2)
>>> a2
-Ultimate Ella
+
>>> a2.release_date
datetime.date(2005, 2, 13)
"""
diff --git a/tests/modeltests/many_to_many/models.py b/tests/modeltests/many_to_many/models.py
index 4422cb1a6a..e80afece46 100644
--- a/tests/modeltests/many_to_many/models.py
+++ b/tests/modeltests/many_to_many/models.py
@@ -12,7 +12,7 @@ from django.db import models
class Publication(models.Model):
title = models.CharField(maxlength=30)
- def __repr__(self):
+ def __str__(self):
return self.title
class Meta:
@@ -22,7 +22,7 @@ class Article(models.Model):
headline = models.CharField(maxlength=100)
publications = models.ManyToManyField(Publication)
- def __repr__(self):
+ def __str__(self):
return self.headline
class Meta:
@@ -58,29 +58,29 @@ API_TESTS = """
# Article objects have access to their related Publication objects.
>>> a1.publications.all()
-[The Python Journal]
+[]
>>> a2.publications.all()
-[Highlights for Children, Science News, Science Weekly, The Python Journal]
+[, , , ]
# Publication objects have access to their related Article objects.
>>> p2.article_set.all()
-[NASA uses Python]
+[]
>>> p1.article_set.all()
-[Django lets you build Web apps easily, NASA uses Python]
+[, ]
>>> Publication.objects.get(id=4).article_set.all()
-[NASA uses Python]
+[]
# We can perform kwarg queries across m2m relationships
>>> Article.objects.filter(publications__id__exact=1)
-[Django lets you build Web apps easily, NASA uses Python]
+[, ]
>>> Article.objects.filter(publications__pk=1)
-[Django lets you build Web apps easily, NASA uses Python]
+[, ]
>>> Article.objects.filter(publications__title__startswith="Science")
-[NASA uses Python, NASA uses Python]
+[, ]
>>> Article.objects.filter(publications__title__startswith="Science").distinct()
-[NASA uses Python]
+[]
# The count() function respects distinct() as well.
>>> Article.objects.filter(publications__title__startswith="Science").count()
@@ -92,23 +92,23 @@ API_TESTS = """
# Reverse m2m queries are supported (i.e., starting at the table that doesn't
# have a ManyToManyField).
>>> Publication.objects.filter(id__exact=1)
-[The Python Journal]
+[]
>>> Publication.objects.filter(pk=1)
-[The Python Journal]
+[]
>>> Publication.objects.filter(article__headline__startswith="NASA")
-[Highlights for Children, Science News, Science Weekly, The Python Journal]
+[, , , ]
>>> Publication.objects.filter(article__id__exact=1)
-[The Python Journal]
+[]
>>> Publication.objects.filter(article__pk=1)
-[The Python Journal]
+[]
# If we delete a Publication, its Articles won't be able to access it.
>>> p1.delete()
>>> Publication.objects.all()
-[Highlights for Children, Science News, Science Weekly]
+[, , ]
>>> a1 = Article.objects.get(pk=1)
>>> a1.publications.all()
[]
@@ -116,7 +116,7 @@ API_TESTS = """
# If we delete an Article, its Publications won't be able to access it.
>>> a2.delete()
>>> Article.objects.all()
-[Django lets you build Web apps easily]
+[]
>>> p2.article_set.all()
[]
@@ -125,22 +125,22 @@ API_TESTS = """
>>> a4.save()
>>> p2.article_set.add(a4)
>>> p2.article_set.all()
-[NASA finds intelligent life on Earth]
+[]
>>> a4.publications.all()
-[Science News]
+[]
# Adding via the other end using keywords
>>> new_article = p2.article_set.create(headline='Oxygen-free diet works wonders')
>>> p2.article_set.all()
-[NASA finds intelligent life on Earth, Oxygen-free diet works wonders]
+[, ]
>>> a5 = p2.article_set.all()[1]
>>> a5.publications.all()
-[Science News]
+[]
# Removing publication from an article:
>>> a4.publications.remove(p2)
>>> p2.article_set.all()
-[Oxygen-free diet works wonders]
+[]
>>> a4.publications.all()
[]
@@ -154,33 +154,33 @@ API_TESTS = """
# Relation sets can be assigned. Assignment clears any existing set members
>>> p2.article_set = [a4, a5]
>>> p2.article_set.all()
-[NASA finds intelligent life on Earth, Oxygen-free diet works wonders]
+[, ]
>>> a4.publications.all()
-[Science News]
+[