mirror of
https://github.com/django/django.git
synced 2025-07-04 01:39:20 +00:00
multi-auth: Merged to [3085]
git-svn-id: http://code.djangoproject.com/svn/django/branches/multi-auth@3086 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
0c341d780e
commit
e976ed1f79
@ -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
|
||||
|
Binary file not shown.
@ -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"
|
||||
|
@ -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'),
|
||||
|
||||
|
@ -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; }
|
||||
|
@ -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; }
|
||||
|
@ -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; }
|
||||
|
@ -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 */
|
||||
* 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 */
|
@ -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();
|
||||
}
|
||||
|
@ -19,9 +19,9 @@
|
||||
<div id="branding">
|
||||
{% block branding %}{% endblock %}
|
||||
</div>
|
||||
{% if not user.is_anonymous %}
|
||||
{% if not user.is_anonymous %}{% if user.is_staff %}
|
||||
<div id="user-tools">{% trans 'Welcome,' %} <strong>{% if user.first_name %}{{ user.first_name }}{% else %}{{ user.username }}{% endif %}</strong>. {% block userlinks %}<a href="doc/">{% trans 'Documentation' %}</a> / <a href="password_change/">{% trans 'Change password' %}</a> / <a href="logout/">{% trans 'Log out' %}</a>{% endblock %}</div>
|
||||
{% endif %}
|
||||
{% endif %}{% endif %}
|
||||
{% block nav-global %}{% endblock %}
|
||||
</div>
|
||||
<!-- END Header -->
|
||||
|
@ -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:
|
||||
|
@ -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], []
|
||||
|
@ -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():
|
||||
|
@ -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:
|
||||
|
0
django/contrib/humanize/templatetags/__init__.py
Normal file
0
django/contrib/humanize/templatetags/__init__.py
Normal file
64
django/contrib/humanize/templatetags/humanize.py
Normal file
64
django/contrib/humanize/templatetags/humanize.py
Normal file
@ -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)
|
@ -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)
|
||||
|
@ -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<id>\d+)/$'), id=3)
|
||||
'places/3/'
|
||||
>>> reverse_helper(re.compile('^people/(?P<state>\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<id>\d+)/$').reverse_helper(id=3)
|
||||
'places/3/'
|
||||
>>> RegexURLPattern('^people/(?P<state>\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
|
||||
|
@ -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:
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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 = {}
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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 ""
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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):
|
||||
|
@ -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():
|
||||
"""
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
=========
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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?
|
||||
-----------------------
|
||||
|
@ -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<page>[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``
|
||||
--------------------------------------------------
|
||||
|
||||
|
@ -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``
|
||||
-----------------------
|
||||
|
||||
|
@ -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/
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
3
setup.py
3
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,
|
||||
|
@ -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]
|
||||
[<Article: Area woman programs in Python>]
|
||||
|
||||
# Django provides a rich database lookup API.
|
||||
>>> Article.objects.get(id__exact=1)
|
||||
Area woman programs in Python
|
||||
<Article: Area woman programs in Python>
|
||||
>>> Article.objects.get(headline__startswith='Area woman')
|
||||
Area woman programs in Python
|
||||
<Article: Area woman programs in Python>
|
||||
>>> Article.objects.get(pub_date__year=2005)
|
||||
Area woman programs in Python
|
||||
<Article: Area woman programs in Python>
|
||||
>>> Article.objects.get(pub_date__year=2005, pub_date__month=7)
|
||||
Area woman programs in Python
|
||||
<Article: 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
|
||||
<Article: 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: Area woman programs in Python>
|
||||
>>> Article.objects.get(headline='Area woman programs in Python')
|
||||
Area woman programs in Python
|
||||
<Article: Area woman programs in Python>
|
||||
|
||||
>>> Article.objects.filter(pub_date__year=2005)
|
||||
[Area woman programs in Python]
|
||||
[<Article: 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]
|
||||
[<Article: 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
|
||||
<Article: 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]
|
||||
[<Article: Area woman programs in Python>, <Article: 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: Area woman programs in Python>
|
||||
>>> Article.objects.all()[1:3]
|
||||
[Second article, Third article]
|
||||
[<Article: Second article>, <Article: Third article>]
|
||||
>>> s3 = Article.objects.filter(id__exact=3)
|
||||
>>> (s1 | s2 | s3)[::2]
|
||||
[Area woman programs in Python, Third article]
|
||||
[<Article: Area woman programs in Python>, <Article: 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]
|
||||
[<Article: Area woman programs in Python>, <Article: Second article>, <Article: Third article>, <Article: Fourth article>, <Article: Article 6>]
|
||||
|
||||
# Slicing again works:
|
||||
>>> Article.objects.all()[0:5][0:2]
|
||||
[Area woman programs in Python, Second article]
|
||||
[<Article: Area woman programs in Python>, <Article: Second article>]
|
||||
>>> Article.objects.all()[0:5][:2]
|
||||
[Area woman programs in Python, Second article]
|
||||
[<Article: Area woman programs in Python>, <Article: Second article>]
|
||||
>>> Article.objects.all()[0:5][4:]
|
||||
[Article 6]
|
||||
[<Article: Article 6>]
|
||||
>>> Article.objects.all()[0:5][5:]
|
||||
[]
|
||||
|
||||
# Some more tests!
|
||||
>>> Article.objects.all()[2:][0:2]
|
||||
[Third article, Fourth article]
|
||||
[<Article: Third article>, <Article: Fourth article>]
|
||||
>>> Article.objects.all()[2:][:2]
|
||||
[Third article, Fourth article]
|
||||
[<Article: Third article>, <Article: Fourth article>]
|
||||
>>> Article.objects.all()[2:][2:3]
|
||||
[Article 6]
|
||||
[<Article: 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: Area woman programs in Python>, <Article: Second article>, <Article: Third article>, <Article: Fourth article>, <Article: Article 6>, <Article: Default headline>, <Article: Article 7>, <Article: Updated article 8>]
|
||||
>>> Article.objects.filter(id__lte=4).delete()
|
||||
>>> Article.objects.all()
|
||||
[Article 6, Default headline, Article 7, Updated article 8]
|
||||
[<Article: Article 6>, <Article: Default headline>, <Article: Article 7>, <Article: Updated article 8>]
|
||||
|
||||
"""
|
||||
|
||||
|
@ -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 = """
|
||||
|
@ -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: John Smith>]
|
||||
|
||||
>>> Person.objects.filter(first_name__exact='John')
|
||||
[John Smith]
|
||||
[<Person: John Smith>]
|
||||
|
||||
>>> Person.objects.get(first_name__exact='John')
|
||||
John Smith
|
||||
<Person: John Smith>
|
||||
|
||||
>>> Person.objects.filter(firstname__exact='John')
|
||||
Traceback (most recent call last):
|
||||
|
@ -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]
|
||||
[<Person: 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]
|
||||
[<Book: 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: Corvette>, <Car: Neon>]
|
||||
>>> Car.fast_cars.all()
|
||||
[Corvette]
|
||||
[<Car: 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]
|
||||
[<Car: Corvette>, <Car: Neon>]
|
||||
"""
|
||||
|
@ -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()
|
||||
[<Article: Beatles reunite>]
|
||||
>>> a.articles_from_same_day_2()
|
||||
[<Article: Beatles reunite>]
|
||||
>>> b.articles_from_same_day_1()
|
||||
[<Article: Area man programs in Python>]
|
||||
>>> b.articles_from_same_day_2()
|
||||
[<Article: Area man programs in Python>]
|
||||
"""
|
||||
|
@ -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]
|
||||
[<Employee: Dan Jones>]
|
||||
|
||||
>>> fran = Employee(employee_code='XYZ456', first_name='Fran', last_name='Bones')
|
||||
>>> fran.save()
|
||||
>>> Employee.objects.all()
|
||||
[Fran Bones, Dan Jones]
|
||||
[<Employee: Fran Bones>, <Employee: Dan Jones>]
|
||||
|
||||
>>> Employee.objects.get(pk='ABC123')
|
||||
Dan Jones
|
||||
<Employee: Dan Jones>
|
||||
>>> Employee.objects.get(pk='XYZ456')
|
||||
Fran Bones
|
||||
<Employee: 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
|
||||
<Employee: 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: Dan Jones>, <Employee: Fran Jones>]
|
||||
>>> Employee.objects.in_bulk(['ABC123', 'XYZ456'])
|
||||
{'XYZ456': Fran Jones, 'ABC123': Dan Jones}
|
||||
{'XYZ456': <Employee: Fran Jones>, 'ABC123': <Employee: Dan Jones>}
|
||||
|
||||
>>> b = Business(name='Sears')
|
||||
>>> b.save()
|
||||
>>> b.employees.add(dan, fran)
|
||||
>>> b.employees.all()
|
||||
[Dan Jones, Fran Jones]
|
||||
[<Employee: Dan Jones>, <Employee: Fran Jones>]
|
||||
>>> fran.business_set.all()
|
||||
[Sears]
|
||||
[<Business: Sears>]
|
||||
>>> Business.objects.in_bulk(['Sears'])
|
||||
{'Sears': Sears}
|
||||
{'Sears': <Business: Sears>}
|
||||
|
||||
>>> Business.objects.filter(name__exact='Sears')
|
||||
[Sears]
|
||||
[<Business: Sears>]
|
||||
>>> Business.objects.filter(pk='Sears')
|
||||
[Sears]
|
||||
[<Business: Sears>]
|
||||
|
||||
# Queries across tables, involving primary key
|
||||
>>> Employee.objects.filter(business__name__exact='Sears')
|
||||
[Dan Jones, Fran Jones]
|
||||
[<Employee: Dan Jones>, <Employee: Fran Jones>]
|
||||
>>> Employee.objects.filter(business__pk='Sears')
|
||||
[Dan Jones, Fran Jones]
|
||||
[<Employee: Dan Jones>, <Employee: Fran Jones>]
|
||||
|
||||
>>> Business.objects.filter(employees__employee_code__exact='ABC123')
|
||||
[Sears]
|
||||
[<Business: Sears>]
|
||||
>>> Business.objects.filter(employees__pk='ABC123')
|
||||
[Sears]
|
||||
[<Business: Sears>]
|
||||
>>> Business.objects.filter(employees__first_name__startswith='Fran')
|
||||
[Sears]
|
||||
[<Business: Sears>]
|
||||
|
||||
"""
|
||||
|
@ -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
|
||||
<Article: Article 4>
|
||||
|
||||
# Get the latest Article that matches certain filters.
|
||||
>>> Article.objects.filter(pub_date__lt=datetime(2005, 7, 27)).latest()
|
||||
Article 1
|
||||
<Article: 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: Article 1>
|
||||
|
||||
>>> Article.objects.filter(pub_date__gt=datetime(2005, 7, 26)).latest('expire_date')
|
||||
Article 3
|
||||
<Article: 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
|
||||
<Person: Stephanie>
|
||||
"""
|
||||
|
@ -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: <Article: Article 1>, 2: <Article: Article 2>}
|
||||
>>> Article.objects.in_bulk([3])
|
||||
{3: Article 3}
|
||||
{3: <Article: Article 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
|
||||
<Article: Article 2>
|
||||
>>> a2.get_next_by_pub_date()
|
||||
Article 3
|
||||
<Article: Article 3>
|
||||
>>> a3.get_next_by_pub_date()
|
||||
Article 7
|
||||
<Article: Article 7>
|
||||
>>> a4.get_next_by_pub_date()
|
||||
Article 6
|
||||
<Article: 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
|
||||
<Article: Article 5>
|
||||
>>> a7.get_next_by_pub_date()
|
||||
Article 4
|
||||
<Article: Article 4>
|
||||
|
||||
>>> a7.get_previous_by_pub_date()
|
||||
Article 3
|
||||
<Article: Article 3>
|
||||
>>> a6.get_previous_by_pub_date()
|
||||
Article 4
|
||||
<Article: Article 4>
|
||||
>>> a5.get_previous_by_pub_date()
|
||||
Article 6
|
||||
<Article: Article 6>
|
||||
>>> a4.get_previous_by_pub_date()
|
||||
Article 7
|
||||
<Article: Article 7>
|
||||
>>> a3.get_previous_by_pub_date()
|
||||
Article 2
|
||||
<Article: Article 2>
|
||||
>>> a2.get_previous_by_pub_date()
|
||||
Article 1
|
||||
<Article: 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: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>]
|
||||
>>> Article.objects.filter(headline__startswith='Article_')
|
||||
[Article_ with underscore]
|
||||
[<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: Article% with percent sign>, <Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>]
|
||||
>>> Article.objects.filter(headline__startswith='Article%')
|
||||
[Article% with percent sign]
|
||||
[<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: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: 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: Article% with percent sign>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: 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]
|
||||
[<Article: Article% with percent sign>, <Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 1>]
|
||||
"""
|
||||
|
@ -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)]
|
||||
[<Writer: John Smith (Main writer)>, <Writer: Jane Doe (Contributor)>]
|
||||
>>> w1.reporter
|
||||
John Smith
|
||||
<Reporter: John Smith>
|
||||
>>> w2.reporter
|
||||
Jane Doe
|
||||
<Reporter: Jane Doe>
|
||||
>>> w1.article
|
||||
This is a test
|
||||
<Article: This is a test>
|
||||
>>> w2.article
|
||||
This is a test
|
||||
<Article: This is a test>
|
||||
>>> r1.writer_set.all()
|
||||
[John Smith (Main writer)]
|
||||
[<Writer: John Smith (Main writer)>]
|
||||
"""
|
||||
|
@ -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]
|
||||
[<Category: Crime>, <Category: News>]
|
||||
|
||||
>>> a2.primary_categories.all()
|
||||
[News, Sports]
|
||||
[<Category: News>, <Category: Sports>]
|
||||
|
||||
>>> a1.secondary_categories.all()
|
||||
[Life]
|
||||
[<Category: Life>]
|
||||
|
||||
|
||||
>>> c1.primary_article_set.all()
|
||||
[Area man runs]
|
||||
[<Article: Area man runs>]
|
||||
>>> c1.secondary_article_set.all()
|
||||
[]
|
||||
>>> c2.primary_article_set.all()
|
||||
[Area man steals, Area man runs]
|
||||
[<Article: Area man steals>, <Article: Area man runs>]
|
||||
>>> c2.secondary_article_set.all()
|
||||
[]
|
||||
>>> c3.primary_article_set.all()
|
||||
[Area man steals]
|
||||
[<Article: Area man steals>]
|
||||
>>> c3.secondary_article_set.all()
|
||||
[]
|
||||
>>> c4.primary_article_set.all()
|
||||
[]
|
||||
>>> c4.secondary_article_set.all()
|
||||
[Area man steals, Area man runs]
|
||||
[<Article: Area man steals>, <Article: Area man runs>]
|
||||
"""
|
||||
|
@ -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]
|
||||
[<Person: Bill>, <Person: Chuck>, <Person: David>]
|
||||
|
||||
# Who is friends with Bill?
|
||||
>>> b.friends.all()
|
||||
[Anne]
|
||||
[<Person: Anne>]
|
||||
|
||||
# Who is friends with Chuck?
|
||||
>>> c.friends.all()
|
||||
[Anne, David]
|
||||
[<Person: Anne>, <Person: David>]
|
||||
|
||||
# Who is friends with David?
|
||||
>>> d.friends.all()
|
||||
[Anne, Chuck]
|
||||
[<Person: Anne>, <Person: 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]
|
||||
[<Person: Bill>, <Person: Chuck>, <Person: David>]
|
||||
|
||||
# Who is friends with Bill?
|
||||
>>> b.friends.all()
|
||||
[Anne]
|
||||
[<Person: Anne>]
|
||||
|
||||
# Remove Anne from Bill's friends
|
||||
>>> b.friends.remove(a)
|
||||
|
||||
# Who is friends with Anne?
|
||||
>>> a.friends.all()
|
||||
[Chuck, David]
|
||||
[<Person: Chuck>, <Person: 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]
|
||||
[<Person: David>]
|
||||
|
||||
# Who is friends with David?
|
||||
>>> d.friends.all()
|
||||
[Chuck]
|
||||
[<Person: 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]
|
||||
[<Person: Bill>, <Person: Chuck>, <Person: David>]
|
||||
|
||||
# Who is stalking Anne?
|
||||
>>> a.stalkers.all()
|
||||
[Bill]
|
||||
[<Person: Bill>]
|
||||
|
||||
# Who are Bill's idols?
|
||||
>>> b.idols.all()
|
||||
[Anne]
|
||||
[<Person: Anne>]
|
||||
|
||||
# Who is stalking Bill?
|
||||
>>> b.stalkers.all()
|
||||
[Anne]
|
||||
[<Person: Anne>]
|
||||
|
||||
# Who are Chuck's idols?
|
||||
>>> c.idols.all()
|
||||
[David]
|
||||
[<Person: David>]
|
||||
|
||||
# Who is stalking Chuck?
|
||||
>>> c.stalkers.all()
|
||||
[Anne]
|
||||
[<Person: Anne>]
|
||||
|
||||
# Who are David's idols?
|
||||
>>> d.idols.all()
|
||||
@ -134,40 +134,40 @@ API_TESTS = """
|
||||
|
||||
# Who is stalking David
|
||||
>>> d.stalkers.all()
|
||||
[Anne, Chuck]
|
||||
[<Person: Anne>, <Person: 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]
|
||||
[<Person: Bill>, <Person: Chuck>, <Person: David>]
|
||||
|
||||
# Who is stalking Anne?
|
||||
[Bill]
|
||||
[<Person: Bill>]
|
||||
|
||||
# Who are Bill's idols
|
||||
>>> b.idols.all()
|
||||
[Anne]
|
||||
[<Person: Anne>]
|
||||
|
||||
# Who is stalking Bill?
|
||||
>>> b.stalkers.all()
|
||||
[Anne]
|
||||
[<Person: Anne>]
|
||||
|
||||
# Remove Anne from Bill's list of stalkers
|
||||
>>> b.stalkers.remove(a)
|
||||
|
||||
# Who are Anne's idols?
|
||||
>>> a.idols.all()
|
||||
[Chuck, David]
|
||||
[<Person: Chuck>, <Person: David>]
|
||||
|
||||
# Who is stalking Anne?
|
||||
>>> a.stalkers.all()
|
||||
[Bill]
|
||||
[<Person: Bill>]
|
||||
|
||||
# Who are Bill's idols?
|
||||
>>> b.idols.all()
|
||||
[Anne]
|
||||
[<Person: Anne>]
|
||||
|
||||
# Who is stalking Bill?
|
||||
>>> b.stalkers.all()
|
||||
@ -187,6 +187,6 @@ API_TESTS = """
|
||||
|
||||
# Who is friends with David?
|
||||
>>> d.stalkers.all()
|
||||
[Chuck]
|
||||
[<Person: Chuck>]
|
||||
|
||||
"""
|
||||
|
@ -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]
|
||||
[<Category: Child category>]
|
||||
>>> r.child_set.get(name__startswith='Child')
|
||||
Child category
|
||||
<Category: Child category>
|
||||
>>> print r.parent
|
||||
None
|
||||
|
||||
>>> c.child_set.all()
|
||||
[]
|
||||
>>> c.parent
|
||||
Root category
|
||||
<Category: Root category>
|
||||
"""
|
||||
|
@ -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
|
||||
<Person: Jane Smith>
|
||||
>>> kid.father
|
||||
John Smith Senior
|
||||
<Person: John Smith Senior>
|
||||
>>> dad.fathers_child_set.all()
|
||||
[John Smith Junior]
|
||||
[<Person: John Smith Junior>]
|
||||
>>> mom.mothers_child_set.all()
|
||||
[John Smith Junior]
|
||||
[<Person: John Smith Junior>]
|
||||
>>> kid.mothers_child_set.all()
|
||||
[]
|
||||
>>> kid.fathers_child_set.all()
|
||||
|
@ -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]
|
||||
[<Musician: Ella Fitzgerald>]
|
||||
>>> [m1] == list(Musician.objects.all())
|
||||
True
|
||||
|
||||
@ -69,9 +69,9 @@ True
|
||||
|
||||
# Verify it worked.
|
||||
>>> Album.objects.all()
|
||||
[Ella and Basie]
|
||||
[<Album: Ella and Basie>]
|
||||
>>> Album.objects.get().musician
|
||||
Ella Fitzgerald
|
||||
<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]
|
||||
[<Album: Ella and Basie>, <Album: Ultimate Ella>]
|
||||
>>> a2 = Album.objects.get(pk=2)
|
||||
>>> a2
|
||||
Ultimate Ella
|
||||
<Album: Ultimate Ella>
|
||||
>>> a2.release_date
|
||||
datetime.date(2005, 2, 13)
|
||||
"""
|
||||
|
@ -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]
|
||||
[<Publication: The Python Journal>]
|
||||
>>> a2.publications.all()
|
||||
[Highlights for Children, Science News, Science Weekly, The Python Journal]
|
||||
[<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>]
|
||||
|
||||
# Publication objects have access to their related Article objects.
|
||||
>>> p2.article_set.all()
|
||||
[NASA uses Python]
|
||||
[<Article: NASA uses Python>]
|
||||
>>> p1.article_set.all()
|
||||
[Django lets you build Web apps easily, NASA uses Python]
|
||||
[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]
|
||||
>>> Publication.objects.get(id=4).article_set.all()
|
||||
[NASA uses Python]
|
||||
[<Article: 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: Django lets you build Web apps easily>, <Article: NASA uses Python>]
|
||||
>>> Article.objects.filter(publications__pk=1)
|
||||
[Django lets you build Web apps easily, NASA uses Python]
|
||||
[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]
|
||||
|
||||
>>> Article.objects.filter(publications__title__startswith="Science")
|
||||
[NASA uses Python, NASA uses Python]
|
||||
[<Article: NASA uses Python>, <Article: NASA uses Python>]
|
||||
|
||||
>>> Article.objects.filter(publications__title__startswith="Science").distinct()
|
||||
[NASA uses Python]
|
||||
[<Article: 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: The Python Journal>]
|
||||
>>> Publication.objects.filter(pk=1)
|
||||
[The Python Journal]
|
||||
[<Publication: The Python Journal>]
|
||||
|
||||
>>> Publication.objects.filter(article__headline__startswith="NASA")
|
||||
[Highlights for Children, Science News, Science Weekly, The Python Journal]
|
||||
[<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>]
|
||||
|
||||
>>> Publication.objects.filter(article__id__exact=1)
|
||||
[The Python Journal]
|
||||
[<Publication: The Python Journal>]
|
||||
|
||||
>>> Publication.objects.filter(article__pk=1)
|
||||
[The Python Journal]
|
||||
[<Publication: 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]
|
||||
[<Publication: Highlights for Children>, <Publication: Science News>, <Publication: 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]
|
||||
[<Article: 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]
|
||||
[<Article: NASA finds intelligent life on Earth>]
|
||||
>>> a4.publications.all()
|
||||
[Science News]
|
||||
[<Publication: 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]
|
||||
[<Article: NASA finds intelligent life on Earth>, <Article: Oxygen-free diet works wonders>]
|
||||
>>> a5 = p2.article_set.all()[1]
|
||||
>>> a5.publications.all()
|
||||
[Science News]
|
||||
[<Publication: Science News>]
|
||||
|
||||
# Removing publication from an article:
|
||||
>>> a4.publications.remove(p2)
|
||||
>>> p2.article_set.all()
|
||||
[Oxygen-free diet works wonders]
|
||||
[<Article: 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]
|
||||
[<Article: NASA finds intelligent life on Earth>, <Article: Oxygen-free diet works wonders>]
|
||||
>>> a4.publications.all()
|
||||
[Science News]
|
||||
[<Publication: Science News>]
|
||||
>>> a4.publications = [p3]
|
||||
>>> p2.article_set.all()
|
||||
[Oxygen-free diet works wonders]
|
||||
[<Article: Oxygen-free diet works wonders>]
|
||||
>>> a4.publications.all()
|
||||
[Science Weekly]
|
||||
[<Publication: Science Weekly>]
|
||||
|
||||
# Relation sets can be cleared:
|
||||
>>> p2.article_set.clear()
|
||||
>>> p2.article_set.all()
|
||||
[]
|
||||
>>> a4.publications.all()
|
||||
[Science Weekly]
|
||||
[<Publication: Science Weekly>]
|
||||
|
||||
# And you can clear from the other end
|
||||
>>> p2.article_set.add(a4, a5)
|
||||
>>> p2.article_set.all()
|
||||
[NASA finds intelligent life on Earth, Oxygen-free diet works wonders]
|
||||
[<Article: NASA finds intelligent life on Earth>, <Article: Oxygen-free diet works wonders>]
|
||||
>>> a4.publications.all()
|
||||
[Science News, Science Weekly]
|
||||
[<Publication: Science News>, <Publication: Science Weekly>]
|
||||
>>> a4.publications.clear()
|
||||
>>> a4.publications.all()
|
||||
[]
|
||||
>>> p2.article_set.all()
|
||||
[Oxygen-free diet works wonders]
|
||||
[<Article: Oxygen-free diet works wonders>]
|
||||
|
||||
# Recreate the article and Publication we just deleted.
|
||||
>>> p1 = Publication(id=None, title='The Python Journal')
|
||||
@ -192,22 +192,22 @@ API_TESTS = """
|
||||
# Bulk delete some Publications - references to deleted publications should go
|
||||
>>> Publication.objects.filter(title__startswith='Science').delete()
|
||||
>>> Publication.objects.all()
|
||||
[Highlights for Children, The Python Journal]
|
||||
[<Publication: Highlights for Children>, <Publication: The Python Journal>]
|
||||
>>> Article.objects.all()
|
||||
[Django lets you build Web apps easily, NASA finds intelligent life on Earth, NASA uses Python, Oxygen-free diet works wonders]
|
||||
[<Article: Django lets you build Web apps easily>, <Article: NASA finds intelligent life on Earth>, <Article: NASA uses Python>, <Article: Oxygen-free diet works wonders>]
|
||||
>>> a2.publications.all()
|
||||
[The Python Journal]
|
||||
[<Publication: The Python Journal>]
|
||||
|
||||
# Bulk delete some articles - references to deleted objects should go
|
||||
>>> q = Article.objects.filter(headline__startswith='Django')
|
||||
>>> print q
|
||||
[Django lets you build Web apps easily]
|
||||
[<Article: Django lets you build Web apps easily>]
|
||||
>>> q.delete()
|
||||
|
||||
# After the delete, the QuerySet cache needs to be cleared, and the referenced objects should be gone
|
||||
>>> print q
|
||||
[]
|
||||
>>> p1.article_set.all()
|
||||
[NASA uses Python]
|
||||
[<Article: NASA uses Python>]
|
||||
|
||||
"""
|
||||
|
@ -11,7 +11,7 @@ class Reporter(models.Model):
|
||||
last_name = models.CharField(maxlength=30)
|
||||
email = models.EmailField()
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return "%s %s" % (self.first_name, self.last_name)
|
||||
|
||||
class Article(models.Model):
|
||||
@ -19,7 +19,7 @@ class Article(models.Model):
|
||||
pub_date = models.DateField()
|
||||
reporter = models.ForeignKey(Reporter)
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return self.headline
|
||||
|
||||
class Meta:
|
||||
@ -42,7 +42,7 @@ API_TESTS = """
|
||||
1
|
||||
|
||||
>>> a.reporter
|
||||
John Smith
|
||||
<Reporter: John Smith>
|
||||
|
||||
# Article objects have access to their related Reporter objects.
|
||||
>>> r = a.reporter
|
||||
@ -52,7 +52,7 @@ John Smith
|
||||
# Create an Article via the Reporter object.
|
||||
>>> new_article = r.article_set.create(headline="John's second story", pub_date=datetime(2005, 7, 29))
|
||||
>>> new_article
|
||||
John's second story
|
||||
<Article: John's second story>
|
||||
>>> new_article.reporter.id
|
||||
1
|
||||
|
||||
@ -62,43 +62,43 @@ John's second story
|
||||
>>> new_article2.reporter.id
|
||||
1
|
||||
>>> r.article_set.all()
|
||||
[John's second story, Paul's story, This is a test]
|
||||
[<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]
|
||||
|
||||
# Add the same article to a different article set - check that it moves.
|
||||
>>> r2.article_set.add(new_article2)
|
||||
>>> new_article2.reporter.id
|
||||
2
|
||||
>>> r.article_set.all()
|
||||
[John's second story, This is a test]
|
||||
[<Article: John's second story>, <Article: This is a test>]
|
||||
>>> r2.article_set.all()
|
||||
[Paul's story]
|
||||
[<Article: Paul's story>]
|
||||
|
||||
# Assign the article to the reporter directly using the descriptor
|
||||
>>> new_article2.reporter = r
|
||||
>>> new_article2.save()
|
||||
>>> new_article2.reporter
|
||||
John Smith
|
||||
<Reporter: John Smith>
|
||||
>>> new_article2.reporter.id
|
||||
1
|
||||
>>> r.article_set.all()
|
||||
[John's second story, Paul's story, This is a test]
|
||||
[<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]
|
||||
>>> r2.article_set.all()
|
||||
[]
|
||||
|
||||
# Set the article back again using set descriptor.
|
||||
>>> r2.article_set = [new_article, new_article2]
|
||||
>>> r.article_set.all()
|
||||
[This is a test]
|
||||
[<Article: This is a test>]
|
||||
>>> r2.article_set.all()
|
||||
[John's second story, Paul's story]
|
||||
[<Article: John's second story>, <Article: Paul's story>]
|
||||
|
||||
# Funny case - assignment notation can only go so far; because the
|
||||
# Funny case - assignment notation can only go so far; because the
|
||||
# ForeignKey cannot be null, existing members of the set must remain
|
||||
>>> r.article_set = [new_article]
|
||||
>>> r.article_set.all()
|
||||
[John's second story, This is a test]
|
||||
[<Article: John's second story>, <Article: This is a test>]
|
||||
>>> r2.article_set.all()
|
||||
[Paul's story]
|
||||
[<Article: Paul's story>]
|
||||
|
||||
# Reporter cannot be null - there should not be a clear or remove method
|
||||
>>> hasattr(r2.article_set, 'remove')
|
||||
@ -108,10 +108,10 @@ False
|
||||
|
||||
# Reporter objects have access to their related Article objects.
|
||||
>>> r.article_set.all()
|
||||
[John's second story, This is a test]
|
||||
[<Article: John's second story>, <Article: This is a test>]
|
||||
|
||||
>>> r.article_set.filter(headline__startswith='This')
|
||||
[This is a test]
|
||||
[<Article: This is a test>]
|
||||
|
||||
>>> r.article_set.count()
|
||||
2
|
||||
@ -121,24 +121,24 @@ False
|
||||
|
||||
# Get articles by id
|
||||
>>> Article.objects.filter(id__exact=1)
|
||||
[This is a test]
|
||||
[<Article: This is a test>]
|
||||
>>> Article.objects.filter(pk=1)
|
||||
[This is a test]
|
||||
[<Article: This is a test>]
|
||||
|
||||
# Query on an article property
|
||||
>>> Article.objects.filter(headline__startswith='This')
|
||||
[This is a test]
|
||||
[<Article: This is a test>]
|
||||
|
||||
# The API automatically follows relationships as far as you need.
|
||||
# Use double underscores to separate relationships.
|
||||
# This works as many levels deep as you want. There's no limit.
|
||||
# Find all Articles for any Reporter whose first name is "John".
|
||||
>>> Article.objects.filter(reporter__first_name__exact='John')
|
||||
[John's second story, This is a test]
|
||||
[<Article: John's second story>, <Article: This is a test>]
|
||||
|
||||
# Query twice over the related field.
|
||||
>>> Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='Smith')
|
||||
[John's second story, This is a test]
|
||||
[<Article: John's second story>, <Article: This is a test>]
|
||||
|
||||
# The underlying query only makes one join when a related table is referenced twice.
|
||||
>>> query = Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='Smith')
|
||||
@ -148,13 +148,13 @@ False
|
||||
|
||||
# The automatically joined table has a predictable name.
|
||||
>>> Article.objects.filter(reporter__first_name__exact='John').extra(where=["many_to_one_article__reporter.last_name='Smith'"])
|
||||
[John's second story, This is a test]
|
||||
[<Article: John's second story>, <Article: This is a test>]
|
||||
|
||||
# Find all Articles for the Reporter whose ID is 1.
|
||||
>>> Article.objects.filter(reporter__id__exact=1)
|
||||
[John's second story, This is a test]
|
||||
[<Article: John's second story>, <Article: This is a test>]
|
||||
>>> Article.objects.filter(reporter__pk=1)
|
||||
[John's second story, This is a test]
|
||||
[<Article: John's second story>, <Article: This is a test>]
|
||||
|
||||
# You need two underscores between "reporter" and "id" -- not one.
|
||||
>>> Article.objects.filter(reporter_id__exact=1)
|
||||
@ -170,7 +170,7 @@ TypeError: Cannot resolve keyword 'reporter_id' into field
|
||||
|
||||
# "pk" shortcut syntax works in a related context, too.
|
||||
>>> Article.objects.filter(reporter__pk=1)
|
||||
[John's second story, This is a test]
|
||||
[<Article: John's second story>, <Article: This is a test>]
|
||||
|
||||
# You can also instantiate an Article by passing
|
||||
# the Reporter's ID instead of a Reporter object.
|
||||
@ -179,31 +179,31 @@ TypeError: Cannot resolve keyword 'reporter_id' into field
|
||||
>>> a3.reporter.id
|
||||
1
|
||||
>>> a3.reporter
|
||||
John Smith
|
||||
<Reporter: John Smith>
|
||||
|
||||
# Similarly, the reporter ID can be a string.
|
||||
>>> a4 = Article(id=None, headline="This is a test", pub_date=datetime(2005, 7, 27), reporter_id="1")
|
||||
>>> a4.save()
|
||||
>>> a4.reporter
|
||||
John Smith
|
||||
<Reporter: John Smith>
|
||||
|
||||
# Reporters can be queried
|
||||
>>> Reporter.objects.filter(id__exact=1)
|
||||
[John Smith]
|
||||
[<Reporter: John Smith>]
|
||||
>>> Reporter.objects.filter(pk=1)
|
||||
[John Smith]
|
||||
[<Reporter: John Smith>]
|
||||
>>> Reporter.objects.filter(first_name__startswith='John')
|
||||
[John Smith]
|
||||
[<Reporter: John Smith>]
|
||||
|
||||
# Reporters can query in opposite direction of ForeignKey definition
|
||||
>>> Reporter.objects.filter(article__id__exact=1)
|
||||
[John Smith]
|
||||
[<Reporter: John Smith>]
|
||||
>>> Reporter.objects.filter(article__pk=1)
|
||||
[John Smith]
|
||||
[<Reporter: John Smith>]
|
||||
>>> Reporter.objects.filter(article__headline__startswith='This')
|
||||
[John Smith, John Smith, John Smith]
|
||||
[<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>]
|
||||
>>> Reporter.objects.filter(article__headline__startswith='This').distinct()
|
||||
[John Smith]
|
||||
[<Reporter: John Smith>]
|
||||
|
||||
# Counting in the opposite direction works in conjunction with distinct()
|
||||
>>> Reporter.objects.filter(article__headline__startswith='This').count()
|
||||
@ -213,20 +213,20 @@ John Smith
|
||||
|
||||
# Queries can go round in circles.
|
||||
>>> Reporter.objects.filter(article__reporter__first_name__startswith='John')
|
||||
[John Smith, John Smith, John Smith, John Smith]
|
||||
[<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>]
|
||||
>>> Reporter.objects.filter(article__reporter__first_name__startswith='John').distinct()
|
||||
[John Smith]
|
||||
[<Reporter: John Smith>]
|
||||
|
||||
# If you delete a reporter, his articles will be deleted.
|
||||
>>> Article.objects.all()
|
||||
[John's second story, Paul's story, This is a test, This is a test, This is a test]
|
||||
[<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>, <Article: This is a test>, <Article: This is a test>]
|
||||
>>> Reporter.objects.order_by('first_name')
|
||||
[John Smith, Paul Jones]
|
||||
[<Reporter: John Smith>, <Reporter: Paul Jones>]
|
||||
>>> r2.delete()
|
||||
>>> Article.objects.all()
|
||||
[John's second story, This is a test, This is a test, This is a test]
|
||||
[<Article: John's second story>, <Article: This is a test>, <Article: This is a test>, <Article: This is a test>]
|
||||
>>> Reporter.objects.order_by('first_name')
|
||||
[John Smith]
|
||||
[<Reporter: John Smith>]
|
||||
|
||||
# Deletes using a join in the query
|
||||
>>> Reporter.objects.filter(article__headline__startswith='This').delete()
|
||||
|
@ -10,19 +10,19 @@ from django.db import models
|
||||
class Reporter(models.Model):
|
||||
name = models.CharField(maxlength=30)
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Article(models.Model):
|
||||
headline = models.CharField(maxlength=100)
|
||||
reporter = models.ForeignKey(Reporter, null=True)
|
||||
|
||||
def __repr__(self):
|
||||
return self.headline
|
||||
|
||||
class Meta:
|
||||
ordering = ('headline',)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return self.headline
|
||||
|
||||
API_TESTS = """
|
||||
# Create a Reporter.
|
||||
>>> r = Reporter(name='John Smith')
|
||||
@ -36,7 +36,7 @@ API_TESTS = """
|
||||
1
|
||||
|
||||
>>> a.reporter
|
||||
John Smith
|
||||
<Reporter: John Smith>
|
||||
|
||||
# Article objects have access to their related Reporter objects.
|
||||
>>> r = a.reporter
|
||||
@ -44,15 +44,15 @@ John Smith
|
||||
# Create an Article via the Reporter object.
|
||||
>>> a2 = r.article_set.create(headline="Second")
|
||||
>>> a2
|
||||
Second
|
||||
<Article: Second>
|
||||
>>> a2.reporter.id
|
||||
1
|
||||
|
||||
# Reporter objects have access to their related Article objects.
|
||||
>>> r.article_set.all()
|
||||
[First, Second]
|
||||
[<Article: First>, <Article: Second>]
|
||||
>>> r.article_set.filter(headline__startswith='Fir')
|
||||
[First]
|
||||
[<Article: First>]
|
||||
>>> r.article_set.count()
|
||||
2
|
||||
|
||||
@ -78,47 +78,47 @@ None
|
||||
|
||||
# To retrieve the articles with no reporters set, use "reporter__isnull=True".
|
||||
>>> Article.objects.filter(reporter__isnull=True)
|
||||
[Third]
|
||||
[<Article: Third>]
|
||||
|
||||
# Set the reporter for the Third article
|
||||
>>> r.article_set.add(a3)
|
||||
>>> r.article_set.all()
|
||||
[First, Second, Third]
|
||||
[<Article: First>, <Article: Second>, <Article: Third>]
|
||||
|
||||
# Remove an article from the set, and check that it was removed.
|
||||
>>> r.article_set.remove(a3)
|
||||
>>> r.article_set.all()
|
||||
[First, Second]
|
||||
[<Article: First>, <Article: Second>]
|
||||
>>> Article.objects.filter(reporter__isnull=True)
|
||||
[Third]
|
||||
[<Article: Third>]
|
||||
|
||||
# Create another article and reporter
|
||||
>>> r2 = Reporter(name='Paul Jones')
|
||||
>>> r2.save()
|
||||
>>> a4 = r2.article_set.create(headline='Fourth')
|
||||
>>> r2.article_set.all()
|
||||
[Fourth]
|
||||
[<Article: Fourth>]
|
||||
|
||||
# Try to remove a4 from a set it does not belong to
|
||||
>>> r.article_set.remove(a4)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
DoesNotExist: 'Article object' is not related to 'Reporter object'.
|
||||
DoesNotExist: <Article: Fourth> is not related to <Reporter: John Smith>.
|
||||
|
||||
>>> r2.article_set.all()
|
||||
[Fourth]
|
||||
[<Article: Fourth>]
|
||||
|
||||
# Use descriptor assignment to allocate ForeignKey. Null is legal, so
|
||||
# existing members of set that are not in the assignment set are set null
|
||||
>>> r2.article_set = [a2, a3]
|
||||
>>> r2.article_set.all()
|
||||
[Second, Third]
|
||||
[<Article: Second>, <Article: Third>]
|
||||
|
||||
# Clear the rest of the set
|
||||
>>> r.article_set.clear()
|
||||
>>> r.article_set.all()
|
||||
[]
|
||||
>>> Article.objects.filter(reporter__isnull=True)
|
||||
[First, Fourth]
|
||||
[<Article: First>, <Article: Fourth>]
|
||||
|
||||
"""
|
||||
|
@ -10,20 +10,20 @@ class Place(models.Model):
|
||||
name = models.CharField(maxlength=50)
|
||||
address = models.CharField(maxlength=80)
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return "%s the place" % self.name
|
||||
|
||||
class Restaurant(Place):
|
||||
serves_hot_dogs = models.BooleanField()
|
||||
serves_pizza = models.BooleanField()
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return "%s the restaurant" % self.name
|
||||
|
||||
class ItalianRestaurant(Restaurant):
|
||||
serves_gnocchi = models.BooleanField()
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return "%s the italian restaurant" % self.name
|
||||
|
||||
API_TESTS = """
|
||||
|
@ -12,7 +12,7 @@ class Place(models.Model):
|
||||
name = models.CharField(maxlength=50)
|
||||
address = models.CharField(maxlength=80)
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return "%s the place" % self.name
|
||||
|
||||
class Restaurant(models.Model):
|
||||
@ -20,15 +20,15 @@ class Restaurant(models.Model):
|
||||
serves_hot_dogs = models.BooleanField()
|
||||
serves_pizza = models.BooleanField()
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return "%s the restaurant" % self.place.name
|
||||
|
||||
class Waiter(models.Model):
|
||||
restaurant = models.ForeignKey(Restaurant)
|
||||
name = models.CharField(maxlength=50)
|
||||
|
||||
def __repr__(self):
|
||||
return "%s the waiter at %r" % (self.name, self.restaurant)
|
||||
def __str__(self):
|
||||
return "%s the waiter at %s" % (self.name, self.restaurant)
|
||||
|
||||
API_TESTS = """
|
||||
# Create a couple of Places.
|
||||
@ -43,11 +43,11 @@ API_TESTS = """
|
||||
|
||||
# A Restaurant can access its place.
|
||||
>>> r.place
|
||||
Demon Dogs the place
|
||||
<Place: Demon Dogs the place>
|
||||
|
||||
# A Place can access its restaurant, if available.
|
||||
>>> p1.restaurant
|
||||
Demon Dogs the restaurant
|
||||
<Restaurant: Demon Dogs the restaurant>
|
||||
|
||||
# p2 doesn't have an associated restaurant.
|
||||
>>> p2.restaurant
|
||||
@ -60,69 +60,69 @@ DoesNotExist: Restaurant matching query does not exist.
|
||||
>>> r.place = p2
|
||||
>>> r.save()
|
||||
>>> p2.restaurant
|
||||
Ace Hardware the restaurant
|
||||
<Restaurant: Ace Hardware the restaurant>
|
||||
>>> r.place
|
||||
Ace Hardware the place
|
||||
<Place: Ace Hardware the place>
|
||||
|
||||
# Set the place back again, using assignment in the reverse direction
|
||||
# Need to reget restaurant object first, because the reverse set
|
||||
# Need to reget restaurant object first, because the reverse set
|
||||
# can't update the existing restaurant instance
|
||||
>>> p1.restaurant = r
|
||||
>>> r.save()
|
||||
>>> p1.restaurant
|
||||
Demon Dogs the restaurant
|
||||
<Restaurant: Demon Dogs the restaurant>
|
||||
|
||||
>>> r = Restaurant.objects.get(pk=1)
|
||||
>>> r.place
|
||||
Demon Dogs the place
|
||||
<Place: Demon Dogs the place>
|
||||
|
||||
# Restaurant.objects.all() just returns the Restaurants, not the Places.
|
||||
# Note that there are two restaurants - Ace Hardware the Restaurant was created
|
||||
# in the call to r.place = p2. This means there are multiple restaurants referencing
|
||||
# in the call to r.place = p2. This means there are multiple restaurants referencing
|
||||
# a single place...
|
||||
>>> Restaurant.objects.all()
|
||||
[Demon Dogs the restaurant, Ace Hardware the restaurant]
|
||||
[<Restaurant: Demon Dogs the restaurant>, <Restaurant: Ace Hardware the restaurant>]
|
||||
|
||||
# Place.objects.all() returns all Places, regardless of whether they have
|
||||
# Restaurants.
|
||||
>>> Place.objects.order_by('name')
|
||||
[Ace Hardware the place, Demon Dogs the place]
|
||||
[<Place: Ace Hardware the place>, <Place: Demon Dogs the place>]
|
||||
|
||||
>>> Restaurant.objects.get(place__id__exact=1)
|
||||
Demon Dogs the restaurant
|
||||
<Restaurant: Demon Dogs the restaurant>
|
||||
>>> Restaurant.objects.get(pk=1)
|
||||
Demon Dogs the restaurant
|
||||
<Restaurant: Demon Dogs the restaurant>
|
||||
>>> Restaurant.objects.get(place__exact=1)
|
||||
Demon Dogs the restaurant
|
||||
<Restaurant: Demon Dogs the restaurant>
|
||||
>>> Restaurant.objects.get(place__pk=1)
|
||||
Demon Dogs the restaurant
|
||||
<Restaurant: Demon Dogs the restaurant>
|
||||
>>> Restaurant.objects.get(place__name__startswith="Demon")
|
||||
Demon Dogs the restaurant
|
||||
<Restaurant: Demon Dogs the restaurant>
|
||||
|
||||
>>> Place.objects.get(id__exact=1)
|
||||
Demon Dogs the place
|
||||
<Place: Demon Dogs the place>
|
||||
>>> Place.objects.get(pk=1)
|
||||
Demon Dogs the place
|
||||
<Place: Demon Dogs the place>
|
||||
>>> Place.objects.get(restaurant__place__exact=1)
|
||||
Demon Dogs the place
|
||||
<Place: Demon Dogs the place>
|
||||
>>> Place.objects.get(restaurant__pk=1)
|
||||
Demon Dogs the place
|
||||
<Place: Demon Dogs the place>
|
||||
|
||||
# Add a Waiter to the Restaurant.
|
||||
>>> w = r.waiter_set.create(name='Joe')
|
||||
>>> w.save()
|
||||
>>> w
|
||||
Joe the waiter at Demon Dogs the restaurant
|
||||
<Waiter: Joe the waiter at Demon Dogs the restaurant>
|
||||
|
||||
# Query the waiters
|
||||
>>> Waiter.objects.filter(restaurant__place__exact=1)
|
||||
[Joe the waiter at Demon Dogs the restaurant]
|
||||
[<Waiter: Joe the waiter at Demon Dogs the restaurant>]
|
||||
>>> Waiter.objects.filter(restaurant__pk=1)
|
||||
[Joe the waiter at Demon Dogs the restaurant]
|
||||
[<Waiter: Joe the waiter at Demon Dogs the restaurant>]
|
||||
>>> Waiter.objects.filter(id__exact=1)
|
||||
[Joe the waiter at Demon Dogs the restaurant]
|
||||
[<Waiter: Joe the waiter at Demon Dogs the restaurant>]
|
||||
>>> Waiter.objects.filter(pk=1)
|
||||
[Joe the waiter at Demon Dogs the restaurant]
|
||||
[<Waiter: Joe the waiter at Demon Dogs the restaurant>]
|
||||
|
||||
# Delete the restaurant; the waiter should also be removed
|
||||
>>> r = Restaurant.objects.get(pk=1)
|
||||
|
@ -1,10 +1,10 @@
|
||||
"""
|
||||
19. OR lookups
|
||||
|
||||
To perform an OR lookup, or a lookup that combines ANDs and ORs,
|
||||
To perform an OR lookup, or a lookup that combines ANDs and ORs,
|
||||
combine QuerySet objects using & and | operators.
|
||||
|
||||
Alternatively, use positional arguments, and pass one or more expressions
|
||||
Alternatively, use positional arguments, and pass one or more expressions
|
||||
of clauses using the variable ``django.db.models.Q`` (or any object with
|
||||
a get_sql method).
|
||||
|
||||
@ -16,10 +16,11 @@ from django.db import models
|
||||
class Article(models.Model):
|
||||
headline = models.CharField(maxlength=50)
|
||||
pub_date = models.DateTimeField()
|
||||
|
||||
class Meta:
|
||||
ordering = ('pub_date',)
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return self.headline
|
||||
|
||||
API_TESTS = """
|
||||
@ -36,10 +37,10 @@ API_TESTS = """
|
||||
>>> a3.save()
|
||||
|
||||
>>> Article.objects.filter(headline__startswith='Hello') | Article.objects.filter(headline__startswith='Goodbye')
|
||||
[Hello, Goodbye, Hello and goodbye]
|
||||
[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]
|
||||
|
||||
>>> Article.objects.filter(Q(headline__startswith='Hello') | Q(headline__startswith='Goodbye'))
|
||||
[Hello, Goodbye, Hello and goodbye]
|
||||
[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]
|
||||
|
||||
>>> Article.objects.filter(Q(headline__startswith='Hello') & Q(headline__startswith='Goodbye'))
|
||||
[]
|
||||
@ -51,34 +52,34 @@ API_TESTS = """
|
||||
[]
|
||||
|
||||
>>> articles.filter(headline__startswith='Hello') & articles.filter(headline__contains='bye')
|
||||
[Hello and goodbye]
|
||||
[<Article: Hello and goodbye>]
|
||||
|
||||
>>> Article.objects.filter(Q(headline__contains='bye'), headline__startswith='Hello')
|
||||
[Hello and goodbye]
|
||||
[<Article: Hello and goodbye>]
|
||||
|
||||
>>> Article.objects.filter(headline__contains='Hello') | Article.objects.filter(headline__contains='bye')
|
||||
[Hello, Goodbye, Hello and goodbye]
|
||||
[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]
|
||||
|
||||
>>> Article.objects.filter(headline__iexact='Hello') | Article.objects.filter(headline__contains='ood')
|
||||
[Hello, Goodbye, Hello and goodbye]
|
||||
[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]
|
||||
|
||||
>>> Article.objects.filter(Q(pk=1) | Q(pk=2))
|
||||
[Hello, Goodbye]
|
||||
[<Article: Hello>, <Article: Goodbye>]
|
||||
|
||||
>>> Article.objects.filter(Q(pk=1) | Q(pk=2) | Q(pk=3))
|
||||
[Hello, Goodbye, Hello and goodbye]
|
||||
[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]
|
||||
|
||||
# Q arg objects are ANDed
|
||||
# Q arg objects are ANDed
|
||||
>>> Article.objects.filter(Q(headline__startswith='Hello'), Q(headline__contains='bye'))
|
||||
[Hello and goodbye]
|
||||
[<Article: Hello and goodbye>]
|
||||
|
||||
# Q arg AND order is irrelevant
|
||||
>>> Article.objects.filter(Q(headline__contains='bye'), headline__startswith='Hello')
|
||||
[Hello and goodbye]
|
||||
[<Article: Hello and goodbye>]
|
||||
|
||||
# Try some arg queries with operations other than get_list
|
||||
>>> Article.objects.get(Q(headline__startswith='Hello'), Q(headline__contains='bye'))
|
||||
Hello and goodbye
|
||||
<Article: Hello and goodbye>
|
||||
|
||||
>>> Article.objects.filter(Q(headline__startswith='Hello') | Q(headline__contains='bye')).count()
|
||||
3
|
||||
@ -87,17 +88,17 @@ Hello and goodbye
|
||||
[{'headline': 'Hello and goodbye', 'pub_date': datetime.datetime(2005, 11, 29, 0, 0), 'id': 3}]
|
||||
|
||||
>>> Article.objects.filter(Q(headline__startswith='Hello')).in_bulk([1,2])
|
||||
{1: Hello}
|
||||
{1: <Article: Hello>}
|
||||
|
||||
# Demonstrating exclude with a Q object
|
||||
>>> Article.objects.exclude(Q(headline__startswith='Hello'))
|
||||
[Goodbye]
|
||||
[<Article: Goodbye>]
|
||||
|
||||
# The 'complex_filter' method supports framework features such as
|
||||
# The 'complex_filter' method supports framework features such as
|
||||
# 'limit_choices_to' which normally take a single dictionary of lookup arguments
|
||||
# but need to support arbitrary queries via Q objects too.
|
||||
>>> Article.objects.complex_filter({'pk': 1})
|
||||
[Hello]
|
||||
[<Article: Hello>]
|
||||
>>> Article.objects.complex_filter(Q(pk=1) | Q(pk=2))
|
||||
[Hello, Goodbye]
|
||||
[<Article: Hello>, <Article: Goodbye>]
|
||||
"""
|
||||
|
@ -21,7 +21,7 @@ class Article(models.Model):
|
||||
class Meta:
|
||||
ordering = ('-pub_date', 'headline')
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return self.headline
|
||||
|
||||
API_TESTS = """
|
||||
@ -39,26 +39,26 @@ API_TESTS = """
|
||||
# By default, Article.objects.all() orders by pub_date descending, then
|
||||
# headline ascending.
|
||||
>>> Article.objects.all()
|
||||
[Article 4, Article 2, Article 3, Article 1]
|
||||
[<Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 1>]
|
||||
|
||||
# Override ordering with order_by, which is in the same format as the ordering
|
||||
# attribute in models.
|
||||
>>> Article.objects.order_by('headline')
|
||||
[Article 1, Article 2, Article 3, Article 4]
|
||||
[<Article: Article 1>, <Article: Article 2>, <Article: Article 3>, <Article: Article 4>]
|
||||
>>> Article.objects.order_by('pub_date', '-headline')
|
||||
[Article 1, Article 3, Article 2, Article 4]
|
||||
[<Article: Article 1>, <Article: Article 3>, <Article: Article 2>, <Article: Article 4>]
|
||||
|
||||
# Use the 'stop' part of slicing notation to limit the results.
|
||||
>>> Article.objects.order_by('headline')[:2]
|
||||
[Article 1, Article 2]
|
||||
[<Article: Article 1>, <Article: Article 2>]
|
||||
|
||||
# Use the 'stop' and 'start' parts of slicing notation to offset the result list.
|
||||
>>> Article.objects.order_by('headline')[1:3]
|
||||
[Article 2, Article 3]
|
||||
[<Article: Article 2>, <Article: Article 3>]
|
||||
|
||||
# Getting a single item should work too:
|
||||
>>> Article.objects.all()[0]
|
||||
Article 4
|
||||
<Article: Article 4>
|
||||
|
||||
# Use '?' to order randomly. (We're using [...] in the output to indicate we
|
||||
# don't know what order the output will be in.
|
||||
|
@ -12,7 +12,7 @@ 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 = """
|
||||
@ -35,11 +35,11 @@ API_TESTS = """
|
||||
|
||||
# get the first page (zero-based)
|
||||
>>> paginator.get_page(0)
|
||||
[Article 1, Article 2, Article 3, Article 4, Article 5]
|
||||
[<Article: Article 1>, <Article: Article 2>, <Article: Article 3>, <Article: Article 4>, <Article: Article 5>]
|
||||
|
||||
# get the second page
|
||||
>>> paginator.get_page(1)
|
||||
[Article 6, Article 7, Article 8, Article 9]
|
||||
[<Article: Article 6>, <Article: Article 7>, <Article: Article 8>, <Article: Article 9>]
|
||||
|
||||
# does the first page have a next or previous page?
|
||||
>>> paginator.has_next_page(0)
|
||||
|
@ -21,7 +21,7 @@ class Thing(models.Model):
|
||||
class Meta:
|
||||
db_table = 'select'
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return self.when
|
||||
|
||||
API_TESTS = """
|
||||
@ -39,18 +39,18 @@ a
|
||||
h
|
||||
|
||||
>>> Thing.objects.order_by('when')
|
||||
[a, h]
|
||||
[<Thing: a>, <Thing: h>]
|
||||
>>> v = Thing.objects.get(pk='a')
|
||||
>>> print v.join
|
||||
b
|
||||
>>> print v.where
|
||||
2005-01-01
|
||||
>>> Thing.objects.order_by('select.when')
|
||||
[a, h]
|
||||
[<Thing: a>, <Thing: h>]
|
||||
|
||||
>>> Thing.objects.dates('where', 'year')
|
||||
[datetime.datetime(2005, 1, 1, 0, 0), datetime.datetime(2006, 1, 1, 0, 0)]
|
||||
|
||||
>>> Thing.objects.filter(where__month=1)
|
||||
[a]
|
||||
[<Thing: a>]
|
||||
"""
|
||||
|
@ -8,20 +8,23 @@ from django.db import models
|
||||
|
||||
class User(models.Model):
|
||||
name = models.CharField(maxlength=200)
|
||||
def __repr__(self):
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Poll(models.Model):
|
||||
question = models.CharField(maxlength=200)
|
||||
creator = models.ForeignKey(User)
|
||||
def __repr__(self):
|
||||
|
||||
def __str__(self):
|
||||
return self.question
|
||||
|
||||
class Choice(models.Model):
|
||||
name = models.CharField(maxlength=100)
|
||||
poll = models.ForeignKey(Poll, related_name="poll_choice")
|
||||
related_poll = models.ForeignKey(Poll, related_name="related_choice")
|
||||
def __repr(self):
|
||||
|
||||
def __str(self):
|
||||
return self.name
|
||||
|
||||
API_TESTS = """
|
||||
@ -38,15 +41,15 @@ API_TESTS = """
|
||||
|
||||
>>> # Reverse lookups by field name:
|
||||
>>> User.objects.get(poll__question__exact="What's the first question?")
|
||||
John Doe
|
||||
<User: John Doe>
|
||||
>>> User.objects.get(poll__question__exact="What's the second question?")
|
||||
Jim Bo
|
||||
<User: Jim Bo>
|
||||
|
||||
>>> # Reverse lookups by related_name:
|
||||
>>> Poll.objects.get(poll_choice__name__exact="This is the answer.")
|
||||
What's the first question?
|
||||
<Poll: What's the first question?>
|
||||
>>> Poll.objects.get(related_choice__name__exact="This is the answer.")
|
||||
What's the second question?
|
||||
<Poll: What's the second question?>
|
||||
|
||||
>>> # If a related_name is given you can't use the field name instead:
|
||||
>>> Poll.objects.get(choice__name__exact="This is the answer")
|
||||
|
@ -11,7 +11,7 @@ class Person(models.Model):
|
||||
first_name = models.CharField(maxlength=20)
|
||||
last_name = models.CharField(maxlength=20)
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return "%s %s" % (self.first_name, self.last_name)
|
||||
|
||||
def save(self):
|
||||
@ -31,7 +31,7 @@ Before save
|
||||
After save
|
||||
|
||||
>>> Person.objects.all()
|
||||
[John Smith]
|
||||
[<Person: John Smith>]
|
||||
|
||||
>>> p1.delete()
|
||||
Before deletion
|
||||
|
0
tests/modeltests/str/__init__.py
Normal file
0
tests/modeltests/str/__init__.py
Normal file
@ -1,7 +1,7 @@
|
||||
"""
|
||||
2. Adding __repr__() to models
|
||||
2. Adding __str__() to models
|
||||
|
||||
Although it's not a strict requirement, each model should have a ``__repr__()``
|
||||
Although it's not a strict requirement, each model should have a ``__str__()``
|
||||
method to return a "human-readable" representation of the object. Do this not
|
||||
only for your own sanity when dealing with the interactive prompt, but also
|
||||
because objects' representations are used throughout Django's
|
||||
@ -14,7 +14,7 @@ class Article(models.Model):
|
||||
headline = models.CharField(maxlength=100)
|
||||
pub_date = models.DateTimeField()
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return self.headline
|
||||
|
||||
API_TESTS = """
|
||||
@ -23,9 +23,9 @@ API_TESTS = """
|
||||
>>> a = Article(headline='Area man programs in Python', pub_date=datetime(2005, 7, 28))
|
||||
>>> a.save()
|
||||
|
||||
>>> repr(a)
|
||||
>>> str(a)
|
||||
'Area man programs in Python'
|
||||
|
||||
>>> a
|
||||
Area man programs in Python
|
||||
<Article: Area man programs in Python>
|
||||
"""
|
@ -14,12 +14,19 @@ class Reporter(models.Model):
|
||||
last_name = models.CharField(maxlength=30)
|
||||
email = models.EmailField()
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return "%s %s" % (self.first_name, self.last_name)
|
||||
|
||||
API_TESTS = """
|
||||
>>> from django.db import connection, transaction
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
building_docs = getattr(settings, 'BUILDING_DOCS', False)
|
||||
|
||||
if building_docs or settings.DATABASE_ENGINE != 'mysql':
|
||||
API_TESTS += """
|
||||
# the default behavior is to autocommit after each save() action
|
||||
>>> def create_a_reporter_then_fail(first, last):
|
||||
... a = Reporter(first_name=first, last_name=last)
|
||||
@ -33,7 +40,7 @@ Exception: I meant to do that
|
||||
|
||||
# The object created before the exception still exists
|
||||
>>> Reporter.objects.all()
|
||||
[Alice Smith]
|
||||
[<Reporter: Alice Smith>]
|
||||
|
||||
# the autocommit decorator works exactly the same as the default behavior
|
||||
>>> autocomitted_create_then_fail = transaction.autocommit(create_a_reporter_then_fail)
|
||||
@ -44,7 +51,7 @@ Exception: I meant to do that
|
||||
|
||||
# Same behavior as before
|
||||
>>> Reporter.objects.all()
|
||||
[Alice Smith, Ben Jones]
|
||||
[<Reporter: Alice Smith>, <Reporter: Ben Jones>]
|
||||
|
||||
# With the commit_on_success decorator, the transaction is only comitted if the
|
||||
# function doesn't throw an exception
|
||||
@ -56,7 +63,7 @@ Exception: I meant to do that
|
||||
|
||||
# This time the object never got saved
|
||||
>>> Reporter.objects.all()
|
||||
[Alice Smith, Ben Jones]
|
||||
[<Reporter: Alice Smith>, <Reporter: Ben Jones>]
|
||||
|
||||
# If there aren't any exceptions, the data will get saved
|
||||
>>> def remove_a_reporter():
|
||||
@ -66,7 +73,7 @@ Exception: I meant to do that
|
||||
>>> remove_comitted_on_success = transaction.commit_on_success(remove_a_reporter)
|
||||
>>> remove_comitted_on_success()
|
||||
>>> Reporter.objects.all()
|
||||
[Ben Jones]
|
||||
[<Reporter: Ben Jones>]
|
||||
|
||||
# You can manually manage transactions if you really want to, but you
|
||||
# have to remember to commit/rollback
|
||||
@ -77,7 +84,7 @@ Exception: I meant to do that
|
||||
>>> manually_managed = transaction.commit_manually(manually_managed)
|
||||
>>> manually_managed()
|
||||
>>> Reporter.objects.all()
|
||||
[Ben Jones, Carol Doe]
|
||||
[<Reporter: Ben Jones>, <Reporter: Carol Doe>]
|
||||
|
||||
# If you forget, you'll get bad errors
|
||||
>>> def manually_managed_mistake():
|
||||
|
@ -17,7 +17,7 @@ class Person(models.Model):
|
||||
favorite_moment = models.DateTimeField()
|
||||
email = models.EmailField()
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
API_TESTS = """
|
||||
|
Loading…
x
Reference in New Issue
Block a user