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:
parent
b0bbdc744d
commit
5088488057
7
AUTHORS
7
AUTHORS
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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 = ()
|
||||
|
Binary file not shown.
@ -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
|
||||
|
Binary file not shown.
@ -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"
|
||||
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -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"
|
||||
|
||||
|
BIN
django/conf/locale/te/LC_MESSAGES/django.mo
Normal file
BIN
django/conf/locale/te/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
2106
django/conf/locale/te/LC_MESSAGES/django.po
Normal file
2106
django/conf/locale/te/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
BIN
django/conf/locale/te/LC_MESSAGES/djangojs.mo
Normal file
BIN
django/conf/locale/te/LC_MESSAGES/djangojs.mo
Normal file
Binary file not shown.
110
django/conf/locale/te/LC_MESSAGES/djangojs.po
Normal file
110
django/conf/locale/te/LC_MESSAGES/djangojs.po
Normal 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 "రేపు"
|
||||
|
@ -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'
|
||||
|
@ -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
|
||||
|
@ -20,6 +20,16 @@ class ContentTypeManager(models.Manager):
|
||||
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)
|
||||
app_label = models.CharField(maxlength=100)
|
||||
|
@ -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)
|
||||
|
@ -32,6 +32,7 @@ STATE_CHOICES = (
|
||||
('ME', 'Maine'),
|
||||
('MH', 'Marshall Islands'),
|
||||
('MD', 'Maryland'),
|
||||
('MA', 'Massachusetts'),
|
||||
('MI', 'Michigan'),
|
||||
('MN', 'Minnesota'),
|
||||
('MS', 'Mississippi'),
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
@ -41,6 +48,11 @@ def get_serializer(format):
|
||||
_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:
|
||||
_load_serializers()
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
36
django/core/serializers/pyyaml.py
Normal file
36
django/core/serializers/pyyaml.py
Normal 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
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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:
|
||||
|
@ -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',
|
||||
|
@ -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 = {}
|
||||
|
@ -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',
|
||||
|
@ -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)
|
||||
|
@ -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',
|
||||
|
@ -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.
|
||||
|
@ -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',
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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()
|
||||
|
@ -91,6 +91,8 @@ UNKNOWN_SOURCE="<unknown source>"
|
||||
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:
|
||||
|
@ -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)
|
||||
|
@ -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 %}
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
"""
|
||||
Django Unit Test and Doctest framework.
|
||||
"""
|
||||
|
||||
from django.test.client import Client
|
||||
from django.test.testcases import TestCase
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
===============
|
||||
|
162
docs/databases.txt
Normal file
162
docs/databases.txt
Normal 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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
---------
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
==============================================
|
||||
|
||||
|
@ -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
|
||||
-------------
|
||||
|
||||
|
@ -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``
|
||||
----------------
|
||||
|
||||
|
@ -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
|
||||
------------
|
||||
|
||||
|
@ -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
|
||||
=============
|
||||
|
@ -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
|
||||
|
2
tests/modeltests/fixtures/__init__.py
Normal file
2
tests/modeltests/fixtures/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
|
18
tests/modeltests/fixtures/fixtures/fixture1.json
Normal file
18
tests/modeltests/fixtures/fixtures/fixture1.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
18
tests/modeltests/fixtures/fixtures/fixture2.json
Normal file
18
tests/modeltests/fixtures/fixtures/fixture2.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
11
tests/modeltests/fixtures/fixtures/fixture2.xml
Normal file
11
tests/modeltests/fixtures/fixtures/fixture2.xml
Normal 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>
|
11
tests/modeltests/fixtures/fixtures/fixture3.xml
Normal file
11
tests/modeltests/fixtures/fixtures/fixture3.xml
Normal 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>
|
10
tests/modeltests/fixtures/fixtures/initial_data.json
Normal file
10
tests/modeltests/fixtures/fixtures/initial_data.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
88
tests/modeltests/fixtures/models.py
Normal file
88
tests/modeltests/fixtures/models.py
Normal 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>]")
|
20
tests/modeltests/test_client/fixtures/testdata.json
Normal file
20
tests/modeltests/test_client/fixtures/testdata.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
@ -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)
|
@ -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(TestCase):
|
||||
fixtures = ['testdata.json']
|
||||
|
||||
class ClientTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
"Set up test environment"
|
||||
self.client = Client()
|
||||
|
@ -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']
|
||||
"""
|
@ -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>
|
||||
|
@ -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>
|
||||
"""}
|
||||
|
170
tests/regressiontests/serializers_regress/models.py
Normal file
170
tests/regressiontests/serializers_regress/models.py
Normal 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)
|
||||
|
243
tests/regressiontests/serializers_regress/tests.py
Normal file
243
tests/regressiontests/serializers_regress/tests.py
Normal 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))
|
@ -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}, ""),
|
||||
|
@ -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')),
|
||||
|
Loading…
x
Reference in New Issue
Block a user