1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +00:00

newforms-admin: Merged to [4749]

git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@4750 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2007-03-16 16:09:29 +00:00
parent b0bbdc744d
commit 5088488057
80 changed files with 6973 additions and 2105 deletions

View File

@ -42,7 +42,6 @@ people who have submitted patches, reported bugs, added translations, helped
answer newbie questions, and generally made Django that much better:
adurdin@gmail.com
akaihola
Andreas
andy@jadedplanet.net
ant9000@netwise.it
@ -86,10 +85,12 @@ answer newbie questions, and generally made Django that much better:
Marc Fargas <telenieko@telenieko.com>
favo@exoweb.net
Eric Floehr <eric@intellovations.com>
Jorge Gajon <gajon@gajon.org>
gandalf@owca.info
Baishampayan Ghose
martin.glueck@gmail.com
Simon Greenhill <dev@simon.net.nz>
Owen Griffiths
Espen Grindhaug <http://grindhaug.org/>
Brian Harring <ferringb@gmail.com>
Brant Harris
@ -107,10 +108,12 @@ answer newbie questions, and generally made Django that much better:
Michael Josephson <http://www.sdjournal.com/>
jpellerin@gmail.com
junzhang.jn@gmail.com
Antti Kaihola <http://akaihola.blogspot.com/>
Ben Dean Kawamura <ben.dean.kawamura@gmail.com>
Garth Kidd <http://www.deadlybloodyserious.com/>
kilian <kilian.cavalotti@lip6.fr>
Sune Kirkeby <http://ibofobi.dk/>
Bastian Kleineidam <calvin@debian.org>
Cameron Knight (ckknight)
Meir Kriheli <http://mksoft.co.il/>
Bruce Kroeze <http://coderseye.com/>
@ -136,6 +139,7 @@ answer newbie questions, and generally made Django that much better:
Jason McBrayer <http://www.carcosa.net/jason/>
mccutchen@gmail.com
michael.mcewan@gmail.com
mikko@sorl.net
mitakummaa@gmail.com
mmarshall
Eric Moritz <http://eric.themoritzfamily.com/>
@ -147,6 +151,7 @@ answer newbie questions, and generally made Django that much better:
Neal Norwitz <nnorwitz@google.com>
oggie rob <oz.robharvey@gmail.com>
Jay Parlar <parlar@gmail.com>
pavithran s <pavithran.s@gmail.com>
pgross@thoughtworks.com
phaedo <http://phaedo.cx/>
phil@produxion.net

View File

@ -1,9 +1,10 @@
#!/usr/bin/env python
import optparse
import os
import sys
def compile_messages():
def compile_messages(locale=None):
basedir = None
if os.path.isdir(os.path.join('conf', 'locale')):
@ -14,6 +15,9 @@ def compile_messages():
print "This script should be run from the Django SVN tree or your project or app tree."
sys.exit(1)
if locale is not None:
basedir = os.path.join(basedir, locale, 'LC_MESSAGES')
for dirpath, dirnames, filenames in os.walk(basedir):
for f in filenames:
if f.endswith('.po'):
@ -32,5 +36,14 @@ def compile_messages():
cmd = 'msgfmt -o "$djangocompilemo" "$djangocompilepo"'
os.system(cmd)
def main():
parser = optparse.OptionParser()
parser.add_option('-l', '--locale', dest='locale',
help="The locale to process. Default is to process all.")
options, args = parser.parse_args()
if len(args):
parser.error("This program takes no arguments")
compile_messages(options.locale)
if __name__ == "__main__":
compile_messages()
main()

View File

@ -81,7 +81,7 @@ def make_messages():
src = pythonize_re.sub('\n#', src)
open(os.path.join(dirpath, '%s.py' % file), "wb").write(src)
thefile = '%s.py' % file
cmd = 'xgettext %s -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy -o - "%s"' % (
cmd = 'xgettext %s -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy --from-code UTF-8 -o - "%s"' % (
os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile))
(stdin, stdout, stderr) = os.popen3(cmd, 'b')
msgs = stdout.read()
@ -103,7 +103,7 @@ def make_messages():
open(os.path.join(dirpath, '%s.py' % file), "wb").write(templatize(src))
thefile = '%s.py' % file
if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
cmd = 'xgettext %s -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy -o - "%s"' % (
cmd = 'xgettext %s -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy --from-code UTF-8 -o - "%s"' % (
os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile))
(stdin, stdout, stderr) = os.popen3(cmd, 'b')
msgs = stdout.read()

View File

@ -69,6 +69,7 @@ LANGUAGES = (
('sr', gettext_noop('Serbian')),
('sv', gettext_noop('Swedish')),
('ta', gettext_noop('Tamil')),
('te', gettext_noop('Telugu')),
('tr', gettext_noop('Turkish')),
('uk', gettext_noop('Ukrainian')),
('zh-cn', gettext_noop('Simplified Chinese')),
@ -319,3 +320,10 @@ TEST_RUNNER = 'django.test.simple.run_tests'
# The name of the database to use for testing purposes.
# If None, a name of 'test_' + DATABASE_NAME will be assumed
TEST_DATABASE_NAME = None
############
# FIXTURES #
############
# The list of directories to search for fixtures
FIXTURE_DIRS = ()

View File

@ -5,14 +5,14 @@
# Ricardo Javier Cárdenes Medina <ricardo.cardenes@gmail.com>, 2005.
# Ricardo Javier Cardenes Medina <ricardo.cardenes@gmail.com>, 2005.
# AgarFu <heaven@croasanaso.sytes.net>, 2007.
# Mario Gonzalez <gonzalemario @t gmail.com>
# Mario Gonzalez <gonzalemario @t gmail.com>, 2007
msgid ""
msgstr ""
"Project-Id-Version: django\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-02-24 17:08+0000\n"
"PO-Revision-Date: 2007-02-24 18:02-0600\n"
"Last-Translator: AgarFu <heaven@croasanaso.sytes.net>\n"
"Last-Translator: Mario Gonzalez <gonzalemario @t gmail.com>\n"
"Language-Team: Castellano <Django-I18N@googlegroups.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-1\n"
@ -435,7 +435,7 @@ msgstr "Introduzca una fecha v
#: db/models/fields/__init__.py:521 core/validators.py:156
msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
msgstr "Introduzca una fecha/hora válida en formato YYYY-MM-DD HH:MM."
msgstr "Introduzca una fecha/hora válida en formato AAAA-MM-DD HH:MM."
#: db/models/fields/__init__.py:625
msgid "Enter a valid filename."
@ -934,19 +934,19 @@ msgstr "nombre en c
#: contrib/auth/models.py:42
msgid "permission"
msgstr "Permiso"
msgstr "permiso"
#: contrib/auth/models.py:43 contrib/auth/models.py:58
msgid "permissions"
msgstr "Permisos"
msgstr "permisos"
#: contrib/auth/models.py:60
msgid "group"
msgstr "Grupo"
msgstr "grupo"
#: contrib/auth/models.py:61 contrib/auth/models.py:100
msgid "groups"
msgstr "Grupos"
msgstr "grupos"
#: contrib/auth/models.py:90
msgid "username"
@ -1034,15 +1034,15 @@ msgstr ""
#: contrib/auth/models.py:102
msgid "user permissions"
msgstr "Permisos"
msgstr "permisos"
#: contrib/auth/models.py:105
msgid "user"
msgstr "Usuario"
msgstr "usuario"
#: contrib/auth/models.py:106
msgid "users"
msgstr "Usuarios"
msgstr "usuarios"
#: contrib/auth/models.py:111
msgid "Personal info"
@ -1062,7 +1062,7 @@ msgstr "Grupos"
#: contrib/auth/models.py:258
msgid "message"
msgstr "Mensaje"
msgstr "mensaje"
#: contrib/auth/forms.py:17 contrib/auth/forms.py:138
msgid "The two password fields didn't match."
@ -1220,11 +1220,11 @@ msgstr "aprobado por el staff"
#: contrib/comments/models.py:176
msgid "free comment"
msgstr "Comentario libre"
msgstr "comentario libre"
#: contrib/comments/models.py:177
msgid "free comments"
msgstr "Comentarios libres"
msgstr "comentarios libres"
#: contrib/comments/models.py:233
msgid "score"
@ -1236,16 +1236,16 @@ msgstr "fecha de la puntuaci
#: contrib/comments/models.py:237
msgid "karma score"
msgstr "Punto karma"
msgstr "punto karma"
#: contrib/comments/models.py:238
msgid "karma scores"
msgstr "Puntos karma"
msgstr "puntos karma"
#: contrib/comments/models.py:242
#, python-format
msgid "%(score)d rating by %(user)s"
msgstr "Puntuado %(score)d por %(user)s"
msgstr "puntuado %(score)d por %(user)s"
#: contrib/comments/models.py:258
#, python-format
@ -1264,11 +1264,11 @@ msgstr "fecha de la marca"
#: contrib/comments/models.py:268
msgid "user flag"
msgstr "Marca de usuario"
msgstr "marca de usuario"
#: contrib/comments/models.py:269
msgid "user flags"
msgstr "Marcas de usuario"
msgstr "marcas de usuario"
#: contrib/comments/models.py:273
#, python-format
@ -1281,11 +1281,11 @@ msgstr "fecha de eliminaci
#: contrib/comments/models.py:280
msgid "moderator deletion"
msgstr "Eliminación de moderador"
msgstr "eliminación de moderador"
#: contrib/comments/models.py:281
msgid "moderator deletions"
msgstr "Eliminaciones de moderador"
msgstr "eliminaciones de moderador"
#: contrib/comments/models.py:285
#, python-format
@ -2095,7 +2095,7 @@ msgstr "etiqueta:"
#: contrib/admin/views/doc.py:77 contrib/admin/views/doc.py:79
#: contrib/admin/views/doc.py:81
msgid "filter:"
msgstr "Filtro:"
msgstr "filtro:"
#: contrib/admin/views/doc.py:135 contrib/admin/views/doc.py:137
#: contrib/admin/views/doc.py:139

View File

@ -93,7 +93,7 @@ msgstr "tšekki"
#: conf/global_settings.py:42
msgid "Welsh"
msgstr ""
msgstr "wales"
#: conf/global_settings.py:43
msgid "Danish"
@ -169,15 +169,15 @@ msgstr "venäjä"
#: conf/global_settings.py:61
msgid "Slovak"
msgstr ""
msgstr "slovakia"
#: conf/global_settings.py:62
msgid "Slovenian"
msgstr ""
msgstr "slovenia"
#: conf/global_settings.py:63
msgid "Serbian"
msgstr ""
msgstr "serbia"
#: conf/global_settings.py:64
msgid "Swedish"
@ -189,15 +189,15 @@ msgstr ""
#: conf/global_settings.py:66
msgid "Ukrainian"
msgstr ""
msgstr "ukraina"
#: conf/global_settings.py:67
msgid "Simplified Chinese"
msgstr ""
msgstr "kiina (yksinkertaistettu)"
#: conf/global_settings.py:68
msgid "Traditional Chinese"
msgstr ""
msgstr "kiina (perinteinen)"
#: core/validators.py:63
msgid "This value must contain only letters, numbers and underscores."
@ -211,7 +211,7 @@ msgstr "Tässä voidaan käyttää vain kirjaimia (a-z), numeroita (0-9) sekä a
#: core/validators.py:75
msgid "Uppercase letters are not allowed here."
msgstr "Versaalit (ABC) eivät kelpaa tässä."
msgstr "Isot kirjaimet (ABC) eivät kelpaa tässä."
#: core/validators.py:79
msgid "Lowercase letters are not allowed here."
@ -270,7 +270,7 @@ msgstr "Kuva ei kelpaa. Lähettämäsi tiedosto ei ole kuva, tai tiedosto on vio
#: core/validators.py:162
#, python-format
msgid "The URL %s does not point to a valid image."
msgstr "Osoittessa %s ei ole kelpaavaa kuvaa."
msgstr "Osoittessa %s ei ole kuvaa tai se on vioittunut."
#: core/validators.py:166
#, python-format
@ -280,7 +280,7 @@ msgstr "Puhelinnumeron tulee olla muodossa XXX-XXX-XXXX. \"%s\" ei kelpaa."
#: core/validators.py:174
#, python-format
msgid "The URL %s does not point to a valid QuickTime video."
msgstr "Osoitteessa %s ei ole kelpaavaa QuickTime-videota."
msgstr "Osoitteessa %s ei ole QuickTime-videota tai se on vioittunut."
#: core/validators.py:178
msgid "A valid URL is required."
@ -308,7 +308,7 @@ msgstr "URL-osoite %s ei kelpaa."
#: core/validators.py:213 core/validators.py:215
#, python-format
msgid "The URL %s is a broken link."
msgstr "Osoite %s on katkennut linkki."
msgstr "Osoite %s on rikkoutunut tai väärä linkki."
#: core/validators.py:221
msgid "Enter a valid U.S. state abbreviation."
@ -324,7 +324,7 @@ msgstr[1] "Sanoja \"%s\" ei saa käyttää tässä."
#: core/validators.py:243
#, python-format
msgid "This field must match the '%s' field."
msgstr ""
msgstr "Arvon täytyy olla sama kuin kentässä '%s'."
#: core/validators.py:262
msgid "Please enter something for at least one field."
@ -403,7 +403,7 @@ msgstr "Tämä arvo ei kelpaa."
#: core/validators.py:441
#, python-format
msgid "Could not retrieve anything from %s."
msgstr ""
msgstr "Tietoja ei voida noutaa kohteesta: %s."
#: core/validators.py:444
#, python-format
@ -1676,7 +1676,13 @@ msgid_plural ""
"\n"
"%(text)s"
msgstr[0] ""
"Kommentin kirjoittanut käyttäjä on kirjoittanut vain yhden kommentin:\n"
"\n"
"%(text)s"
msgstr[1] ""
"Kommentin kirjoittanut käyttäjä on kirjoittanut alle %(count)s kommenttia:\n"
"\n"
"%(text)s"
# Mitä "sketchy user" tarkoittaa?
#: contrib/comments/views/comments.py:116
@ -1972,38 +1978,38 @@ msgstr "joulu"
#: utils/timesince.py:12
msgid "year"
msgid_plural "years"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "vuosi"
msgstr[1] "vuotta"
#: utils/timesince.py:13
msgid "month"
msgid_plural "months"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "kuukausi"
msgstr[1] "kuukautta"
#: utils/timesince.py:14
msgid "week"
msgid_plural "weeks"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "viikko"
msgstr[1] "viikkoa"
#: utils/timesince.py:15
msgid "day"
msgid_plural "days"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "päivä"
msgstr[1] "päivää"
#: utils/timesince.py:16
msgid "hour"
msgid_plural "hours"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "tunti"
msgstr[1] "tuntia"
#: utils/timesince.py:17
msgid "minute"
msgid_plural "minutes"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "minuutti"
msgstr[1] "minuuttia"
#: utils/translation/trans_real.py:362
msgid "DATE_FORMAT"
@ -2019,10 +2025,9 @@ msgstr "G:i"
#: utils/translation/trans_real.py:380
msgid "YEAR_MONTH_FORMAT"
msgstr "N j, Y"
msgstr "N Y"
#: utils/translation/trans_real.py:381
#, fuzzy
msgid "MONTH_DAY_FORMAT"
msgstr "N j, Y"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,22 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
# Swedish translation of Django
# Copyright (C) 2005
# This file is distributed under the same license as the Django package.
#
#
# Robin Sonefors <ozamosi@blinkenlights.se>, 2005.
# Mikko Hellsing <mikko@sorl.net>, 2007.
msgid ""
msgstr ""
"Project-Id-Version: Django\n"
"Project-Id-Version: djangojs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2005-12-09 11:51+0100\n"
"PO-Revision-Date: 2005-12-04 14:12+0100\n"
"Last-Translator: Robin Sonefors <ozamosi@blinkenlights.se>\n"
"Language-Team: Django Translators <Django-I18N@googlegroups.com>\n"
"POT-Creation-Date: 2007-03-06 02:29+0100\n"
"PO-Revision-Date: 2007-03-06 10:30+0100\n"
"Last-Translator: Mikko Hellsing <mikko@sorl.net>\n"
"Language-Team: Django I18N <Django-I18N@googlegroups.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-Language: Swedish\n"
"X-Poedit-Country: SWEDEN\n"
@ -24,9 +26,8 @@ msgid "Available %s"
msgstr "Tillgänglig %s"
#: contrib/admin/media/js/SelectFilter2.js:41
#, fuzzy
msgid "Choose all"
msgstr "Välj en tidpunkt"
msgstr "Välj alla"
#: contrib/admin/media/js/SelectFilter2.js:46
msgid "Add"
@ -34,29 +35,31 @@ msgstr "Lägg till"
#: contrib/admin/media/js/SelectFilter2.js:48
msgid "Remove"
msgstr "Tag bort"
msgstr "Ta bort"
#: contrib/admin/media/js/SelectFilter2.js:53
#, perl-format
msgid "Chosen %s"
msgstr "Valde %s"
msgstr "Vald %s"
#: contrib/admin/media/js/SelectFilter2.js:54
msgid "Select your choice(s) and click "
msgstr "Välj ditt/dina val och klicka "
msgstr "Gör dina val och klicka på "
#: contrib/admin/media/js/SelectFilter2.js:59
msgid "Clear all"
msgstr "Avmarkera alla"
msgstr "Ta bort alla"
#: contrib/admin/media/js/dateparse.js:26
#: contrib/admin/media/js/dateparse.js:32
#: contrib/admin/media/js/calendar.js:24
msgid ""
"January February March April May June July August September October November "
"December"
msgstr "Januari Februari Mars April Maj Juni Juli Augusti September Oktober November December"
msgstr ""
"Januari Februari Mars April Maj Juni Juli Augusti September Oktober November "
"December"
#: contrib/admin/media/js/dateparse.js:27
#: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr "Söndag Mondag Tisdag Onsdag Torsdag Fredag Lördag"
@ -64,49 +67,59 @@ msgstr "Söndag Mondag Tisdag Onsdag Torsdag Fredag Lördag"
msgid "S M T W T F S"
msgstr "S M T O T F L"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
msgid "Show"
msgstr "Visa"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
msgid "Hide"
msgstr "Göm"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Now"
msgstr "Nu"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
msgid "Clock"
msgstr "Klocka"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
msgid "Choose a time"
msgstr "Välj en tidpunkt"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "Midnight"
msgstr "Midnatt"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "6 a.m."
msgstr "06.00"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
msgid "Noon"
msgstr "Mitt på dagen"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
msgid "Cancel"
msgstr "Avbryt"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
msgid "Today"
msgstr "Idag"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
msgid "Calendar"
msgstr "Kalender"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
msgid "Yesterday"
msgstr "Igår"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow"
msgstr "Imorgon"

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,110 @@
# translation of djangojs.po to Telugu
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# pavithran <pavithran.s@gmail.com>, 2007.
msgid ""
msgstr ""
"Project-Id-Version: djangojs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2005-12-09 11:51+0100\n"
"PO-Revision-Date: 2007-03-06 16:08+0530\n"
"Last-Translator: pavithran <pavithran.s@gmail.com>\n"
"Language-Team: Telugu <indlinux-telugu@lists.sourceforge.net>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: KBabel 1.11.4\n"
#: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format
msgid "Available %s"
msgstr "ఆందుబాతులోఉన్న %s "
#: contrib/admin/media/js/SelectFilter2.js:41
msgid "Choose all"
msgstr "అన్నీ ఎన్నుకోండి"
#: contrib/admin/media/js/SelectFilter2.js:46
msgid "Add"
msgstr "ఙత చేయి"
#: contrib/admin/media/js/SelectFilter2.js:48
msgid "Remove"
msgstr "తీసివేయండి"
#: contrib/admin/media/js/SelectFilter2.js:53
#, perl-format
msgid "Chosen %s"
msgstr "ఎన్నుకున్న %s"
#: contrib/admin/media/js/SelectFilter2.js:54
msgid "Select your choice(s) and click "
msgstr "మీ ఇష్టాలు ఎన్నుకోండి"
#: contrib/admin/media/js/SelectFilter2.js:59
msgid "Clear all"
msgstr "అన్ని తీసివేయు"
#: contrib/admin/media/js/dateparse.js:26
#: contrib/admin/media/js/calendar.js:24
msgid ""
"January February March April May June July August September October November "
"December"
msgstr "ఙాన్వరి ఫిబ్రవరి మార్చి ఎప్రిల్ మే ఙూను ఙులై ఆగష్టు సెప్టెంబర్ అక్టోబర్ నవంబర్ డిసెంబర్"
#: contrib/admin/media/js/dateparse.js:27
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr "ఆదివారము సోమవారము మంగళవారము బుధవారము గురువారము శుక్రవారము శనివారము"
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
msgstr "ఆ సో మం భు గు శు శ"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
msgid "Now"
msgstr "ఇప్పుడు"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
msgid "Clock"
msgstr "గడియారము"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
msgid "Choose a time"
msgstr "ఒక సమయము ఎన్నుకోండి"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Midnight"
msgstr "ఆర్ధరాత్రి"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "6 a.m."
msgstr "6"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "Noon"
msgstr "మధ్యాహ్నము"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
msgid "Cancel"
msgstr "రద్దు చేయు"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
msgid "Today"
msgstr "ఈనాడు"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
msgid "Calendar"
msgstr "కాలెండర్"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
msgid "Yesterday"
msgstr "నిన్న"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
msgid "Tomorrow"
msgstr "రేపు"

View File

@ -16,8 +16,9 @@ DATABASE_PASSWORD = '' # Not used with sqlite3.
DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
# Local time zone for this installation. All choices can be found here:
# Local time zone for this installation. Choices can be found here:
# http://www.postgresql.org/docs/8.1/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE
# although not all variations may be possible on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Chicago'

View File

@ -7,6 +7,7 @@ from django.db.models import get_apps, get_models, signals
def create_contenttypes(app, created_models, verbosity=2):
from django.contrib.contenttypes.models import ContentType
ContentType.objects.clear_cache()
app_models = get_models(app)
if not app_models:
return

View File

@ -19,6 +19,16 @@ class ContentTypeManager(models.Manager):
model=key[1], defaults={'name': str(opts.verbose_name)})
CONTENT_TYPE_CACHE[key] = ct
return ct
def clear_cache(self):
"""
Clear out the content-type cache. This needs to happen during database
flushes to prevent caching of "stale" content type IDs (see
django.contrib.contenttypes.management.create_contenttypes for where
this gets called).
"""
global CONTENT_TYPE_CACHE
CONTENT_TYPE_CACHE = {}
class ContentType(models.Model):
name = models.CharField(maxlength=100)

View File

@ -1,3 +1,5 @@
from django.utils.translation import ngettext
from django.utils.translation import gettext_lazy as _
from django import template
import re
@ -12,9 +14,9 @@ def ordinal(value):
value = int(value)
except ValueError:
return value
t = ('th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th')
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[0])
return '%d%s' % (value, t[value % 10])
register.filter(ordinal)
@ -41,11 +43,14 @@ def intword(value):
if value < 1000000:
return value
if value < 1000000000:
return '%.1f million' % (value / 1000000.0)
new_value = value / 1000000.0
return ngettext('%(value).1f million', '%(value).1f million', new_value) % {'value': new_value}
if value < 1000000000000:
return '%.1f billion' % (value / 1000000000.0)
new_value = value / 1000000000.0
return ngettext('%(value).1f billion', '%(value).1f billion', new_value) % {'value': new_value}
if value < 1000000000000000:
return '%.1f trillion' % (value / 1000000000000.0)
new_value = value / 1000000000000.0
return ngettext('%(value).1f trillion', '%(value).1f trillion', new_value) % {'value': new_value}
return value
register.filter(intword)
@ -60,5 +65,5 @@ def apnumber(value):
return value
if not 0 < value < 10:
return value
return ('one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine')[value-1]
return (_('one'), _('two'), _('three'), _('four'), _('five'), _('six'), _('seven'), _('eight'), _('nine'))[value-1]
register.filter(apnumber)

View File

@ -32,6 +32,7 @@ STATE_CHOICES = (
('ME', 'Maine'),
('MH', 'Marshall Islands'),
('MD', 'Maryland'),
('MA', 'Massachusetts'),
('MI', 'Michigan'),
('MN', 'Minnesota'),
('MS', 'Mississippi'),
@ -235,4 +236,4 @@ STATES_NORMALIZED = {
'wy': 'WY',
'wyo': 'WY',
'wyoming': 'WY',
}
}

View File

@ -10,6 +10,7 @@ TEST_COOKIE_VALUE = 'worked'
class SessionWrapper(object):
def __init__(self, session_key):
self.session_key = session_key
self.accessed = False
self.modified = False
def __contains__(self, key):
@ -46,6 +47,7 @@ class SessionWrapper(object):
def _get_session(self):
# Lazily loads session from storage.
self.accessed = True
try:
return self._session_cache
except AttributeError:
@ -72,12 +74,14 @@ class SessionMiddleware(object):
def process_response(self, request, response):
# If request.session was modified, or if response.session was set, save
# those changes and set a session cookie.
patch_vary_headers(response, ('Cookie',))
try:
accessed = request.session.accessed
modified = request.session.modified
except AttributeError:
pass
else:
if accessed:
patch_vary_headers(response, ('Cookie',))
if modified or settings.SESSION_SAVE_EVERY_REQUEST:
session_key = request.session.session_key or Session.objects.get_new_session_key()
if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE:

View File

@ -68,6 +68,25 @@ def _get_table_list():
cursor = connection.cursor()
return get_introspection_module().get_table_list(cursor)
def _get_sequence_list():
"Returns a list of information about all DB sequences for all models in all apps"
from django.db import models
apps = models.get_apps()
sequence_list = []
for app in apps:
for model in models.get_models(app):
for f in model._meta.fields:
if isinstance(f, models.AutoField):
sequence_list.append({'table':model._meta.db_table,'column':f.column,})
break # Only one AutoField is allowed per model, so don't bother continuing.
for f in model._meta.many_to_many:
sequence_list.append({'table':f.m2m_db_table(),'column':None,})
return sequence_list
# If the foreign key points to an AutoField, a PositiveIntegerField or a
# PositiveSmallIntegerField, the foreign key should be an IntegerField, not the
# referred field type. Otherwise, the foreign key should be the same type of
@ -334,7 +353,15 @@ def get_sql_reset(app):
get_sql_reset.help_doc = "Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given app name(s)."
get_sql_reset.args = APP_ARGS
def get_sql_initial_data_for_model(model):
def get_sql_flush():
"Returns a list of the SQL statements used to flush the database"
from django.db import backend
statements = backend.get_sql_flush(style, _get_table_list(), _get_sequence_list())
return statements
get_sql_flush.help_doc = "Returns a list of the SQL statements required to return all tables in the database to the state they were in just after they were installed."
get_sql_flush.args = ''
def get_custom_sql_for_model(model):
from django.db import models
from django.conf import settings
@ -361,8 +388,8 @@ def get_sql_initial_data_for_model(model):
return output
def get_sql_initial_data(app):
"Returns a list of the initial INSERT SQL statements for the given app."
def get_custom_sql(app):
"Returns a list of the custom table modifying SQL statements for the given app."
from django.db.models import get_models
output = []
@ -370,11 +397,17 @@ def get_sql_initial_data(app):
app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
for model in app_models:
output.extend(get_sql_initial_data_for_model(model))
output.extend(get_custom_sql_for_model(model))
return output
get_sql_initial_data.help_doc = "Prints the initial INSERT SQL statements for the given app name(s)."
get_sql_initial_data.args = APP_ARGS
get_custom_sql.help_doc = "Prints the custom table modifying SQL statements for the given app name(s)."
get_custom_sql.args = APP_ARGS
def get_sql_initial_data(apps):
"Returns a list of the initial INSERT SQL statements for the given app."
return style.ERROR("This action has been renamed. Try './manage.py sqlcustom %s'." % ' '.join(apps and apps or ['app1', 'app2']))
get_sql_initial_data.help_doc = "RENAMED: see 'sqlcustom'"
get_sql_initial_data.args = ''
def get_sql_sequence_reset(app):
"Returns a list of the SQL statements to reset PostgreSQL sequences for the given app."
@ -432,16 +465,26 @@ def get_sql_indexes_for_model(model):
def get_sql_all(app):
"Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
return get_sql_create(app) + get_sql_initial_data(app) + get_sql_indexes(app)
return get_sql_create(app) + get_custom_sql(app) + get_sql_indexes(app)
get_sql_all.help_doc = "Prints the CREATE TABLE, initial-data and CREATE INDEX SQL statements for the given model module name(s)."
get_sql_all.args = APP_ARGS
def _emit_post_sync_signal(created_models, verbosity, interactive):
from django.db import models
from django.dispatch import dispatcher
# Emit the post_sync signal for every application.
for app in models.get_apps():
app_name = app.__name__.split('.')[-2]
if verbosity >= 2:
print "Running post-sync handlers for application", app_name
dispatcher.send(signal=models.signals.post_syncdb, sender=app,
app=app, created_models=created_models,
verbosity=verbosity, interactive=interactive)
def syncdb(verbosity=1, interactive=True):
"Creates the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
from django.db import connection, transaction, models, get_creation_module
from django.db.models import signals
from django.conf import settings
from django.dispatch import dispatcher
disable_termcolors()
@ -503,27 +546,22 @@ def syncdb(verbosity=1, interactive=True):
# Send the post_syncdb signal, so individual apps can do whatever they need
# to do at this point.
for app in models.get_apps():
app_name = app.__name__.split('.')[-2]
if verbosity >= 2:
print "Running post-sync handlers for application", app_name
dispatcher.send(signal=signals.post_syncdb, sender=app,
app=app, created_models=created_models,
verbosity=verbosity, interactive=interactive)
_emit_post_sync_signal(created_models, verbosity, interactive)
# Install initial data for the app (but only if this is a model we've
# just created)
# Install custom SQL for the app (but only if this
# is a model we've just created)
for app in models.get_apps():
for model in models.get_models(app):
if model in created_models:
initial_sql = get_sql_initial_data_for_model(model)
if initial_sql:
custom_sql = get_custom_sql_for_model(model)
if custom_sql:
if verbosity >= 1:
print "Installing initial data for %s.%s model" % (app_name, model._meta.object_name)
print "Installing custom SQL for %s.%s model" % (app_name, model._meta.object_name)
try:
for sql in initial_sql:
for sql in custom_sql:
cursor.execute(sql)
except Exception, e:
sys.stderr.write("Failed to install initial SQL data for %s.%s model: %s" % \
sys.stderr.write("Failed to install custom SQL for %s.%s model: %s" % \
(app_name, model._meta.object_name, e))
transaction.rollback_unless_managed()
else:
@ -548,7 +586,10 @@ def syncdb(verbosity=1, interactive=True):
else:
transaction.commit_unless_managed()
syncdb.args = ''
# Install the 'initialdata' fixture, using format discovery
load_data(['initial_data'], verbosity=verbosity)
syncdb.help_doc = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
syncdb.args = '[--verbosity] [--interactive]'
def get_admin_index(app):
"Returns admin-index template snippet (in list form) for the given app."
@ -601,36 +642,6 @@ def diffsettings():
print '\n'.join(output)
diffsettings.args = ""
def install(app):
"Executes the equivalent of 'get_sql_all' in the current database."
from django.db import connection, transaction
app_name = app.__name__.split('.')[-2]
disable_termcolors()
# First, try validating the models.
_check_for_validation_errors(app)
sql_list = get_sql_all(app)
try:
cursor = connection.cursor()
for sql in sql_list:
cursor.execute(sql)
except Exception, e:
sys.stderr.write(style.ERROR("""Error: %s couldn't be installed. Possible reasons:
* The database isn't running or isn't configured correctly.
* At least one of the database tables already exists.
* The SQL was invalid.
Hint: Look at the output of 'django-admin.py sqlall %s'. That's the SQL this command wasn't able to run.
The full error: """ % (app_name, app_name)) + style.ERROR_OUTPUT(str(e)) + '\n')
transaction.rollback_unless_managed()
sys.exit(1)
transaction.commit_unless_managed()
install.help_doc = "Executes ``sqlall`` for the given app(s) in the current database."
install.args = APP_ARGS
def reset(app, interactive=True):
"Executes the equivalent of 'get_sql_reset' in the current database."
from django.db import connection, transaction
@ -672,7 +683,68 @@ The full error: """ % (app_name, app_name)) + style.ERROR_OUTPUT(str(e)) + '\n')
else:
print "Reset cancelled."
reset.help_doc = "Executes ``sqlreset`` for the given app(s) in the current database."
reset.args = APP_ARGS
reset.args = '[--interactive]' + APP_ARGS
def flush(verbosity=1, interactive=True):
"Returns all tables in the database to the same state they were in immediately after syncdb."
from django.conf import settings
from django.db import connection, transaction, models
from django.dispatch import dispatcher
disable_termcolors()
# First, try validating the models.
_check_for_validation_errors()
# Import the 'management' module within each installed app, to register
# dispatcher events.
for app_name in settings.INSTALLED_APPS:
try:
__import__(app_name + '.management', {}, {}, [''])
except ImportError:
pass
sql_list = get_sql_flush()
if interactive:
confirm = raw_input("""
You have requested a flush of the database.
This will IRREVERSIBLY DESTROY all data currently in the database,
and return each table to the state it was in after syncdb.
Are you sure you want to do this?
Type 'yes' to continue, or 'no' to cancel: """)
else:
confirm = 'yes'
if confirm == 'yes':
try:
cursor = connection.cursor()
for sql in sql_list:
cursor.execute(sql)
except Exception, e:
sys.stderr.write(style.ERROR("""Error: Database %s couldn't be flushed. Possible reasons:
* The database isn't running or isn't configured correctly.
* At least one of the expected database tables doesn't exist.
* The SQL was invalid.
Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run.
The full error: """ % settings.DATABASE_NAME + style.ERROR_OUTPUT(str(e)) + '\n'))
transaction.rollback_unless_managed()
sys.exit(1)
transaction.commit_unless_managed()
# Emit the post sync signal. This allows individual
# applications to respond as if the database had been
# sync'd from scratch.
_emit_post_sync_signal(models.get_models(), verbosity, interactive)
# Reinstall the initial_data fixture
load_data(['initial_data'], verbosity=verbosity)
else:
print "Flush cancelled."
flush.help_doc = "Executes ``sqlflush`` on the current database."
flush.args = '[--verbosity] [--interactive]'
def _start_helper(app_or_project, name, directory, other_name=''):
other = {'project': 'app', 'app': 'project'}[app_or_project]
@ -755,7 +827,7 @@ def inspectdb():
yield "# * Make sure each model has one field with primary_key=True"
yield "# Feel free to rename the models, but don't rename db_table values or field names."
yield "#"
yield "# Also note: You'll have to insert the output of 'django-admin.py sqlinitialdata [appname]'"
yield "# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [appname]'"
yield "# into your database."
yield ''
yield 'from django.db import models'
@ -1254,6 +1326,125 @@ def test(app_labels, verbosity=1):
test.help_doc = 'Runs the test suite for the specified applications, or the entire site if no apps are specified'
test.args = '[--verbosity] ' + APP_ARGS
def load_data(fixture_labels, verbosity=1):
"Installs the provided fixture file(s) as data in the database."
from django.db.models import get_apps
from django.core import serializers
from django.db import connection, transaction
from django.conf import settings
import sys
# Keep a count of the installed objects and fixtures
count = [0,0]
humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path'
# Get a cursor (even though we don't need one yet). This has
# the side effect of initializing the test database (if
# it isn't already initialized).
cursor = connection.cursor()
# Start transaction management. All fixtures are installed in a
# single transaction to ensure that all references are resolved.
transaction.commit_unless_managed()
transaction.enter_transaction_management()
transaction.managed(True)
app_fixtures = [os.path.join(os.path.dirname(app.__file__),'fixtures') for app in get_apps()]
for fixture_label in fixture_labels:
if verbosity > 0:
print "Loading '%s' fixtures..." % fixture_label
for fixture_dir in app_fixtures + list(settings.FIXTURE_DIRS) + ['']:
if verbosity > 1:
print "Checking %s for fixtures..." % humanize(fixture_dir)
parts = fixture_label.split('.')
if len(parts) == 1:
fixture_name = fixture_label
formats = serializers.get_serializer_formats()
else:
fixture_name, format = '.'.join(parts[:-1]), parts[-1]
formats = [format]
label_found = False
for format in formats:
serializer = serializers.get_serializer(format)
if verbosity > 1:
print "Trying %s for %s fixture '%s'..." % \
(humanize(fixture_dir), format, fixture_name)
try:
full_path = os.path.join(fixture_dir, '.'.join([fixture_name, format]))
fixture = open(full_path, 'r')
if label_found:
fixture.close()
print style.ERROR("Multiple fixtures named '%s' in %s. Aborting." %
(fixture_name, humanize(fixture_dir)))
transaction.rollback()
transaction.leave_transaction_management()
return
else:
count[1] += 1
if verbosity > 0:
print "Installing %s fixture '%s' from %s." % \
(format, fixture_name, humanize(fixture_dir))
try:
objects = serializers.deserialize(format, fixture)
for obj in objects:
count[0] += 1
obj.save()
label_found = True
except Exception, e:
fixture.close()
sys.stderr.write(
style.ERROR("Problem installing fixture '%s': %s\n" %
(full_path, str(e))))
transaction.rollback()
transaction.leave_transaction_management()
return
fixture.close()
except:
if verbosity > 1:
print "No %s fixture '%s' in %s." % \
(format, fixture_name, humanize(fixture_dir))
if count[0] == 0:
if verbosity > 0:
print "No fixtures found."
else:
if verbosity > 0:
print "Installed %d object(s) from %d fixture(s)" % tuple(count)
transaction.commit()
transaction.leave_transaction_management()
load_data.help_doc = 'Installs the named fixture(s) in the database'
load_data.args = "[--verbosity] fixture, fixture, ..."
def dump_data(app_labels, format='json', indent=None):
"Output the current contents of the database as a fixture of the given format"
from django.db.models import get_app, get_apps, get_models
from django.core import serializers
if len(app_labels) == 0:
app_list = get_apps()
else:
app_list = [get_app(app_label) for app_label in app_labels]
# Check that the serialization format exists; this is a shortcut to
# avoid collating all the objects and _then_ failing.
try:
serializers.get_serializer(format)
except KeyError:
sys.stderr.write(style.ERROR("Unknown serialization format: %s\n" % format))
objects = []
for app in app_list:
for model in get_models(app):
objects.extend(model.objects.all())
try:
return serializers.serialize(format, objects, indent=indent)
except Exception, e:
sys.stderr.write(style.ERROR("Unable to serialize database: %s\n" % e))
dump_data.help_doc = 'Output the contents of the database as a fixture of the given format'
dump_data.args = '[--format]' + APP_ARGS
# Utilities for command-line script
DEFAULT_ACTION_MAPPING = {
@ -1261,8 +1452,10 @@ DEFAULT_ACTION_MAPPING = {
'createcachetable' : createcachetable,
'dbshell': dbshell,
'diffsettings': diffsettings,
'dumpdata': dump_data,
'flush': flush,
'inspectdb': inspectdb,
'install': install,
'loaddata': load_data,
'reset': reset,
'runfcgi': runfcgi,
'runserver': runserver,
@ -1270,6 +1463,8 @@ DEFAULT_ACTION_MAPPING = {
'sql': get_sql_create,
'sqlall': get_sql_all,
'sqlclear': get_sql_delete,
'sqlcustom': get_custom_sql,
'sqlflush': get_sql_flush,
'sqlindexes': get_sql_indexes,
'sqlinitialdata': get_sql_initial_data,
'sqlreset': get_sql_reset,
@ -1286,7 +1481,6 @@ NO_SQL_TRANSACTION = (
'createcachetable',
'dbshell',
'diffsettings',
'install',
'reset',
'sqlindexes',
'syncdb',
@ -1333,6 +1527,10 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
help='Tells Django to NOT prompt the user for input of any kind.')
parser.add_option('--noreload', action='store_false', dest='use_reloader', default=True,
help='Tells Django to NOT use the auto-reloader when running the development server.')
parser.add_option('--format', default='json', dest='format',
help='Specifies the output serialization format for fixtures')
parser.add_option('--indent', default=None, dest='indent',
type='int', help='Specifies the indent level to use when pretty-printing output')
parser.add_option('--verbosity', action='store', dest='verbosity', default='1',
type='choice', choices=['0', '1', '2'],
help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
@ -1366,7 +1564,7 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
action_mapping[action](options.plain is True)
elif action in ('validate', 'diffsettings', 'dbshell'):
action_mapping[action]()
elif action == 'syncdb':
elif action in ('flush', 'syncdb'):
action_mapping[action](int(options.verbosity), options.interactive)
elif action == 'inspectdb':
try:
@ -1380,11 +1578,16 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
action_mapping[action](args[1])
except IndexError:
parser.print_usage_and_exit()
elif action == 'test':
elif action in ('test', 'loaddata'):
try:
action_mapping[action](args[1:], int(options.verbosity))
except IndexError:
parser.print_usage_and_exit()
elif action == 'dumpdata':
try:
print action_mapping[action](args[1:], options.format, options.indent)
except IndexError:
parser.print_usage_and_exit()
elif action in ('startapp', 'startproject'):
try:
name = args[1]
@ -1403,6 +1606,10 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
action_mapping[action](addr, port, options.use_reloader, options.admin_media_path)
elif action == 'runfcgi':
action_mapping[action](args[1:])
elif action == 'sqlinitialdata':
print action_mapping[action](args[1:])
elif action == 'sqlflush':
print '\n'.join(action_mapping[action]())
else:
from django.db import models
validate(silent_success=True)

View File

@ -25,6 +25,13 @@ BUILTIN_SERIALIZERS = {
"json" : "django.core.serializers.json",
}
# Check for PyYaml and register the serializer if it's available.
try:
import yaml
BUILTIN_SERIALIZERS["yaml"] = "django.core.serializers.pyyaml"
except ImportError:
pass
_serializers = {}
def register_serializer(format, serializer_module):
@ -40,6 +47,11 @@ def get_serializer(format):
if not _serializers:
_load_serializers()
return _serializers[format].Serializer
def get_serializer_formats():
if not _serializers:
_load_serializers()
return _serializers.keys()
def get_deserializer(format):
if not _serializers:

View File

@ -54,11 +54,7 @@ class Serializer(object):
Convert a field's value to a string.
"""
if isinstance(field, models.DateTimeField):
value = getattr(obj, field.name)
if value is None:
value = ''
else:
value = value.strftime("%Y-%m-%d %H:%M:%S")
value = getattr(obj, field.name).strftime("%Y-%m-%d %H:%M:%S")
elif isinstance(field, models.FileField):
value = getattr(obj, "get_%s_url" % field.name, lambda: None)()
else:
@ -141,7 +137,7 @@ class Deserializer(object):
class DeserializedObject(object):
"""
A deserialzed model.
A deserialized model.
Basically a container for holding the pre-saved deserialized data along
with the many-to-many data saved with the object.

View File

@ -57,7 +57,7 @@ def Deserializer(object_list, **options):
for d in object_list:
# Look up the model and starting build a dict of data for it.
Model = _get_model(d["model"])
data = {Model._meta.pk.attname : d["pk"]}
data = {Model._meta.pk.attname : Model._meta.pk.to_python(d["pk"])}
m2m_data = {}
# Handle each field
@ -70,16 +70,17 @@ def Deserializer(object_list, **options):
# Handle M2M relations
if field.rel and isinstance(field.rel, models.ManyToManyRel):
pks = []
m2m_convert = field.rel.to._meta.pk.to_python
for pk in field_value:
if isinstance(pk, unicode):
pks.append(pk.encode(options.get("encoding", settings.DEFAULT_CHARSET)))
pks.append(m2m_convert(pk.encode(options.get("encoding", settings.DEFAULT_CHARSET))))
else:
pks.append(pk)
pks.append(m2m_convert(pk))
m2m_data[field.name] = pks
# Handle FK fields
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
data[field.attname] = field_value
data[field.attname] = field.rel.to._meta.pk.to_python(field_value)
# Handle all other fields
else:

View File

@ -0,0 +1,36 @@
"""
YAML serializer.
Requires PyYaml (http://pyyaml.org/), but that's checked for in __init__.
"""
import datetime
from django.core.serializers.python import Serializer as PythonSerializer
from django.core.serializers.python import Deserializer as PythonDeserializer
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
import yaml
class Serializer(PythonSerializer):
"""
Convert a queryset to YAML.
"""
def end_serialization(self):
yaml.dump(self.objects, self.stream, **self.options)
def getvalue(self):
return self.stream.getvalue()
def Deserializer(stream_or_string, **options):
"""
Deserialize a stream or string of YAML data.
"""
if isinstance(stream_or_string, basestring):
stream = StringIO(stream_or_string)
else:
stream = stream_or_string
for obj in PythonDeserializer(yaml.load(stream)):
yield obj

View File

@ -13,6 +13,10 @@ class Serializer(base.Serializer):
Serializes a QuerySet to XML.
"""
def indent(self, level):
if self.options.get('indent', None) is not None:
self.xml.ignorableWhitespace('\n' + ' ' * self.options.get('indent', None) * level)
def start_serialization(self):
"""
Start serialization -- open the XML document and the root element.
@ -25,6 +29,7 @@ class Serializer(base.Serializer):
"""
End serialization -- end the document.
"""
self.indent(0)
self.xml.endElement("django-objects")
self.xml.endDocument()
@ -35,6 +40,7 @@ class Serializer(base.Serializer):
if not hasattr(obj, "_meta"):
raise base.SerializationError("Non-model object (%s) encountered during serialization" % type(obj))
self.indent(1)
self.xml.startElement("object", {
"pk" : str(obj._get_pk_val()),
"model" : str(obj._meta),
@ -44,6 +50,7 @@ class Serializer(base.Serializer):
"""
Called after handling all fields for an object.
"""
self.indent(1)
self.xml.endElement("object")
def handle_field(self, obj, field):
@ -51,16 +58,19 @@ class Serializer(base.Serializer):
Called to handle each field on an object (except for ForeignKeys and
ManyToManyFields)
"""
self.indent(2)
self.xml.startElement("field", {
"name" : field.name,
"type" : field.get_internal_type()
})
# Get a "string version" of the object's data (this is handled by the
# serializer base class). None is handled specially.
value = self.get_string_value(obj, field)
if value is not None:
# serializer base class).
if getattr(obj, field.name) is not None:
value = self.get_string_value(obj, field)
self.xml.characters(str(value))
else:
self.xml.addQuickElement("None")
self.xml.endElement("field")
@ -92,6 +102,7 @@ class Serializer(base.Serializer):
"""
Helper to output the <field> element for relational fields
"""
self.indent(2)
self.xml.startElement("field", {
"name" : field.name,
"rel" : field.rel.__class__.__name__,
@ -127,7 +138,8 @@ class Deserializer(base.Deserializer):
pk = node.getAttribute("pk")
if not pk:
raise base.DeserializationError("<object> node is missing the 'pk' attribute")
data = {Model._meta.pk.name : pk}
data = {Model._meta.pk.attname : Model._meta.pk.to_python(pk)}
# Also start building a dict of m2m data (this is saved as
# {m2m_accessor_attribute : [list_of_related_objects]})
@ -148,17 +160,20 @@ class Deserializer(base.Deserializer):
# As is usually the case, relation fields get the special treatment.
if field.rel and isinstance(field.rel, models.ManyToManyRel):
m2m_data[field.name] = self._handle_m2m_field_node(field_node)
m2m_data[field.name] = self._handle_m2m_field_node(field_node, field)
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
data[field.attname] = self._handle_fk_field_node(field_node)
data[field.attname] = self._handle_fk_field_node(field_node, field)
else:
value = field.to_python(getInnerText(field_node).strip().encode(self.encoding))
if len(field_node.childNodes) == 1 and field_node.childNodes[0].nodeName == 'None':
value = None
else:
value = field.to_python(getInnerText(field_node).strip().encode(self.encoding))
data[field.name] = value
# Return a DeserializedObject so that the m2m data has a place to live.
return base.DeserializedObject(Model(**data), m2m_data)
def _handle_fk_field_node(self, node):
def _handle_fk_field_node(self, node, field):
"""
Handle a <field> node for a ForeignKey
"""
@ -166,13 +181,16 @@ class Deserializer(base.Deserializer):
if len(node.childNodes) == 1 and node.childNodes[0].nodeName == 'None':
return None
else:
return getInnerText(node).strip().encode(self.encoding)
return field.rel.to._meta.pk.to_python(
getInnerText(node).strip().encode(self.encoding))
def _handle_m2m_field_node(self, node):
def _handle_m2m_field_node(self, node, field):
"""
Handle a <field> node for a ManyToManyField
"""
return [c.getAttribute("pk").encode(self.encoding) for c in node.getElementsByTagName("object")]
return [field.rel.to._meta.pk.to_python(
c.getAttribute("pk").encode(self.encoding))
for c in node.getElementsByTagName("object")]
def _get_model_from_node(self, node, attr):
"""

View File

@ -140,7 +140,8 @@ def _isValidDate(date_string):
try:
date(year, month, day)
except ValueError, e:
raise ValidationError, gettext('Invalid date: %s.' % e)
msg = gettext('Invalid date: %s') % gettext(str(e))
raise ValidationError, msg
def isValidANSIDate(field_data, all_data):
if not ansi_date_re.search(field_data):
@ -363,7 +364,7 @@ class NumberIsInRange(object):
self.lower, self.upper = lower, upper
if not error_message:
if lower and upper:
self.error_message = gettext("This value must be between %s and %s.") % (lower, upper)
self.error_message = gettext("This value must be between %(lower)s and %(upper)s.") % {'lower': lower, 'upper': upper}
elif lower:
self.error_message = gettext("This value must be at least %s.") % lower
elif upper:

View File

@ -76,10 +76,11 @@ class DatabaseWrapper(local):
return cursor
def _commit(self):
return self.connection.commit()
if self.connection is not None:
return self.connection.commit()
def _rollback(self):
if self.connection:
if self.connection is not None:
return self.connection.rollback()
def close(self):
@ -137,6 +138,19 @@ def get_drop_foreignkey_sql():
def get_pk_default_value():
return "DEFAULT"
def get_sql_flush(sql_styler, full_table_list):
"""Return a list of SQL statements required to remove all data from
all tables in the database (without actually removing the tables
themselves) and put the database in an empty 'initial' state
"""
# Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
# TODO - SQL not actually tested against ADO MSSQL yet!
# TODO - autoincrement indices reset required? See other get_sql_flush() implementations
sql_list = ['%s %s;' % \
(sql_styler.SQL_KEYWORD('TRUNCATE'),
sql_styler.SQL_FIELD(quote_name(table))
) for table in full_table_list]
OPERATOR_MAPPING = {
'exact': '= %s',
'iexact': 'LIKE %s',

View File

@ -39,4 +39,6 @@ get_random_function_sql = complain
get_deferrable_sql = complain
get_fulltext_search_sql = complain
get_drop_foreignkey_sql = complain
get_sql_flush = complain
OPERATOR_MAPPING = {}

View File

@ -10,6 +10,9 @@ try:
except ImportError, e:
from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured, "Error loading MySQLdb module: %s" % e
if Database.version_info < (1,2,1,'final',2):
raise ImportError, "MySQLdb-1.2.1p2 or newer is required; you have %s" % MySQLdb.__version__
from MySQLdb.converters import conversions
from MySQLdb.constants import FIELD_TYPE
import types
@ -17,11 +20,14 @@ import re
DatabaseError = Database.DatabaseError
# MySQLdb-1.2.1 supports the Python boolean type, and only uses datetime
# module for time-related columns; older versions could have used mx.DateTime
# or strings if there were no datetime module. However, MySQLdb still returns
# TIME columns as timedelta -- they are more like timedelta in terms of actual
# behavior as they are signed and include days -- and Django expects time, so
# we still need to override that.
django_conversions = conversions.copy()
django_conversions.update({
types.BooleanType: util.rev_typecast_boolean,
FIELD_TYPE.DATETIME: util.typecast_timestamp,
FIELD_TYPE.DATE: util.typecast_date,
FIELD_TYPE.TIME: util.typecast_time,
})
@ -31,31 +37,12 @@ django_conversions.update({
# http://dev.mysql.com/doc/refman/5.0/en/news.html .
server_version_re = re.compile(r'(\d{1,2})\.(\d{1,2})\.(\d{1,2})')
# This is an extra debug layer over MySQL queries, to display warnings.
# It's only used when DEBUG=True.
class MysqlDebugWrapper:
def __init__(self, cursor):
self.cursor = cursor
def execute(self, sql, params=()):
try:
return self.cursor.execute(sql, params)
except Database.Warning, w:
self.cursor.execute("SHOW WARNINGS")
raise Database.Warning, "%s: %s" % (w, self.cursor.fetchall())
def executemany(self, sql, param_list):
try:
return self.cursor.executemany(sql, param_list)
except Database.Warning, w:
self.cursor.execute("SHOW WARNINGS")
raise Database.Warning, "%s: %s" % (w, self.cursor.fetchall())
def __getattr__(self, attr):
if self.__dict__.has_key(attr):
return self.__dict__[attr]
else:
return getattr(self.cursor, attr)
# MySQLdb-1.2.1 and newer automatically makes use of SHOW WARNINGS on
# MySQL-4.1 and newer, so the MysqlDebugWrapper is unnecessary. Since the
# point is to raise Warnings as exceptions, this can be done with the Python
# warning module, and this is setup when the connection is created, and the
# standard util.CursorDebugWrapper can be used. Also, using sql_mode
# TRADITIONAL will automatically cause most warnings to be treated as errors.
try:
# Only exists in Python 2.4+
@ -83,35 +70,39 @@ class DatabaseWrapper(local):
def cursor(self):
from django.conf import settings
from warnings import filterwarnings
if not self._valid_connection():
kwargs = {
'user': settings.DATABASE_USER,
'db': settings.DATABASE_NAME,
'passwd': settings.DATABASE_PASSWORD,
'conv': django_conversions,
}
if settings.DATABASE_USER:
kwargs['user'] = settings.DATABASE_USER
if settings.DATABASE_NAME:
kwargs['db'] = settings.DATABASE_NAME
if settings.DATABASE_PASSWORD:
kwargs['passwd'] = settings.DATABASE_PASSWORD
if settings.DATABASE_HOST.startswith('/'):
kwargs['unix_socket'] = settings.DATABASE_HOST
else:
elif settings.DATABASE_HOST:
kwargs['host'] = settings.DATABASE_HOST
if settings.DATABASE_PORT:
kwargs['port'] = int(settings.DATABASE_PORT)
kwargs.update(self.options)
self.connection = Database.connect(**kwargs)
cursor = self.connection.cursor()
if self.connection.get_server_info() >= '4.1':
cursor.execute("SET NAMES 'utf8'")
else:
cursor = self.connection.cursor()
if settings.DEBUG:
return util.CursorDebugWrapper(MysqlDebugWrapper(cursor), self)
filterwarnings("error", category=Database.Warning)
return util.CursorDebugWrapper(cursor, self)
return cursor
def _commit(self):
self.connection.commit()
if self.connection is not None:
self.connection.commit()
def _rollback(self):
if self.connection:
if self.connection is not None:
try:
self.connection.rollback()
except Database.NotSupportedError:
@ -186,6 +177,36 @@ def get_drop_foreignkey_sql():
def get_pk_default_value():
return "DEFAULT"
def get_sql_flush(style, tables, sequences):
"""Return a list of SQL statements required to remove all data from
all tables in the database (without actually removing the tables
themselves) and put the database in an empty 'initial' state
"""
# NB: The generated SQL below is specific to MySQL
# 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
# to clear all tables of all data
if tables:
sql = ['SET FOREIGN_KEY_CHECKS = 0;'] + \
['%s %s;' % \
(style.SQL_KEYWORD('TRUNCATE'),
style.SQL_FIELD(quote_name(table))
) for table in tables] + \
['SET FOREIGN_KEY_CHECKS = 1;']
# 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements
# to reset sequence indices
sql.extend(["%s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('TABLE'),
style.SQL_TABLE(quote_name(sequence['table'])),
style.SQL_KEYWORD('AUTO_INCREMENT'),
style.SQL_FIELD('= 1'),
) for sequence in sequences])
return sql
else:
return []
OPERATOR_MAPPING = {
'exact': '= %s',
'iexact': 'LIKE %s',

View File

@ -3,12 +3,25 @@ import os
def runshell():
args = ['']
args += ["--user=%s" % settings.DATABASE_USER]
if settings.DATABASE_PASSWORD:
args += ["--password=%s" % settings.DATABASE_PASSWORD]
if settings.DATABASE_HOST:
args += ["--host=%s" % settings.DATABASE_HOST]
if settings.DATABASE_PORT:
args += ["--port=%s" % settings.DATABASE_PORT]
args += [settings.DATABASE_NAME]
db = settings.DATABASE_OPTIONS.get('db', settings.DATABASE_NAME)
user = settings.DATABASE_OPTIONS.get('user', settings.DATABASE_USER)
passwd = settings.DATABASE_OPTIONS.get('passwd', settings.DATABASE_PASSWORD)
host = settings.DATABASE_OPTIONS.get('host', settings.DATABASE_HOST)
port = settings.DATABASE_OPTIONS.get('port', settings.DATABASE_PORT)
defaults_file = settings.DATABASE_OPTIONS.get('read_default_file')
# Seems to be no good way to set sql_mode with CLI
if defaults_file:
args += ["--defaults-file=%s" % defaults_file]
if user:
args += ["--user=%s" % user]
if passwd:
args += ["--password=%s" % passwd]
if host:
args += ["--host=%s" % host]
if port:
args += ["--port=%s" % port]
if db:
args += [db]
os.execvp('mysql', args)

View File

@ -43,10 +43,11 @@ class DatabaseWrapper(local):
return FormatStylePlaceholderCursor(self.connection)
def _commit(self):
self.connection.commit()
if self.connection is not None:
self.connection.commit()
def _rollback(self):
if self.connection:
if self.connection is not None:
try:
self.connection.rollback()
except Database.NotSupportedError:
@ -120,6 +121,20 @@ def get_drop_foreignkey_sql():
def get_pk_default_value():
return "DEFAULT"
def get_sql_flush(style, tables, sequences):
"""Return a list of SQL statements required to remove all data from
all tables in the database (without actually removing the tables
themselves) and put the database in an empty 'initial' state
"""
# Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
# TODO - SQL not actually tested against Oracle yet!
# TODO - autoincrement indices reset required? See other get_sql_flush() implementations
sql = ['%s %s;' % \
(style.SQL_KEYWORD('TRUNCATE'),
style.SQL_FIELD(quote_name(table))
) for table in tables]
OPERATOR_MAPPING = {
'exact': '= %s',
'iexact': 'LIKE %s',

View File

@ -52,6 +52,8 @@ class UnicodeCursorWrapper(object):
else:
return getattr(self.cursor, attr)
postgres_version = None
class DatabaseWrapper(local):
def __init__(self, **kwargs):
self.connection = None
@ -81,15 +83,20 @@ class DatabaseWrapper(local):
if set_tz:
cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE])
cursor = UnicodeCursorWrapper(cursor, settings.DEFAULT_CHARSET)
global postgres_version
if not postgres_version:
cursor.execute("SELECT version()")
postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')]
if settings.DEBUG:
return util.CursorDebugWrapper(cursor, self)
return cursor
def _commit(self):
return self.connection.commit()
if self.connection is not None:
return self.connection.commit()
def _rollback(self):
if self.connection:
if self.connection is not None:
return self.connection.rollback()
def close(self):
@ -151,6 +158,62 @@ def get_drop_foreignkey_sql():
def get_pk_default_value():
return "DEFAULT"
def get_sql_flush(style, tables, sequences):
"""Return a list of SQL statements required to remove all data from
all tables in the database (without actually removing the tables
themselves) and put the database in an empty 'initial' state
"""
if tables:
if postgres_version[0] >= 8 and postgres_version[1] >= 1:
# Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to* in order to be able to
# truncate tables referenced by a foreign key in any other table. The result is a
# single SQL TRUNCATE statement.
sql = ['%s %s;' % \
(style.SQL_KEYWORD('TRUNCATE'),
style.SQL_FIELD(', '.join([quote_name(table) for table in tables]))
)]
else:
# Older versions of Postgres can't do TRUNCATE in a single call, so they must use
# a simple delete.
sql = ['%s %s %s;' % \
(style.SQL_KEYWORD('DELETE'),
style.SQL_KEYWORD('FROM'),
style.SQL_FIELD(quote_name(table))
) for table in tables]
# 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
# to reset sequence indices
for sequence_info in sequences:
table_name = sequence_info['table']
column_name = sequence_info['column']
if column_name and len(column_name)>0:
# sequence name in this case will be <table>_<column>_seq
sql.append("%s %s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('SEQUENCE'),
style.SQL_FIELD('%s_%s_seq' % (table_name, column_name)),
style.SQL_KEYWORD('RESTART'),
style.SQL_KEYWORD('WITH'),
style.SQL_FIELD('1')
)
)
else:
# sequence name in this case will be <table>_id_seq
sql.append("%s %s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('SEQUENCE'),
style.SQL_FIELD('%s_id_seq' % table_name),
style.SQL_KEYWORD('RESTART'),
style.SQL_KEYWORD('WITH'),
style.SQL_FIELD('1')
)
)
return sql
else:
return []
# Register these custom typecasts, because Django expects dates/times to be
# in Python's native (standard-library) datetime/time format, whereas psycopg
# use mx.DateTime by default.

View File

@ -20,6 +20,8 @@ except ImportError:
# Import copy of _thread_local.py from Python 2.4
from django.utils._threading_local import local
postgres_version = None
class DatabaseWrapper(local):
def __init__(self, **kwargs):
self.connection = None
@ -49,15 +51,20 @@ class DatabaseWrapper(local):
cursor.tzinfo_factory = None
if set_tz:
cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE])
global postgres_version
if not postgres_version:
cursor.execute("SELECT version()")
postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')]
if settings.DEBUG:
return util.CursorDebugWrapper(cursor, self)
return cursor
def _commit(self):
return self.connection.commit()
if self.connection is not None:
return self.connection.commit()
def _rollback(self):
if self.connection:
if self.connection is not None:
return self.connection.rollback()
def close(self):
@ -111,6 +118,58 @@ def get_drop_foreignkey_sql():
def get_pk_default_value():
return "DEFAULT"
def get_sql_flush(style, tables, sequences):
"""Return a list of SQL statements required to remove all data from
all tables in the database (without actually removing the tables
themselves) and put the database in an empty 'initial' state
"""
if tables:
if postgres_version[0] >= 8 and postgres_version[1] >= 1:
# Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to* in order to be able to
# truncate tables referenced by a foreign key in any other table. The result is a
# single SQL TRUNCATE statement
sql = ['%s %s;' % \
(style.SQL_KEYWORD('TRUNCATE'),
style.SQL_FIELD(', '.join([quote_name(table) for table in tables]))
)]
else:
sql = ['%s %s %s;' % \
(style.SQL_KEYWORD('DELETE'),
style.SQL_KEYWORD('FROM'),
style.SQL_FIELD(quote_name(table))
) for table in tables]
# 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
# to reset sequence indices
for sequence in sequences:
table_name = sequence['table']
column_name = sequence['column']
if column_name and len(column_name) > 0:
# sequence name in this case will be <table>_<column>_seq
sql.append("%s %s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('SEQUENCE'),
style.SQL_FIELD('%s_%s_seq' % (table_name, column_name)),
style.SQL_KEYWORD('RESTART'),
style.SQL_KEYWORD('WITH'),
style.SQL_FIELD('1')
)
)
else:
# sequence name in this case will be <table>_id_seq
sql.append("%s %s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('SEQUENCE'),
style.SQL_FIELD('%s_id_seq' % table_name),
style.SQL_KEYWORD('RESTART'),
style.SQL_KEYWORD('WITH'),
style.SQL_FIELD('1')
)
)
return sql
else:
return []
OPERATOR_MAPPING = {
'exact': '= %s',
'iexact': 'ILIKE %s',

View File

@ -67,10 +67,11 @@ class DatabaseWrapper(local):
return cursor
def _commit(self):
self.connection.commit()
if self.connection is not None:
self.connection.commit()
def _rollback(self):
if self.connection:
if self.connection is not None:
self.connection.rollback()
def close(self):
@ -151,6 +152,24 @@ def get_drop_foreignkey_sql():
def get_pk_default_value():
return "NULL"
def get_sql_flush(style, tables, sequences):
"""Return a list of SQL statements required to remove all data from
all tables in the database (without actually removing the tables
themselves) and put the database in an empty 'initial' state
"""
# NB: The generated SQL below is specific to SQLite
# Note: The DELETE FROM... SQL generated below works for SQLite databases
# because constraints don't exist
sql = ['%s %s %s;' % \
(style.SQL_KEYWORD('DELETE'),
style.SQL_KEYWORD('FROM'),
style.SQL_FIELD(quote_name(table))
) for table in tables]
# Note: No requirement for reset of auto-incremented indices (cf. other
# get_sql_flush() implementations). Just return SQL at this point
return sql
def _sqlite_date_trunc(lookup_type, dt):
try:
dt = util.typecast_timestamp(dt)

View File

@ -739,6 +739,13 @@ class NullBooleanField(Field):
kwargs['null'] = True
Field.__init__(self, *args, **kwargs)
def to_python(self, value):
if value in (None, True, False): return value
if value in ('None'): return None
if value in ('t', 'True', '1'): return True
if value in ('f', 'False', '0'): return False
raise validators.ValidationError, gettext("This value must be either None, True or False.")
def get_manipulator_field_objs(self):
return [oldforms.NullBooleanField]
@ -821,7 +828,7 @@ class TimeField(Field):
if value is not None:
# MySQL will throw a warning if microseconds are given, because it
# doesn't support microseconds.
if settings.DATABASE_ENGINE == 'mysql':
if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'):
value = value.replace(microsecond=0)
value = str(value)
return Field.get_db_prep_save(self, value)

View File

@ -1,7 +1,7 @@
class BoundRelatedObject(object):
def __init__(self, related_object, field_mapping, original):
self.relation = related_object
self.field_mappings = field_mapping[related_object.opts.module_name]
self.field_mappings = field_mapping[related_object.name]
def template_name(self):
raise NotImplementedError
@ -16,7 +16,7 @@ class RelatedObject(object):
self.opts = model._meta
self.field = field
self.edit_inline = field.rel.edit_inline
self.name = self.opts.module_name
self.name = '%s:%s' % (self.opts.app_label, self.opts.module_name)
self.var_name = self.opts.object_name.lower()
def flatten_data(self, follow, obj=None):

View File

@ -130,7 +130,9 @@ class FormWrapper(object):
if self.edit_inline:
self.fill_inline_collections()
for inline_collection in self._inline_collections:
if inline_collection.name == key:
# The 'orig_name' comparison is for backwards compatibility
# with hand-crafted forms.
if inline_collection.name == key or (':' not in key and inline_collection.orig_name == key):
return inline_collection
raise KeyError, "Could not find Formfield or InlineObjectCollection named %r" % key
@ -226,6 +228,9 @@ class InlineObjectCollection(object):
self.errors = errors
self._collections = None
self.name = rel_obj.name
# This is the name used prior to fixing #1839. Needs for backwards
# compatibility.
self.orig_name = rel_obj.opts.module_name
def __len__(self):
self.fill()

View File

@ -91,6 +91,8 @@ UNKNOWN_SOURCE="&lt;unknown source&gt;"
tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END),
re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END),
re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END)))
# matches if the string is valid number
number_re = re.compile(r'[-+]?(\d+|\d*\.\d+)$')
# global dictionary of libraries that have been loaded using get_library
libraries = {}
@ -632,12 +634,9 @@ def resolve_variable(path, context):
(The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.')
"""
if path[0].isdigit():
if number_re.match(path):
number_type = '.' in path and float or int
try:
current = number_type(path)
except ValueError:
current = settings.TEMPLATE_STRING_IF_INVALID
current = number_type(path)
elif path[0] in ('"', "'") and path[0] == path[-1]:
current = path[1:-1]
else:

View File

@ -70,14 +70,15 @@ def floatformat(text, arg=-1):
With a negative numeric argument, it will display that many decimal
places -- but only if there's places to be displayed.
Examples:
num1 = 34.23234
num2 = 34.00000
num1|floatformat results in 34.2
num2|floatformat is 34
num1|floatformat:3 is 34.232
num2|floatformat:3 is 34.000
num1|floatformat:-3 is 34.232
num2|floatformat:-3 is 34
* num1 = 34.23234
* num2 = 34.00000
* num1|floatformat results in 34.2
* num2|floatformat is 34
* num1|floatformat:3 is 34.232
* num2|floatformat:3 is 34.000
* num1|floatformat:-3 is 34.232
* num2|floatformat:-3 is 34
"""
try:
f = float(text)

View File

@ -435,6 +435,15 @@ def cycle(parser, token):
cycle = register.tag(cycle)
def debug(parser, token):
"""
Output a whole load of debugging information, including the current context and imported modules.
Sample usage::
<pre>
{% debug %}
</pre>
"""
return DebugNode()
debug = register.tag(debug)
@ -538,21 +547,6 @@ def do_for(parser, token):
do_for = register.tag("for", do_for)
def do_ifequal(parser, token, negate):
"""
Output the contents of the block if the two arguments equal/don't equal each other.
Examples::
{% ifequal user.id comment.user_id %}
...
{% endifequal %}
{% ifnotequal user.id comment.user_id %}
...
{% else %}
...
{% endifnotequal %}
"""
bits = list(token.split_contents())
if len(bits) != 3:
raise TemplateSyntaxError, "%r takes two arguments" % bits[0]
@ -568,11 +562,27 @@ def do_ifequal(parser, token, negate):
#@register.tag
def ifequal(parser, token):
"""
Output the contents of the block if the two arguments equal each other.
Examples::
{% ifequal user.id comment.user_id %}
...
{% endifequal %}
{% ifnotequal user.id comment.user_id %}
...
{% else %}
...
{% endifnotequal %}
"""
return do_ifequal(parser, token, False)
ifequal = register.tag(ifequal)
#@register.tag
def ifnotequal(parser, token):
"""Output the contents of the block if the two arguments are not equal. See ifequal."""
return do_ifequal(parser, token, True)
ifnotequal = register.tag(ifnotequal)
@ -889,8 +899,9 @@ templatetag = register.tag(templatetag)
def url(parser, token):
"""
Returns an absolute URL matching given view with its parameters. This is a
way to define links that aren't tied to a particular url configuration:
Returns an absolute URL matching given view with its parameters.
This is a way to define links that aren't tied to a particular URL configuration::
{% url path.to.some_view arg1,arg2,name1=value1 %}
@ -901,16 +912,16 @@ def url(parser, token):
URL. All arguments for the URL should be present.
For example if you have a view ``app_name.client`` taking client's id and
the corresponding line in a urlconf looks like this:
the corresponding line in a URLconf looks like this::
('^client/(\d+)/$', 'app_name.client')
and this app's urlconf is included into the project's urlconf under some
path:
and this app's URLconf is included into the project's URLconf under some
path::
('^clients/', include('project_name.app_name.urls'))
then in a template you can create a link for a certain client like this:
then in a template you can create a link for a certain client like this::
{% url app_name.client client.id %}

View File

@ -0,0 +1,6 @@
"""
Django Unit Test and Doctest framework.
"""
from django.test.client import Client
from django.test.testcases import TestCase

View File

@ -1,5 +1,7 @@
import re, doctest, unittest
from django.db import transaction
from django.core import management
from django.db.models import get_apps
normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s)
@ -28,3 +30,21 @@ class DocTestRunner(doctest.DocTestRunner):
from django.db import transaction
transaction.rollback_unless_managed()
class TestCase(unittest.TestCase):
def install_fixtures(self):
"""If the Test Case class has a 'fixtures' member, clear the database and
install the named fixtures at the start of each test.
"""
management.flush(verbosity=0, interactive=False)
if hasattr(self, 'fixtures'):
management.load_data(self.fixtures, verbosity=0)
def run(self, result=None):
"""Wrapper around default run method so that user-defined Test Cases
automatically call install_fixtures without having to include a call to
super().
"""
self.install_fixtures()
super(TestCase, self).run(result)

View File

@ -92,6 +92,13 @@ class SortedDict(dict):
"Returns the value of the item at the given zero-based index."
return self[self.keyOrder[index]]
def copy(self):
"Returns a copy of this object."
# This way of initializing the copy means it works for subclasses, too.
obj = self.__class__(self)
obj.keyOrder = self.keyOrder
return obj
class MultiValueDictKeyError(KeyError):
pass

View File

@ -13,6 +13,7 @@ Usage:
from django.utils.dates import MONTHS, MONTHS_3, MONTHS_AP, WEEKDAYS
from django.utils.tzinfo import LocalTimezone
from django.utils.translation import gettext as _
from calendar import isleap, monthrange
import re, time
@ -36,14 +37,14 @@ class TimeFormat(Formatter):
def a(self):
"'a.m.' or 'p.m.'"
if self.data.hour > 11:
return 'p.m.'
return 'a.m.'
return _('p.m.')
return _('a.m.')
def A(self):
"'AM' or 'PM'"
if self.data.hour > 11:
return 'PM'
return 'AM'
return _('PM')
return _('AM')
def B(self):
"Swatch Internet time"
@ -91,9 +92,9 @@ class TimeFormat(Formatter):
Proprietary extension.
"""
if self.data.minute == 0 and self.data.hour == 0:
return 'midnight'
return _('midnight')
if self.data.minute == 0 and self.data.hour == 12:
return 'noon'
return _('noon')
return '%s %s' % (self.f(), self.a())
def s(self):

View File

@ -9,16 +9,16 @@ def set_language(request):
"""
Redirect to a given url while setting the chosen language in the
session or cookie. The url and the language code need to be
specified in the GET paramters.
specified in the GET parameters.
"""
lang_code = request.GET['language']
lang_code = request.GET.get('language', None)
next = request.GET.get('next', None)
if not next:
next = request.META.get('HTTP_REFERER', None)
if not next:
next = '/'
response = http.HttpResponseRedirect(next)
if check_for_language(lang_code):
if lang_code and check_for_language(lang_code):
if hasattr(request, 'session'):
request.session['django_language'] = lang_code
else:

View File

@ -195,7 +195,7 @@ The second part of this workflow involves a set of flags the describe what the
ticket has or needs in order to be "ready for checkin":
"Has patch"
The means the ticket has an associated patch_. These will be
This means the ticket has an associated patch_. These will be
reviewed to see if the patch is "good".
"Needs documentation"
@ -212,6 +212,33 @@ ticket has or needs in order to be "ready for checkin":
ready for checkin. This could mean the patch no longer applies
cleanly, or that the code doesn't live up to our standards.
A ticket can be resolved in a number of ways:
"fixed"
Used by one of the core developers once a patch has been rolled into
Django and the issue is fixed.
"invalid"
Used if the ticket is found to be incorrect or a user error.
"wontfix"
Used when a core developer decides that this request is not
appropriate for consideration in Django. This is usually chosen after
discussion in the ``django-developers`` mailing list, and you should
feel free to join in when it's something you care about.
"duplicate"
Used when another ticket covers the same issue. By closing duplicate
tickets, we keep all the discussion in one place, which helps everyone.
"worksforme"
Used when the triage team is unable to replicate the original bug.
If you believe that the ticket was closed in error -- because you're
still having the issue, or it's popped up somewhere else, or the triagers have
-- made a mistake, please reopen the ticket and tell us why. Please do not
reopen tickets that have been marked as "wontfix" by core developers.
.. _required details: `Reporting bugs`_
.. _good patch: `Patch style`_
.. _patch: `Submitting patches`_
@ -276,9 +303,11 @@ Please follow these coding standards when writing code for inclusion in Django:
def my_view(req, foo):
# ...
* Please don't put your name in the code. While we appreciate all
contributions to Django, our policy is not to publish individual
developer names in code -- for instance, at the top of Python modules.
* Please don't put your name in the code you contribute. Our policy is to
keep contributors' names in the ``AUTHORS`` file distributed with Django
-- not scattered throughout the codebase itself. Feel free to include a
change to the ``AUTHORS`` file in your patch if you make more than a
single trivial change.
Committing code
===============
@ -498,12 +527,12 @@ sure all other lines are commented::
# http://code.djangoproject.com/svn/django/trunk/
#
/path/to/trunk
# <branch> is a svn checkout of:
# http://code.djangoproject.com/svn/django/branches/<branch>/
#
#/path/to/<branch>
# On windows a path may look like this:
# C:/path/to/<branch>

162
docs/databases.txt Normal file
View File

@ -0,0 +1,162 @@
===============================
Notes about supported databases
===============================
Django attempts to support as many features as possible on all database
backends. However, not all database backends are alike, and we've had to make
design decisions on which features to support and which assumptions we can make
safely.
This file describes some of the features that might be relevant to Django
usage. Of course, it is not intended as a replacement for server-specific
documentation or reference manuals.
MySQL notes
===========
Django expects the database to support transactions, referential integrity,
and Unicode support (UTF-8 encoding). Fortunately, MySQL_ has all these
features as available as far back as 3.23. While it may be possible to use
3.23 or 4.0, you'll probably have less trouble if you use 4.1 or 5.0.
MySQL 4.1
---------
`MySQL 4.1`_ has greatly improved support for character sets. It is possible to
set different default character sets on the database, table, and column.
Previous versions have only a server-wide character set setting. It's also the
first version where the character set can be changed on the fly. 4.1 also has
support for views, but Django currently doesn't use views.
MySQL 5.0
---------
`MySQL 5.0`_ adds the ``information_schema`` database, which contains detailed
data on all database schema. Django's ``inspectdb`` feature uses this
``information_schema`` if it's available. 5.0 also has support for stored
procedures, but Django currently doesn't use stored procedures.
.. _MySQL: http://www.mysql.com/
.. _MySQL 4.1: http://dev.mysql.com/doc/refman/4.1/en/index.html
.. _MySQL 5.0: http://dev.mysql.com/doc/refman/5.0/en/index.html
Storage engines
---------------
MySQL has several `storage engines`_ (previously called table types). You can
change the default storage engine in the server configuration.
The default engine is MyISAM_. The main drawback of MyISAM is that it doesn't
currently support transactions or foreign keys. On the plus side, it's
currently the only engine that supports full-text indexing and searching.
The InnoDB_ engine is fully transactional and supports foreign key references.
The BDB_ engine, like InnoDB, is also fully transactional and supports foreign
key references. However, its use seems to be deprecated.
`Other storage engines`_, including SolidDB_ and Falcon_, are on the horizon.
For now, InnoDB is probably your best choice.
.. _storage engines: http://dev.mysql.com/doc/refman/5.0/en/storage-engines.html
.. _MyISAM: http://dev.mysql.com/doc/refman/5.0/en/myisam-storage-engine.html
.. _BDB: http://dev.mysql.com/doc/refman/5.0/en/bdb-storage-engine.html
.. _InnoDB: http://dev.mysql.com/doc/refman/5.0/en/innodb.html
.. _Other storage engines: http://dev.mysql.com/doc/refman/5.1/en/storage-engines-other.html
.. _SolidDB: http://forge.mysql.com/projects/view.php?id=139
.. _Falcon: http://dev.mysql.com/doc/falcon/en/index.html
MySQLdb
-------
`MySQLdb`_ is the Python interface to MySQL. 1.2.1 is the first version that
has support for MySQL 4.1 and newer. If you are trying to use an older version
of MySQL, then 1.2.0 *might* work for you.
.. _MySQLdb: http://sourceforge.net/projects/mysql-python
Creating your database
----------------------
You can `create your database`_ using the command-line tools and this SQL::
CREATE DATABASE <dbname> CHARACTER SET utf8;
This ensures all tables and columns will use UTF-8 by default.
.. _create your database: http://dev.mysql.com/doc/refman/5.0/en/create-database.html
Connecting to the database
--------------------------
Refer to the `settings documentation`_.
Connection settings are used in this order:
1. ``DATABASE_OPTIONS``
2. ``DATABASE_NAME``, ``DATABASE_USER``, ``DATABASE_PASSWORD``, ``DATABASE_HOST``,
``DATABASE_PORT``
3. MySQL option files.
In other words, if you set the name of the database in ``DATABASE_OPTIONS``,
this will take precedence over ``DATABASE_NAME``, which would override
anything in a `MySQL option file`_.
Here's a sample configuration which uses a MySQL option file::
# settings.py
DATABASE_ENGINE = "mysql"
DATABASE_OPTIONS = {
'read_default_file': '/path/to/my.cnf',
}
# my.cnf
[client]
database = DATABASE_NAME
user = DATABASE_USER
passwd = DATABASE_PASSWORD
default-character-set = utf8
Several other MySQLdb connection options may be useful, such as ``ssl``,
``use_unicode``, ``init_command``, and ``sql_mode``. Consult the
`MySQLdb documentation`_ for more details.
.. _settings documentation: http://www.djangoproject.com/documentation/settings/#database-engine
.. _MySQL option file: http://dev.mysql.com/doc/refman/5.0/en/option-files.html
.. _MySQLdb documentation: http://mysql-python.sourceforge.net/
Creating your tables
--------------------
When Django generates the schema, it doesn't specify a storage engine, so
tables will be created with whatever default storage engine your database
server is configured for. The easiest solution is to set your database server's
default storage engine to the desired engine.
If you're using a hosting service and can't change your server's default
storage engine, you have a couple of options.
* After the tables are created, execute an ``ALTER TABLE`` statement to
convert a table to a new storage engine (such as InnoDB)::
ALTER TABLE <tablename> ENGINE=INNODB;
This can be tedious if you have a lot of tables.
* Another option is to use the ``init_command`` option for MySQLdb prior to
creating your tables::
DATABASE_OPTIONS = {
# ...
"init_command": "SET storage_engine=INNODB",
# ...
}
This sets the default storage engine upon connecting to the database.
After your tables have been created, you should remove this option.
* Another method for changing the storage engine is described in
AlterModelOnSyncDB_.
.. _AlterModelOnSyncDB: http://code.djangoproject.com/wiki/AlterModelOnSyncDB

View File

@ -6,7 +6,7 @@ Once you've created your `data models`_, Django automatically gives you a
database-abstraction API that lets you create, retrieve, update and delete
objects. This document explains that API.
.. _`data models`: http://www.djangoproject.com/documentation/model_api/
.. _`data models`: ../model_api/
Throughout this reference, we'll refer to the following models, which comprise
a weblog application::
@ -85,7 +85,7 @@ There's no way to tell what the value of an ID will be before you call
unless you explicitly specify ``primary_key=True`` on a field. See the
`AutoField documentation`_.)
.. _AutoField documentation: http://www.djangoproject.com/documentation/model_api/#autofield
.. _AutoField documentation: ../model_api/#autofield
Explicitly specifying auto-primary-key values
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -1801,4 +1801,4 @@ 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
.. _Executing custom SQL: ../model_api/#executing-custom-sql

View File

@ -57,7 +57,7 @@ Gentoo
------
A Django build is available for `Gentoo Linux`_, and is based on Django 0.95.1.
The `current Gentoo build`_ can be installed by typing ``emerge Django``.
The `current Gentoo build`_ can be installed by typing ``emerge django``.
.. _Gentoo Linux: http://www.gentoo.org/
.. _current Gentoo build: http://packages.gentoo.org/packages/?category=dev-python;name=django

View File

@ -97,6 +97,33 @@ example, the default settings don't define ``ROOT_URLCONF``, so
Note that Django's default settings live in ``django/conf/global_settings.py``,
if you're ever curious to see the full list of defaults.
dumpdata [appname appname ...]
------------------------------
**New in Django development version**
Output to standard output all data in the database associated with the named
application(s).
By default, the database will be dumped in JSON format. If you want the output
to be in another format, use the ``--format`` option (e.g., ``format=xml``).
You may specify any Django serialization backend (including any user specified
serialization backends named in the ``SERIALIZATION_MODULES`` setting).
If no application name is provided, all installed applications will be dumped.
The output of ``dumpdata`` can be used as input for ``loaddata``.
flush
-----
**New in Django development version**
Return the database to the state it was in immediately after syncdb was
executed. This means that all data will be removed from the database, any
post-synchronization handlers will be re-executed, and the ``initial_data``
fixture will be re-installed.
inspectdb
---------
@ -141,8 +168,78 @@ only works in PostgreSQL and with certain types of MySQL tables.
install [appname appname ...]
-----------------------------
**Removed in Django development version**
Executes the equivalent of ``sqlall`` for the given appnames.
loaddata [fixture fixture ...]
------------------------------
**New in Django development version**
Searches for and loads the contents of the named fixture into the database.
A *Fixture* is a collection of files that contain the serialized contents of
the database. Each fixture has a unique name; however, the files that
comprise the fixture can be distributed over multiple directories, in
multiple applications.
Django will search in three locations for fixtures:
1. In the ``fixtures`` directory of every installed application
2. In any directory named in the ``FIXTURE_DIRS`` setting
3. In the literal path named by the fixture
Django will load any and all fixtures it finds in these locations that match
the provided fixture names.
If the named fixture has a file extension, only fixtures of that type
will be loaded. For example::
django-admin.py loaddata mydata.json
would only load JSON fixtures called ``mydata``. The fixture extension
must correspond to the registered name of a serializer (e.g., ``json`` or
``xml``).
If you omit the extension, Django will search all available fixture types
for a matching fixture. For example::
django-admin.py loaddata mydata
would look for any fixture of any fixture type called ``mydata``. If a fixture
directory contained ``mydata.json``, that fixture would be loaded
as a JSON fixture. However, if two fixtures with the same name but different
fixture type are discovered (for example, if ``mydata.json`` and
``mydata.xml`` were found in the same fixture directory), fixture
installation will be aborted, and any data installed in the call to
``loaddata`` will be removed from the database.
The fixtures that are named can include directory components. These
directories will be included in the search path. For example::
django-admin.py loaddata foo/bar/mydata.json
would search ``<appname>/fixtures/foo/bar/mydata.json`` for each installed
application, ``<dirname>/foo/bar/mydata.json`` for each directory in
``FIXTURE_DIRS``, and the literal path ``foo/bar/mydata.json``.
Note that the order in which fixture files are processed is undefined. However,
all fixture data is installed as a single transaction, so data in
one fixture can reference data in another fixture. If the database backend
supports row-level constraints, these constraints will be checked at the
end of the transaction.
.. admonition:: MySQL and Fixtures
Unfortunately, MySQL isn't capable of completely supporting all the
features of Django fixtures. If you use MyISAM tables, MySQL doesn't
support transactions or constraints, so you won't get a rollback if
multiple transaction files are found, or validation of fixture data.
If you use InnoDB tables, you won't be able to have any forward
references in your data files - MySQL doesn't provide a mechanism to
defer checking of row constraints until a transaction is committed.
reset [appname appname ...]
---------------------------
Executes the equivalent of ``sqlreset`` for the given appnames.
@ -250,15 +347,12 @@ sqlclear [appname appname ...]
Prints the DROP TABLE SQL statements for the given appnames.
sqlindexes [appname appname ...]
----------------------------------------
sqlcustom [appname appname ...]
-------------------------------
Prints the CREATE INDEX SQL statements for the given appnames.
**New in Django development version**
sqlinitialdata [appname appname ...]
--------------------------------------------
Prints the initial INSERT SQL statements for the given appnames.
Prints the custom SQL statements for the given appnames.
For each model in each specified app, this command looks for the file
``<appname>/sql/<modelname>.sql``, where ``<appname>`` is the given appname and
@ -269,11 +363,23 @@ command.
Each of the SQL files, if given, is expected to contain valid SQL. The SQL
files are piped directly into the database after all of the models'
table-creation statements have been executed. Use this SQL hook to populate
tables with any necessary initial records, SQL functions or test data.
table-creation statements have been executed. Use this SQL hook to make any
table modifications, or insert any SQL functions into the database.
Note that the order in which the SQL files are processed is undefined.
sqlindexes [appname appname ...]
----------------------------------------
Prints the CREATE INDEX SQL statements for the given appnames.
sqlinitialdata [appname appname ...]
--------------------------------------------
**Removed in Django development version**
This method has been renamed ``sqlcustom`` in the development version of Django.
sqlreset [appname appname ...]
--------------------------------------
@ -313,6 +419,10 @@ this command to install the default apps.
If you're installing the ``django.contrib.auth`` application, ``syncdb`` will
give you the option of creating a superuser immediately.
``syncdb`` will also search for and install any fixture named ``initial_data``.
See the documentation for ``loaddata`` for details on the specification of
fixture data files.
test
----
@ -362,12 +472,37 @@ setting the Python path for you.
.. _import search path: http://diveintopython.org/getting_to_know_python/everything_is_an_object.html
--format
--------
**New in Django development version**
Example usage::
django-admin.py dumpdata --format=xml
Specifies the output format that will be used. The name provided must be the name
of a registered serializer.
--help
------
Displays a help message that includes a terse list of all available actions and
options.
--indent
--------
**New in Django development version**
Example usage::
django-admin.py dumpdata --indent=4
Specifies the number of spaces that will be used for indentation when
pretty-printing output. By default, output will *not* be pretty-printed.
Pretty-printing will only be enabled if the indent option is provided.
--noinput
---------

View File

@ -304,3 +304,14 @@ If you have access to a command shell on a Unix system, you can accomplish this
easily by using the ``touch`` command::
touch mysite.fcgi
Serving admin media files
=========================
Regardless of the server and configuration you eventually decide to use, you will
also need to give some thought to how to serve the admin media files. The
advice given in the modpython_ documentation is also applicable in the setups
detailed above.
.. _modpython: ../modpython/#serving-the-admin-files

View File

@ -417,6 +417,27 @@ Here's a simple function that might drive the above form::
form = forms.FormWrapper(manipulator, new_data, errors)
return render_to_response('contact_form.html', {'form': form})
Implementing ``flatten_data`` for custom manipulators
------------------------------------------------------
It is possible (although rarely needed) to replace the default automatically
created manipulators on a model with your own custom manipulators. If you do
this and you are intending to use those models in generic views, you should
also define a ``flatten_data`` method in any ``ChangeManipulator`` replacement.
This should act like the default ``flatten_data`` and return a dictionary
mapping field names to their values, like so::
def flatten_data(self):
obj = self.original_object
return dict(
from = obj.from,
subject = obj.subject,
...
)
In this way, your new change manipulator will act exactly like the default
version.
``FileField`` and ``ImageField`` special cases
==============================================

View File

@ -282,6 +282,17 @@ How to create language files
Once you've tagged your strings for later translation, you need to write (or
obtain) the language translations themselves. Here's how that works.
.. admonition:: Locale restrictions
Django does not support localizing your application into a locale for
which Django itself has not been translated. In this case, it will ignore
your translation files. If you were to try this and Django supported it,
you would inevitably see a mixture of translated strings (from your
application) and English strings (from Django itself). If you want to
support a locale for your application that is not already part of
Django, you'll need to make at least a minimal translation of the Django
core.
Message files
-------------

View File

@ -1216,6 +1216,10 @@ screen via ``<script src="">`` tags. This can be used to tweak a given type of
admin page in JavaScript or to provide "quick links" to fill in default values
for certain fields.
If you use relative URLs -- URLs that don't start with ``http://`` or ``/`` --
then the admin site will automatically prefix these links with
``settings.ADMIN_MEDIA_PREFIX``.
``list_display``
----------------

View File

@ -162,10 +162,13 @@ a model object and return its URL. This is a way of overriding
``get_absolute_url()`` methods on a per-installation basis. Example::
ABSOLUTE_URL_OVERRIDES = {
'blogs.Weblog': lambda o: "/blogs/%s/" % o.slug,
'news.Story': lambda o: "/stories/%s/%s/" % (o.pub_year, o.slug),
'blogs.weblog': lambda o: "/blogs/%s/" % o.slug,
'news.story': lambda o: "/stories/%s/%s/" % (o.pub_year, o.slug),
}
Note that the model name used in this setting should be all lower-case, regardless
of the case of the actual model class name.
ADMIN_FOR
---------
@ -422,6 +425,19 @@ Subject-line prefix for e-mail messages sent with ``django.core.mail.mail_admins
or ``django.core.mail.mail_managers``. You'll probably want to include the
trailing space.
FIXTURE_DIRS
-------------
**New in Django development version**
Default: ``()`` (Empty tuple)
List of locations of the fixture data files, in search order. Note that
these paths should use Unix-style forward slashes, even on Windows. See
`Testing Django Applications`_.
.. _Testing Django Applications: ../testing/
IGNORABLE_404_ENDS
------------------
@ -653,6 +669,17 @@ link). This is only used if ``CommonMiddleware`` is installed (see the
`middleware docs`_). See also ``IGNORABLE_404_STARTS``,
``IGNORABLE_404_ENDS`` and the section on `error reporting via e-mail`_
SERIALIZATION_MODULES
---------------------
Default: Not defined.
A dictionary of modules containing serializer definitions (provided as
strings), keyed by a string identifier for that serialization type. For
example, to define a YAML serializer, use::
SERIALIZATION_MODULES = { 'yaml' : 'path.to.yaml_serializer' }
SERVER_EMAIL
------------

View File

@ -198,7 +198,6 @@ used as test conditions.
.. _Twill: http://twill.idyll.org/
.. _Selenium: http://www.openqa.org/selenium/
Making requests
~~~~~~~~~~~~~~~
@ -357,7 +356,55 @@ The following is a simple unit test using the Test Client::
Fixtures
--------
Feature still to come...
A test case for a database-backed website isn't much use if there isn't any
data in the database. To make it easy to put test data into the database,
Django provides a fixtures framework.
A *Fixture* is a collection of files that contain the serialized contents of
the database. Each fixture has a unique name; however, the files that
comprise the fixture can be distributed over multiple directories, in
multiple applications.
.. note::
If you have synchronized a Django project, you have already experienced
the use of one fixture -- the ``initial_data`` fixture. Every time you
synchronize the database, Django installs the ``initial_data`` fixture.
This provides a mechanism to populate a new database with any initial
data (such as a default set of categories). Fixtures with other names
can be installed manually using ``django-admin.py loaddata``.
However, for the purposes of unit testing, each test must be able to
guarantee the contents of the database at the start of each and every
test. To do this, Django provides a TestCase baseclass that can integrate
with fixtures.
Moving from a normal unittest TestCase to a Django TestCase is easy - just
change the base class of your test, and define a list of fixtures
to be used. For example, the test case from `Writing unittests`_ would
look like::
from django.test import TestCase
from myapp.models import Animal
class AnimalTestCase(TestCase):
fixtures = ['mammals.json', 'birds']
def setUp(self):
# test definitions as before
At the start of each test case, before ``setUp()`` is run, Django will
flush the database, returning the database the state it was in directly
after ``syncdb`` was called. Then, all the named fixtures are installed.
In this example, any JSON fixture called ``mammals``, and any fixture
named ``birds`` will be installed. See the documentation on
`loading fixtures`_ for more details on defining and installing fixtures.
.. _`loading fixtures`: ../django_admin/#loaddata-fixture-fixture
This flush/load procedure is repeated for each test in the test case, so you
can be certain that the outcome of a test will not be affected by
another test, or the order of test execution.
Running tests
=============

View File

@ -147,7 +147,7 @@ complete -F _django_completion django-admin.py manage.py
# Support for multiple interpreters.
unset pythons
if command -v whereis &>/dev/null; then
python_interpreters=$(whereis -b python | cut -d " " -f 2-)
python_interpreters=$(whereis python | cut -d " " -f 2-)
for python in $python_interpreters; do
pythons="${pythons} $(basename $python)"
done

View File

@ -0,0 +1,2 @@

View File

@ -0,0 +1,18 @@
[
{
"pk": "2",
"model": "fixtures.article",
"fields": {
"headline": "Poker has no place on ESPN",
"pub_date": "2006-06-16 12:00:00"
}
},
{
"pk": "3",
"model": "fixtures.article",
"fields": {
"headline": "Time to reform copyright",
"pub_date": "2006-06-16 13:00:00"
}
}
]

View File

@ -0,0 +1,18 @@
[
{
"pk": "3",
"model": "fixtures.article",
"fields": {
"headline": "Copyright is fine the way it is",
"pub_date": "2006-06-16 14:00:00"
}
},
{
"pk": "4",
"model": "fixtures.article",
"fields": {
"headline": "Django conquers world!",
"pub_date": "2006-06-16 15:00:00"
}
}
]

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
<object pk="2" model="fixtures.article">
<field type="CharField" name="headline">Poker on TV is great!</field>
<field type="DateTimeField" name="pub_date">2006-06-16 11:00:00</field>
</object>
<object pk="5" model="fixtures.article">
<field type="CharField" name="headline">XML identified as leading cause of cancer</field>
<field type="DateTimeField" name="pub_date">2006-06-16 16:00:00</field>
</object>
</django-objects>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
<object pk="2" model="fixtures.article">
<field type="CharField" name="headline">Poker on TV is great!</field>
<field type="DateTimeField" name="pub_date">2006-06-16 11:00:00</field>
</object>
<object pk="5" model="fixtures.article">
<field type="CharField" name="headline">XML identified as leading cause of cancer</field>
<field type="DateTimeField" name="pub_date">2006-06-16 16:00:00</field>
</object>
</django-objects>

View File

@ -0,0 +1,10 @@
[
{
"pk": "1",
"model": "fixtures.article",
"fields": {
"headline": "Python program becomes self aware",
"pub_date": "2006-06-16 11:00:00"
}
}
]

View File

@ -0,0 +1,88 @@
"""
39. Fixtures.
Fixtures are a way of loading data into the database in bulk. Fixure data
can be stored in any serializable format (including JSON and XML). Fixtures
are identified by name, and are stored in either a directory named 'fixtures'
in the application directory, on in one of the directories named in the
FIXTURE_DIRS setting.
"""
from django.db import models
class Article(models.Model):
headline = models.CharField(maxlength=100, default='Default headline')
pub_date = models.DateTimeField()
def __str__(self):
return self.headline
class Meta:
ordering = ('-pub_date', 'headline')
__test__ = {'API_TESTS': """
>>> from django.core import management
>>> from django.db.models import get_app
# Reset the database representation of this app.
# This will return the database to a clean initial state.
>>> management.flush(verbosity=0, interactive=False)
# Syncdb introduces 1 initial data object from initial_data.json.
>>> Article.objects.all()
[<Article: Python program becomes self aware>]
# Load fixture 1. Single JSON file, with two objects.
>>> management.load_data(['fixture1.json'], verbosity=0)
>>> Article.objects.all()
[<Article: Time to reform copyright>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]
# Load fixture 2. JSON file imported by default. Overwrites some existing objects
>>> management.load_data(['fixture2.json'], verbosity=0)
>>> Article.objects.all()
[<Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]
# Load fixture 3, XML format.
>>> management.load_data(['fixture3.xml'], verbosity=0)
>>> Article.objects.all()
[<Article: XML identified as leading cause of cancer>, <Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker on TV is great!>, <Article: Python program becomes self aware>]
# Load a fixture that doesn't exist
>>> management.load_data(['unknown.json'], verbosity=0)
# object list is unaffected
>>> Article.objects.all()
[<Article: XML identified as leading cause of cancer>, <Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker on TV is great!>, <Article: Python program becomes self aware>]
# Reset the database representation of this app. This will delete all data.
>>> management.flush(verbosity=0, interactive=False)
>>> Article.objects.all()
[<Article: Python program becomes self aware>]
# Load fixture 1 again, using format discovery
>>> management.load_data(['fixture1'], verbosity=0)
>>> Article.objects.all()
[<Article: Time to reform copyright>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]
# Try to load fixture 2 using format discovery; this will fail
# because there are two fixture2's in the fixtures directory
>>> management.load_data(['fixture2'], verbosity=0) # doctest: +ELLIPSIS
Multiple fixtures named 'fixture2' in '...fixtures'. Aborting.
>>> Article.objects.all()
[<Article: Time to reform copyright>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]
# Dump the current contents of the database as a JSON fixture
>>> print management.dump_data(['fixtures'], format='json')
[{"pk": "3", "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": "2", "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": "1", "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}]
"""}
from django.test import TestCase
class SampleTestCase(TestCase):
fixtures = ['fixture1.json', 'fixture2.json']
def testClassFixtures(self):
"Check that test case has installed 4 fixture objects"
self.assertEqual(Article.objects.count(), 4)
self.assertEquals(str(Article.objects.all()), "[<Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]")

View File

@ -0,0 +1,20 @@
[
{
"pk": "1",
"model": "auth.user",
"fields": {
"username": "testclient",
"first_name": "Test",
"last_name": "Client",
"is_active": true,
"is_superuser": false,
"is_staff": false,
"last_login": "2006-12-17 07:03:31",
"groups": [],
"user_permissions": [],
"password": "sha1$6efc0$f93efe9fd7542f25a7be94871ea45aa95de57161",
"email": "testclient@example.com",
"date_joined": "2006-12-17 07:03:31"
}
}
]

View File

@ -1,10 +0,0 @@
from django.dispatch import dispatcher
from django.db.models import signals
import models as test_client_app
from django.contrib.auth.models import User
def setup_test(app, created_models, verbosity):
# Create a user account for the login-based tests
User.objects.create_user('testclient','testclient@example.com', 'password')
dispatcher.connect(setup_test, sender=test_client_app, signal=signals.post_syncdb)

View File

@ -19,10 +19,11 @@ testing against the contexts and templates produced by a view,
rather than the HTML rendered to the end-user.
"""
from django.test.client import Client
import unittest
from django.test import Client, TestCase
class ClientTest(unittest.TestCase):
class ClientTest(TestCase):
fixtures = ['testdata.json']
def setUp(self):
"Set up test environment"
self.client = Client()

View File

@ -31,4 +31,35 @@
'nonexistent'
>>> d.setlist('lastname', ['Holovaty', 'Willison'])
"""
### SortedDict #################################################################
>>> d = SortedDict()
>>> d['one'] = 'one'
>>> d['two'] = 'two'
>>> d['three'] = 'three'
>>> d['one']
'one'
>>> d['two']
'two'
>>> d['three']
'three'
>>> d.keys()
['one', 'two', 'three']
>>> d.values()
['one', 'two', 'three']
>>> d['one'] = 'not one'
>>> d['one']
'not one'
>>> d.keys() == d.copy().keys()
True
### DotExpandedDict ############################################################
>>> d = DotExpandedDict({'person.1.firstname': ['Simon'], 'person.1.lastname': ['Willison'], 'person.2.firstname': ['Adrian'], 'person.2.lastname': ['Holovaty']})
>>> d['person']['1']['lastname']
['Willison']
>>> d['person']['2']['lastname']
['Holovaty']
>>> d['person']['2']['firstname']
['Adrian']
"""

View File

@ -3476,6 +3476,7 @@ as its choices.
<option value="ME">Maine</option>
<option value="MH">Marshall Islands</option>
<option value="MD">Maryland</option>
<option value="MA">Massachusetts</option>
<option value="MI">Michigan</option>
<option value="MN">Minnesota</option>
<option value="MS">Mississippi</option>

View File

@ -1,13 +1,34 @@
from django.db import models
# If ticket #1578 ever slips back in, these models will not be able to be
# created (the field names being lower-cased versions of their opposite
# classes is important here).
class First(models.Model):
second = models.IntegerField()
class Second(models.Model):
first = models.ForeignKey(First, related_name = 'the_first')
# If ticket #1578 ever slips back in, these models will not be able to be
# created (the field names being lower-cased versions of their opposite
# classes is important here).
# Protect against repetition of #1839, #2415 and #2536.
class Third(models.Model):
name = models.CharField(maxlength=20)
third = models.ForeignKey('self', null=True, related_name='child_set')
__test__ = {'API_TESTS':""}
class Parent(models.Model):
name = models.CharField(maxlength=20)
bestchild = models.ForeignKey('Child', null=True, related_name='favored_by')
class Child(models.Model):
name = models.CharField(maxlength=20)
parent = models.ForeignKey(Parent)
__test__ = {'API_TESTS':"""
>>> Third.AddManipulator().save(dict(id='3', name='An example', another=None))
<Third: Third object>
>>> parent = Parent(name = 'fred')
>>> parent.save()
>>> Child.AddManipulator().save(dict(name='bam-bam', parent=parent.id))
<Child: Child object>
"""}

View File

@ -0,0 +1,170 @@
"""
A test spanning all the capabilities of all the serializers.
This class sets up a model for each model field type
(except for image types, because of the PIL dependency).
"""
from django.db import models
# The following classes are for testing basic data
# marshalling, including NULL values.
class BooleanData(models.Model):
data = models.BooleanField(null=True)
class CharData(models.Model):
data = models.CharField(maxlength=30, null=True)
class DateData(models.Model):
data = models.DateField(null=True)
class DateTimeData(models.Model):
data = models.DateTimeField(null=True)
class EmailData(models.Model):
data = models.EmailField(null=True)
class FileData(models.Model):
data = models.FileField(null=True, upload_to='/foo/bar')
class FilePathData(models.Model):
data = models.FilePathField(null=True)
class FloatData(models.Model):
data = models.FloatField(null=True, decimal_places=3, max_digits=5)
class IntegerData(models.Model):
data = models.IntegerField(null=True)
# class ImageData(models.Model):
# data = models.ImageField(null=True)
class IPAddressData(models.Model):
data = models.IPAddressField(null=True)
class NullBooleanData(models.Model):
data = models.NullBooleanField(null=True)
class PhoneData(models.Model):
data = models.PhoneNumberField(null=True)
class PositiveIntegerData(models.Model):
data = models.PositiveIntegerField(null=True)
class PositiveSmallIntegerData(models.Model):
data = models.PositiveSmallIntegerField(null=True)
class SlugData(models.Model):
data = models.SlugField(null=True)
class SmallData(models.Model):
data = models.SmallIntegerField(null=True)
class TextData(models.Model):
data = models.TextField(null=True)
class TimeData(models.Model):
data = models.TimeField(null=True)
class USStateData(models.Model):
data = models.USStateField(null=True)
class XMLData(models.Model):
data = models.XMLField(null=True)
# The following test classes are all for validation
# of related objects; in particular, forward, backward,
# and self references.
class Anchor(models.Model):
"""This is a model that can be used as
something for other models to point at"""
data = models.CharField(maxlength=30)
class FKData(models.Model):
data = models.ForeignKey(Anchor, null=True)
class M2MData(models.Model):
data = models.ManyToManyField(Anchor, null=True)
class O2OData(models.Model):
data = models.OneToOneField(Anchor, null=True)
class FKSelfData(models.Model):
data = models.ForeignKey('self', null=True)
class M2MSelfData(models.Model):
data = models.ManyToManyField('self', null=True, symmetrical=False)
# The following test classes are for validating the
# deserialization of objects that use a user-defined
# field as the primary key.
# Some of these data types have been commented out
# because they can't be used as a primary key on one
# or all database backends.
class BooleanPKData(models.Model):
data = models.BooleanField(primary_key=True)
class CharPKData(models.Model):
data = models.CharField(maxlength=30, primary_key=True)
# class DatePKData(models.Model):
# data = models.DateField(primary_key=True)
# class DateTimePKData(models.Model):
# data = models.DateTimeField(primary_key=True)
class EmailPKData(models.Model):
data = models.EmailField(primary_key=True)
class FilePKData(models.Model):
data = models.FileField(primary_key=True, upload_to='/foo/bar')
class FilePathPKData(models.Model):
data = models.FilePathField(primary_key=True)
class FloatPKData(models.Model):
data = models.FloatField(primary_key=True, decimal_places=3, max_digits=5)
class IntegerPKData(models.Model):
data = models.IntegerField(primary_key=True)
# class ImagePKData(models.Model):
# data = models.ImageField(primary_key=True)
class IPAddressPKData(models.Model):
data = models.IPAddressField(primary_key=True)
class NullBooleanPKData(models.Model):
data = models.NullBooleanField(primary_key=True)
class PhonePKData(models.Model):
data = models.PhoneNumberField(primary_key=True)
class PositiveIntegerPKData(models.Model):
data = models.PositiveIntegerField(primary_key=True)
class PositiveSmallIntegerPKData(models.Model):
data = models.PositiveSmallIntegerField(primary_key=True)
class SlugPKData(models.Model):
data = models.SlugField(primary_key=True)
class SmallPKData(models.Model):
data = models.SmallIntegerField(primary_key=True)
# class TextPKData(models.Model):
# data = models.TextField(primary_key=True)
# class TimePKData(models.Model):
# data = models.TimeField(primary_key=True)
class USStatePKData(models.Model):
data = models.USStateField(primary_key=True)
# class XMLPKData(models.Model):
# data = models.XMLField(primary_key=True)

View File

@ -0,0 +1,243 @@
"""
A test spanning all the capabilities of all the serializers.
This class defines sample data and a dynamically generated
test case that is capable of testing the capabilities of
the serializers. This includes all valid data values, plus
forward, backwards and self references.
"""
import unittest, datetime
from django.utils.functional import curry
from django.core import serializers
from django.db import transaction
from django.core import management
from models import *
# A set of functions that can be used to recreate
# test data objects of various kinds
def data_create(pk, klass, data):
instance = klass(id=pk)
instance.data = data
instance.save()
return instance
def fk_create(pk, klass, data):
instance = klass(id=pk)
setattr(instance, 'data_id', data)
instance.save()
return instance
def m2m_create(pk, klass, data):
instance = klass(id=pk)
instance.save()
instance.data = data
return instance
def o2o_create(pk, klass, data):
instance = klass()
instance.data_id = data
instance.save()
return instance
def pk_create(pk, klass, data):
instance = klass()
instance.data = data
instance.save()
return instance
# A set of functions that can be used to compare
# test data objects of various kinds
def data_compare(testcase, pk, klass, data):
instance = klass.objects.get(id=pk)
testcase.assertEqual(data, instance.data,
"Objects with PK=%d not equal; expected '%s' (%s), got '%s' (%s)" % (pk,data, type(data), instance.data, type(instance.data)))
def fk_compare(testcase, pk, klass, data):
instance = klass.objects.get(id=pk)
testcase.assertEqual(data, instance.data_id)
def m2m_compare(testcase, pk, klass, data):
instance = klass.objects.get(id=pk)
testcase.assertEqual(data, [obj.id for obj in instance.data.all()])
def o2o_compare(testcase, pk, klass, data):
instance = klass.objects.get(data=data)
testcase.assertEqual(data, instance.data_id)
def pk_compare(testcase, pk, klass, data):
instance = klass.objects.get(data=data)
testcase.assertEqual(data, instance.data)
# Define some data types. Each data type is
# actually a pair of functions; one to create
# and one to compare objects of that type
data_obj = (data_create, data_compare)
fk_obj = (fk_create, fk_compare)
m2m_obj = (m2m_create, m2m_compare)
o2o_obj = (o2o_create, o2o_compare)
pk_obj = (pk_create, pk_compare)
test_data = [
# Format: (data type, PK value, Model Class, data)
(data_obj, 1, BooleanData, True),
(data_obj, 2, BooleanData, False),
(data_obj, 10, CharData, "Test Char Data"),
(data_obj, 11, CharData, ""),
(data_obj, 12, CharData, "None"),
(data_obj, 13, CharData, "null"),
(data_obj, 14, CharData, "NULL"),
(data_obj, 15, CharData, None),
(data_obj, 20, DateData, datetime.date(2006,6,16)),
(data_obj, 21, DateData, None),
(data_obj, 30, DateTimeData, datetime.datetime(2006,6,16,10,42,37)),
(data_obj, 31, DateTimeData, None),
(data_obj, 40, EmailData, "hovercraft@example.com"),
(data_obj, 41, EmailData, None),
(data_obj, 50, FileData, 'file:///foo/bar/whiz.txt'),
(data_obj, 51, FileData, None),
(data_obj, 60, FilePathData, "/foo/bar/whiz.txt"),
(data_obj, 61, FilePathData, None),
(data_obj, 70, FloatData, 12.345),
(data_obj, 71, FloatData, -12.345),
(data_obj, 72, FloatData, 0.0),
(data_obj, 73, FloatData, None),
(data_obj, 80, IntegerData, 123456789),
(data_obj, 81, IntegerData, -123456789),
(data_obj, 82, IntegerData, 0),
(data_obj, 83, IntegerData, None),
#(XX, ImageData
(data_obj, 90, IPAddressData, "127.0.0.1"),
(data_obj, 91, IPAddressData, None),
(data_obj, 100, NullBooleanData, True),
(data_obj, 101, NullBooleanData, False),
(data_obj, 102, NullBooleanData, None),
(data_obj, 110, PhoneData, "212-634-5789"),
(data_obj, 111, PhoneData, None),
(data_obj, 120, PositiveIntegerData, 123456789),
(data_obj, 121, PositiveIntegerData, None),
(data_obj, 130, PositiveSmallIntegerData, 12),
(data_obj, 131, PositiveSmallIntegerData, None),
(data_obj, 140, SlugData, "this-is-a-slug"),
(data_obj, 141, SlugData, None),
(data_obj, 150, SmallData, 12),
(data_obj, 151, SmallData, -12),
(data_obj, 152, SmallData, 0),
(data_obj, 153, SmallData, None),
(data_obj, 160, TextData, """This is a long piece of text.
It contains line breaks.
Several of them.
The end."""),
(data_obj, 161, TextData, ""),
(data_obj, 162, TextData, None),
(data_obj, 170, TimeData, datetime.time(10,42,37)),
(data_obj, 171, TimeData, None),
(data_obj, 180, USStateData, "MA"),
(data_obj, 181, USStateData, None),
(data_obj, 190, XMLData, "<foo></foo>"),
(data_obj, 191, XMLData, None),
(data_obj, 300, Anchor, "Anchor 1"),
(data_obj, 301, Anchor, "Anchor 2"),
(fk_obj, 400, FKData, 300), # Post reference
(fk_obj, 401, FKData, 500), # Pre reference
(fk_obj, 402, FKData, None), # Empty reference
(m2m_obj, 410, M2MData, []), # Empty set
(m2m_obj, 411, M2MData, [300,301]), # Post reference
(m2m_obj, 412, M2MData, [500,501]), # Pre reference
(m2m_obj, 413, M2MData, [300,301,500,501]), # Pre and Post reference
(o2o_obj, None, O2OData, 300), # Post reference
(o2o_obj, None, O2OData, 500), # Pre reference
(fk_obj, 430, FKSelfData, 431), # Pre reference
(fk_obj, 431, FKSelfData, 430), # Post reference
(fk_obj, 432, FKSelfData, None), # Empty reference
(m2m_obj, 440, M2MSelfData, []),
(m2m_obj, 441, M2MSelfData, []),
(m2m_obj, 442, M2MSelfData, [440, 441]),
(m2m_obj, 443, M2MSelfData, [445, 446]),
(m2m_obj, 444, M2MSelfData, [440, 441, 445, 446]),
(m2m_obj, 445, M2MSelfData, []),
(m2m_obj, 446, M2MSelfData, []),
(data_obj, 500, Anchor, "Anchor 3"),
(data_obj, 501, Anchor, "Anchor 4"),
(pk_obj, 601, BooleanPKData, True),
(pk_obj, 602, BooleanPKData, False),
(pk_obj, 610, CharPKData, "Test Char PKData"),
# (pk_obj, 620, DatePKData, datetime.date(2006,6,16)),
# (pk_obj, 630, DateTimePKData, datetime.datetime(2006,6,16,10,42,37)),
(pk_obj, 640, EmailPKData, "hovercraft@example.com"),
(pk_obj, 650, FilePKData, 'file:///foo/bar/whiz.txt'),
(pk_obj, 660, FilePathPKData, "/foo/bar/whiz.txt"),
(pk_obj, 670, FloatPKData, 12.345),
(pk_obj, 671, FloatPKData, -12.345),
(pk_obj, 672, FloatPKData, 0.0),
(pk_obj, 680, IntegerPKData, 123456789),
(pk_obj, 681, IntegerPKData, -123456789),
(pk_obj, 682, IntegerPKData, 0),
# (XX, ImagePKData
(pk_obj, 690, IPAddressPKData, "127.0.0.1"),
(pk_obj, 700, NullBooleanPKData, True),
(pk_obj, 701, NullBooleanPKData, False),
(pk_obj, 710, PhonePKData, "212-634-5789"),
(pk_obj, 720, PositiveIntegerPKData, 123456789),
(pk_obj, 730, PositiveSmallIntegerPKData, 12),
(pk_obj, 740, SlugPKData, "this-is-a-slug"),
(pk_obj, 750, SmallPKData, 12),
(pk_obj, 751, SmallPKData, -12),
(pk_obj, 752, SmallPKData, 0),
# (pk_obj, 760, TextPKData, """This is a long piece of text.
# It contains line breaks.
# Several of them.
# The end."""),
# (pk_obj, 770, TimePKData, datetime.time(10,42,37)),
(pk_obj, 780, USStatePKData, "MA"),
# (pk_obj, 790, XMLPKData, "<foo></foo>"),
]
# Dynamically create serializer tests to ensure that all
# registered serializers are automatically tested.
class SerializerTests(unittest.TestCase):
pass
def serializerTest(format, self):
# Clear the database first
management.flush(verbosity=0, interactive=False)
# Create all the objects defined in the test data
objects = []
transaction.enter_transaction_management()
transaction.managed(True)
for (func, pk, klass, datum) in test_data:
objects.append(func[0](pk, klass, datum))
transaction.commit()
transaction.leave_transaction_management()
# Serialize the test database
serialized_data = serializers.serialize(format, objects, indent=2)
# Flush the database and recreate from the serialized data
management.flush(verbosity=0, interactive=False)
transaction.enter_transaction_management()
transaction.managed(True)
for obj in serializers.deserialize(format, serialized_data):
obj.save()
transaction.commit()
transaction.leave_transaction_management()
# Assert that the deserialized data is the same
# as the original source
for (func, pk, klass, datum) in test_data:
func[1](self, pk, klass, datum)
for format in serializers.get_serializer_formats():
setattr(SerializerTests, 'test_'+format+'_serializer', curry(serializerTest, format))

View File

@ -401,6 +401,20 @@ class Templates(unittest.TestCase):
'ifequal-split09': (r"{% ifequal a 'slash\man' %}yes{% else %}no{% endifequal %}", {'a': r"slash\man"}, "yes"),
'ifequal-split10': (r"{% ifequal a 'slash\man' %}yes{% else %}no{% endifequal %}", {'a': r"slashman"}, "no"),
# NUMERIC RESOLUTION
'ifequal-numeric01': ('{% ifequal x 5 %}yes{% endifequal %}', {'x': '5'}, ''),
'ifequal-numeric02': ('{% ifequal x 5 %}yes{% endifequal %}', {'x': 5}, 'yes'),
'ifequal-numeric03': ('{% ifequal x 5.2 %}yes{% endifequal %}', {'x': 5}, ''),
'ifequal-numeric04': ('{% ifequal x 5.2 %}yes{% endifequal %}', {'x': 5.2}, 'yes'),
'ifequal-numeric05': ('{% ifequal x 0.2 %}yes{% endifequal %}', {'x': .2}, 'yes'),
'ifequal-numeric06': ('{% ifequal x .2 %}yes{% endifequal %}', {'x': .2}, 'yes'),
'ifequal-numeric07': ('{% ifequal x 2. %}yes{% endifequal %}', {'x': 2}, ''),
'ifequal-numeric08': ('{% ifequal x "5" %}yes{% endifequal %}', {'x': 5}, ''),
'ifequal-numeric09': ('{% ifequal x "5" %}yes{% endifequal %}', {'x': '5'}, 'yes'),
'ifequal-numeric10': ('{% ifequal x -5 %}yes{% endifequal %}', {'x': -5}, 'yes'),
'ifequal-numeric11': ('{% ifequal x -5.2 %}yes{% endifequal %}', {'x': -5.2}, 'yes'),
'ifequal-numeric12': ('{% ifequal x +5 %}yes{% endifequal %}', {'x': 5}, 'yes'),
### IFNOTEQUAL TAG ########################################################
'ifnotequal01': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 2}, "yes"),
'ifnotequal02': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 1}, ""),

View File

@ -6,7 +6,7 @@ urlpatterns = patterns('',
# Always provide the auth system login and logout views
(r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}),
(r'^accounts/logout/$', 'django.contrib.auth.views.login'),
(r'^accounts/logout/$', 'django.contrib.auth.views.logout'),
# test urlconf for {% url %} template tag
(r'^url_tag/', include('regressiontests.templates.urls')),