mirror of
https://github.com/django/django.git
synced 2025-07-04 09:49:12 +00:00
newforms-admin: Merged from trunk up to [5916]
git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@5918 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
0f92ac52cb
commit
fcec755f01
11
AUTHORS
11
AUTHORS
@ -67,9 +67,11 @@ answer newbie questions, and generally made Django that much better:
|
||||
Andrew Brehaut <http://brehaut.net/blog>
|
||||
brut.alll@gmail.com
|
||||
Jonathan Buchanan <jonathan.buchanan@gmail.com>
|
||||
Trevor Caira <trevor@caira.com>
|
||||
Ricardo Javier Cárdenes Medina <ricardo.cardenes@gmail.com>
|
||||
Antonio Cavedoni <http://cavedoni.com/>
|
||||
C8E
|
||||
cedric@terramater.net
|
||||
Chris Chamberlin <dja@cdc.msbx.net>
|
||||
Amit Chakradeo <http://amit.chakradeo.net/>
|
||||
ChaosKCW
|
||||
@ -77,6 +79,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Bryan Chow <bryan at verdjn dot com>
|
||||
Michal Chruszcz <troll@pld-linux.org>
|
||||
Ian Clelland <clelland@gmail.com>
|
||||
colin@owlfish.com
|
||||
crankycoder@gmail.com
|
||||
Pete Crosier <pete.crosier@gmail.com>
|
||||
Matt Croydon <http://www.postneo.com/>
|
||||
@ -99,6 +102,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
dusk@woofle.net
|
||||
Andy Dustman <farcepest@gmail.com>
|
||||
Clint Ecker
|
||||
eibaan@gmail.com
|
||||
enlight
|
||||
Enrico <rico.bl@gmail.com>
|
||||
A. Murat Eren <meren@pardus.org.tr>
|
||||
@ -119,16 +123,19 @@ answer newbie questions, and generally made Django that much better:
|
||||
martin.glueck@gmail.com
|
||||
GomoX <gomo@datafull.com>
|
||||
Mario Gonzalez <gonzalemario@gmail.com>
|
||||
pradeep.gowda@gmail.com
|
||||
Simon Greenhill <dev@simon.net.nz>
|
||||
Owen Griffiths
|
||||
Espen Grindhaug <http://grindhaug.org/>
|
||||
Thomas Güttler <hv@tbz-pariv.de>
|
||||
dAniel hAhler
|
||||
Brian Harring <ferringb@gmail.com>
|
||||
Brant Harris
|
||||
Hawkeye
|
||||
Joe Heck <http://www.rhonabwy.com/wp/>
|
||||
Joel Heenan <joelh-django@planetjoel.com>
|
||||
hipertracker@gmail.com
|
||||
Brett Hoerner <bretthoerner@bretthoerner.com>
|
||||
Ian Holsman <http://feh.holsman.net/>
|
||||
Kieran Holland <http://www.kieranholland.com>
|
||||
Sung-Jin Hong <serialx.net@gmail.com>
|
||||
@ -138,6 +145,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Hyun Mi Ae
|
||||
Tom Insam
|
||||
Baurzhan Ismagulov <ibr@radix50.net>
|
||||
james_027@yahoo.com
|
||||
jcrasta@gmail.com
|
||||
Zak Johnson <zakj@nox.cx>
|
||||
Michael Josephson <http://www.sdjournal.com/>
|
||||
@ -192,6 +200,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
mmarshall
|
||||
Andreas Mock <andreas.mock@web.de>
|
||||
Reza Mohammadi <reza@zeerak.ir>
|
||||
Aljosa Mohorovic <aljosa.mohorovic@gmail.com>
|
||||
Eric Moritz <http://eric.themoritzfamily.com/>
|
||||
mrmachine <real.human@mrmachine.net>
|
||||
Robin Munn <http://www.geekforgod.com/>
|
||||
@ -254,6 +263,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
thebjorn <bp@datakortet.no>
|
||||
Zach Thompson <zthompson47@gmail.com>
|
||||
tibimicu@gmax.net
|
||||
tobias@neuyork.de
|
||||
Tom Tobin
|
||||
Joe Topjian <http://joe.terrarum.net/geek/code/python/django/>
|
||||
torne-django@wolfpuppy.org.uk
|
||||
@ -274,6 +284,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
charly.wilhelm@gmail.com
|
||||
Rachel Willmer <http://www.willmer.com/kb/>
|
||||
Gary Wilson <gary.wilson@gmail.com>
|
||||
Jakub Wiśniowski <restless.being@gmail.com>
|
||||
wojtek
|
||||
ye7cakf02@sneakemail.com
|
||||
ymasuda@ethercube.com
|
||||
|
@ -84,7 +84,7 @@ def make_messages():
|
||||
thefile = '%s.py' % file
|
||||
cmd = 'xgettext %s -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --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')
|
||||
(stdin, stdout, stderr) = os.popen3(cmd, 't')
|
||||
msgs = stdout.read()
|
||||
errors = stderr.read()
|
||||
if errors:
|
||||
@ -101,12 +101,13 @@ def make_messages():
|
||||
thefile = file
|
||||
if file.endswith('.html'):
|
||||
src = open(os.path.join(dirpath, file), "rb").read()
|
||||
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))
|
||||
open(os.path.join(dirpath, thefile), "wb").write(templatize(src))
|
||||
if verbose:
|
||||
sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
|
||||
cmd = 'xgettext -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
|
||||
domain, os.path.join(dirpath, thefile))
|
||||
(stdin, stdout, stderr) = os.popen3(cmd, 'b')
|
||||
(stdin, stdout, stderr) = os.popen3(cmd, 't')
|
||||
msgs = stdout.read()
|
||||
errors = stderr.read()
|
||||
if errors:
|
||||
|
@ -53,6 +53,7 @@ LANGUAGES = (
|
||||
('gl', gettext_noop('Galician')),
|
||||
('hu', gettext_noop('Hungarian')),
|
||||
('he', gettext_noop('Hebrew')),
|
||||
('hr', gettext_noop('Croatian')),
|
||||
('is', gettext_noop('Icelandic')),
|
||||
('it', gettext_noop('Italian')),
|
||||
('ja', gettext_noop('Japanese')),
|
||||
@ -80,7 +81,7 @@ LANGUAGES = (
|
||||
)
|
||||
|
||||
# Languages using BiDi (right-to-left) layout
|
||||
LANGUAGES_BIDI = ("he", "ar")
|
||||
LANGUAGES_BIDI = ("he", "ar", "fa")
|
||||
|
||||
# If you set this to False, Django will make some optimizations so as not
|
||||
# to load the internationalization machinery.
|
||||
|
Binary file not shown.
@ -3,10 +3,10 @@
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Django 1.0\n"
|
||||
""
|
||||
msgstr "Project-Id-Version: Django 1.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-04-09 22:42+0200\n"
|
||||
"POT-Creation-Date: 2007-07-28 12:33+0200\n"
|
||||
"PO-Revision-Date: 2007-02-05 03:19+0100\n"
|
||||
"Last-Translator: Jannis Leidel <jl@websushi.org>\n"
|
||||
"Language-Team: \n"
|
||||
@ -19,591 +19,590 @@ msgstr ""
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
"X-Generator: KBabel 1.11.4\n"
|
||||
|
||||
#: conf/global_settings.py:39
|
||||
#:conf/global_settings.py:38
|
||||
msgid "Arabic"
|
||||
msgstr "Arabisch"
|
||||
|
||||
#: conf/global_settings.py:40
|
||||
#:conf/global_settings.py:39
|
||||
msgid "Bengali"
|
||||
msgstr "Bengali"
|
||||
|
||||
#: conf/global_settings.py:41
|
||||
#:conf/global_settings.py:40
|
||||
msgid "Bulgarian"
|
||||
msgstr "Bulgarisch"
|
||||
|
||||
#:conf/global_settings.py:41
|
||||
msgid "Catalan"
|
||||
msgstr "Katalanisch"
|
||||
|
||||
#: conf/global_settings.py:42
|
||||
#:conf/global_settings.py:42
|
||||
msgid "Czech"
|
||||
msgstr "Tschechisch"
|
||||
|
||||
#: conf/global_settings.py:43
|
||||
#:conf/global_settings.py:43
|
||||
msgid "Welsh"
|
||||
msgstr "Walisisch"
|
||||
|
||||
#: conf/global_settings.py:44
|
||||
#:conf/global_settings.py:44
|
||||
msgid "Danish"
|
||||
msgstr "Dänisch"
|
||||
|
||||
#: conf/global_settings.py:45
|
||||
#:conf/global_settings.py:45
|
||||
msgid "German"
|
||||
msgstr "Deutsch"
|
||||
|
||||
#: conf/global_settings.py:46
|
||||
#:conf/global_settings.py:46
|
||||
msgid "Greek"
|
||||
msgstr "Griechisch"
|
||||
|
||||
#: conf/global_settings.py:47
|
||||
#:conf/global_settings.py:47
|
||||
msgid "English"
|
||||
msgstr "Englisch"
|
||||
|
||||
#: conf/global_settings.py:48
|
||||
#:conf/global_settings.py:48
|
||||
msgid "Spanish"
|
||||
msgstr "Spanisch"
|
||||
|
||||
#: conf/global_settings.py:49
|
||||
#:conf/global_settings.py:49
|
||||
msgid "Argentinean Spanish"
|
||||
msgstr "Argentinisches Spanisch"
|
||||
|
||||
#: conf/global_settings.py:50
|
||||
#:conf/global_settings.py:50
|
||||
msgid "Persian"
|
||||
msgstr "Persisch"
|
||||
|
||||
#:conf/global_settings.py:51
|
||||
msgid "Finnish"
|
||||
msgstr "Finnisch"
|
||||
|
||||
#: conf/global_settings.py:51
|
||||
#:conf/global_settings.py:52
|
||||
msgid "French"
|
||||
msgstr "Französisch"
|
||||
|
||||
#: conf/global_settings.py:52
|
||||
#:conf/global_settings.py:53
|
||||
msgid "Galician"
|
||||
msgstr "Galicisch"
|
||||
|
||||
#: conf/global_settings.py:53
|
||||
#:conf/global_settings.py:54
|
||||
msgid "Hungarian"
|
||||
msgstr "Ungarisch"
|
||||
|
||||
#: conf/global_settings.py:54
|
||||
#:conf/global_settings.py:55
|
||||
msgid "Hebrew"
|
||||
msgstr "Hebräisch"
|
||||
|
||||
#: conf/global_settings.py:55
|
||||
#:conf/global_settings.py:56
|
||||
msgid "Icelandic"
|
||||
msgstr "Isländisch"
|
||||
|
||||
#: conf/global_settings.py:56
|
||||
#:conf/global_settings.py:57
|
||||
msgid "Italian"
|
||||
msgstr "Italienisch"
|
||||
|
||||
#: conf/global_settings.py:57
|
||||
#:conf/global_settings.py:58
|
||||
msgid "Japanese"
|
||||
msgstr "Japanisch"
|
||||
|
||||
#: conf/global_settings.py:58
|
||||
#:conf/global_settings.py:59
|
||||
msgid "Korean"
|
||||
msgstr "Koreanisch"
|
||||
|
||||
#: conf/global_settings.py:59
|
||||
#:conf/global_settings.py:60
|
||||
msgid "Kannada"
|
||||
msgstr "Kannada"
|
||||
|
||||
#: conf/global_settings.py:60
|
||||
#:conf/global_settings.py:61
|
||||
msgid "Latvian"
|
||||
msgstr "Lettisch"
|
||||
|
||||
#: conf/global_settings.py:61
|
||||
#:conf/global_settings.py:62
|
||||
msgid "Macedonian"
|
||||
msgstr "Mazedonisch"
|
||||
|
||||
#: conf/global_settings.py:62
|
||||
#:conf/global_settings.py:63
|
||||
msgid "Dutch"
|
||||
msgstr "Holländisch"
|
||||
|
||||
#: conf/global_settings.py:63
|
||||
#:conf/global_settings.py:64
|
||||
msgid "Norwegian"
|
||||
msgstr "Norwegisch"
|
||||
|
||||
#: conf/global_settings.py:64
|
||||
#:conf/global_settings.py:65
|
||||
msgid "Polish"
|
||||
msgstr "Polnisch"
|
||||
|
||||
#: conf/global_settings.py:65
|
||||
#:conf/global_settings.py:66
|
||||
msgid "Portugese"
|
||||
msgstr "Portugiesisch"
|
||||
|
||||
#: conf/global_settings.py:66
|
||||
#:conf/global_settings.py:67
|
||||
msgid "Brazilian"
|
||||
msgstr "Brasilianisches Portugiesisch"
|
||||
|
||||
#: conf/global_settings.py:67
|
||||
#:conf/global_settings.py:68
|
||||
msgid "Romanian"
|
||||
msgstr "Rumänisch"
|
||||
|
||||
#: conf/global_settings.py:68
|
||||
#:conf/global_settings.py:69
|
||||
msgid "Russian"
|
||||
msgstr "Russisch"
|
||||
|
||||
#: conf/global_settings.py:69
|
||||
#:conf/global_settings.py:70
|
||||
msgid "Slovak"
|
||||
msgstr "Slowakisch"
|
||||
|
||||
#: conf/global_settings.py:70
|
||||
#:conf/global_settings.py:71
|
||||
msgid "Slovenian"
|
||||
msgstr "Slowenisch"
|
||||
|
||||
#: conf/global_settings.py:71
|
||||
#:conf/global_settings.py:72
|
||||
msgid "Serbian"
|
||||
msgstr "Serbisch"
|
||||
|
||||
#: conf/global_settings.py:72
|
||||
#:conf/global_settings.py:73
|
||||
msgid "Swedish"
|
||||
msgstr "Schwedisch"
|
||||
|
||||
#: conf/global_settings.py:73
|
||||
#:conf/global_settings.py:74
|
||||
msgid "Tamil"
|
||||
msgstr "Tamilisch"
|
||||
|
||||
#: conf/global_settings.py:74
|
||||
#:conf/global_settings.py:75
|
||||
msgid "Telugu"
|
||||
msgstr "Telugisch"
|
||||
|
||||
#: conf/global_settings.py:75
|
||||
#:conf/global_settings.py:76
|
||||
msgid "Turkish"
|
||||
msgstr "Türkisch"
|
||||
|
||||
#: conf/global_settings.py:76
|
||||
#:conf/global_settings.py:77
|
||||
msgid "Ukrainian"
|
||||
msgstr "Ukrainisch"
|
||||
|
||||
#: conf/global_settings.py:77
|
||||
#:conf/global_settings.py:78
|
||||
msgid "Simplified Chinese"
|
||||
msgstr "Vereinfachtes Chinesisch"
|
||||
|
||||
#: conf/global_settings.py:78
|
||||
#:conf/global_settings.py:79
|
||||
msgid "Traditional Chinese"
|
||||
msgstr "Traditionelles Chinesisch"
|
||||
|
||||
#: contrib/admin/filterspecs.py:40
|
||||
#, python-format
|
||||
#:contrib/admin/filterspecs.py:42
|
||||
#,python-format
|
||||
msgid ""
|
||||
"<h3>By %s:</h3>\n"
|
||||
"<ul>\n"
|
||||
msgstr ""
|
||||
"<h3>Nach %s:</h3>\n"
|
||||
msgstr "<h3>Nach %s:</h3>\n"
|
||||
"<ul>\n"
|
||||
|
||||
#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88
|
||||
#: contrib/admin/filterspecs.py:143 contrib/admin/filterspecs.py:169
|
||||
#:contrib/admin/filterspecs.py:72 contrib/admin/filterspecs.py:90
|
||||
#:contrib/admin/filterspecs.py:145 contrib/admin/filterspecs.py:171
|
||||
msgid "All"
|
||||
msgstr "Alle"
|
||||
|
||||
#: contrib/admin/filterspecs.py:109
|
||||
#:contrib/admin/filterspecs.py:111
|
||||
msgid "Any date"
|
||||
msgstr "Alle Daten"
|
||||
|
||||
#: contrib/admin/filterspecs.py:110
|
||||
#:contrib/admin/filterspecs.py:112
|
||||
msgid "Today"
|
||||
msgstr "Heute"
|
||||
|
||||
#: contrib/admin/filterspecs.py:113
|
||||
#:contrib/admin/filterspecs.py:115
|
||||
msgid "Past 7 days"
|
||||
msgstr "Letzte 7 Tage"
|
||||
|
||||
#: contrib/admin/filterspecs.py:115
|
||||
#:contrib/admin/filterspecs.py:117
|
||||
msgid "This month"
|
||||
msgstr "Diesen Monat"
|
||||
|
||||
#: contrib/admin/filterspecs.py:117
|
||||
#:contrib/admin/filterspecs.py:119
|
||||
msgid "This year"
|
||||
msgstr "Dieses Jahr"
|
||||
|
||||
#: contrib/admin/filterspecs.py:143 newforms/widgets.py:180
|
||||
#: oldforms/__init__.py:577
|
||||
#:contrib/admin/filterspecs.py:145 newforms/widgets.py:181
|
||||
#:oldforms/__init__.py:587
|
||||
msgid "Yes"
|
||||
msgstr "Ja"
|
||||
|
||||
#: contrib/admin/filterspecs.py:143 newforms/widgets.py:180
|
||||
#: oldforms/__init__.py:577
|
||||
#:contrib/admin/filterspecs.py:145 newforms/widgets.py:181
|
||||
#:oldforms/__init__.py:587
|
||||
msgid "No"
|
||||
msgstr "Nein"
|
||||
|
||||
#: contrib/admin/filterspecs.py:150 newforms/widgets.py:180
|
||||
#: oldforms/__init__.py:577
|
||||
#:contrib/admin/filterspecs.py:152 newforms/widgets.py:181
|
||||
#:oldforms/__init__.py:587
|
||||
msgid "Unknown"
|
||||
msgstr "Unbekannt"
|
||||
|
||||
#: contrib/admin/models.py:16
|
||||
#:contrib/admin/models.py:17
|
||||
msgid "action time"
|
||||
msgstr "Zeitpunkt der Aktion"
|
||||
|
||||
#: contrib/admin/models.py:19
|
||||
#:contrib/admin/models.py:20
|
||||
msgid "object id"
|
||||
msgstr "Objekt-ID"
|
||||
|
||||
#: contrib/admin/models.py:20
|
||||
#:contrib/admin/models.py:21
|
||||
msgid "object repr"
|
||||
msgstr "Objekt Darst."
|
||||
|
||||
#: contrib/admin/models.py:21
|
||||
#:contrib/admin/models.py:22
|
||||
msgid "action flag"
|
||||
msgstr "Aktionskennzeichen"
|
||||
|
||||
#: contrib/admin/models.py:22
|
||||
#:contrib/admin/models.py:23
|
||||
msgid "change message"
|
||||
msgstr "Änderungsmeldung"
|
||||
|
||||
#: contrib/admin/models.py:25
|
||||
#:contrib/admin/models.py:26
|
||||
msgid "log entry"
|
||||
msgstr "Logeintrag"
|
||||
|
||||
#: contrib/admin/models.py:26
|
||||
#:contrib/admin/models.py:27
|
||||
msgid "log entries"
|
||||
msgstr "Logeinträge"
|
||||
|
||||
#: contrib/admin/templates/admin/404.html:4
|
||||
#: contrib/admin/templates/admin/404.html:8
|
||||
#:contrib/admin/templates/admin/404.html:4
|
||||
#:contrib/admin/templates/admin/404.html:8
|
||||
msgid "Page not found"
|
||||
msgstr "Seite nicht gefunden"
|
||||
|
||||
#: contrib/admin/templates/admin/404.html:10
|
||||
#:contrib/admin/templates/admin/404.html:10
|
||||
msgid "We're sorry, but the requested page could not be found."
|
||||
msgstr ""
|
||||
"Es tut uns leid, aber die angeforderte Seite konnte nicht gefunden werden."
|
||||
msgstr "Es tut uns leid, aber die angeforderte Seite konnte nicht gefunden werden."
|
||||
|
||||
#: contrib/admin/templates/admin/500.html:4
|
||||
#: contrib/admin/templates/admin/base.html:30
|
||||
#: contrib/admin/templates/admin/change_form.html:13
|
||||
#: contrib/admin/templates/admin/change_list.html:6
|
||||
#: contrib/admin/templates/admin/delete_confirmation.html:6
|
||||
#: contrib/admin/templates/admin/invalid_setup.html:4
|
||||
#: contrib/admin/templates/admin/object_history.html:5
|
||||
#: contrib/admin/templates/admin/auth/user/change_password.html:12
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:3
|
||||
#: contrib/admin/templates/registration/logged_out.html:4
|
||||
#: contrib/admin/templates/registration/password_change_done.html:4
|
||||
#: contrib/admin/templates/registration/password_change_form.html:4
|
||||
#: contrib/admin/templates/registration/password_reset_done.html:4
|
||||
#: contrib/admin/templates/registration/password_reset_form.html:4
|
||||
#:contrib/admin/templates/admin/500.html:4
|
||||
#:contrib/admin/templates/admin/base.html:30
|
||||
#:contrib/admin/templates/admin/change_form.html:13
|
||||
#:contrib/admin/templates/admin/change_list.html:6
|
||||
#:contrib/admin/templates/admin/delete_confirmation.html:6
|
||||
#:contrib/admin/templates/admin/invalid_setup.html:4
|
||||
#:contrib/admin/templates/admin/object_history.html:5
|
||||
#:contrib/admin/templates/admin/auth/user/change_password.html:12
|
||||
#:contrib/admin/templates/admin_doc/bookmarklets.html:3
|
||||
#:contrib/admin/templates/registration/logged_out.html:4
|
||||
#:contrib/admin/templates/registration/password_change_done.html:4
|
||||
#:contrib/admin/templates/registration/password_change_form.html:4
|
||||
#:contrib/admin/templates/registration/password_reset_done.html:4
|
||||
#:contrib/admin/templates/registration/password_reset_form.html:4
|
||||
msgid "Home"
|
||||
msgstr "Start"
|
||||
|
||||
#: contrib/admin/templates/admin/500.html:4
|
||||
#:contrib/admin/templates/admin/500.html:4
|
||||
msgid "Server error"
|
||||
msgstr "Serverfehler"
|
||||
|
||||
#: contrib/admin/templates/admin/500.html:6
|
||||
#:contrib/admin/templates/admin/500.html:6
|
||||
msgid "Server error (500)"
|
||||
msgstr "Serverfehler (500)"
|
||||
|
||||
#: contrib/admin/templates/admin/500.html:9
|
||||
#:contrib/admin/templates/admin/500.html:9
|
||||
msgid "Server Error <em>(500)</em>"
|
||||
msgstr "Serverfehler <em>(500)</em>"
|
||||
|
||||
#: contrib/admin/templates/admin/500.html:10
|
||||
#:contrib/admin/templates/admin/500.html:10
|
||||
msgid ""
|
||||
"There's been an error. It's been reported to the site administrators via e-"
|
||||
"mail and should be fixed shortly. Thanks for your patience."
|
||||
msgstr ""
|
||||
"Ein Fehler ist aufgetreten. Dieser Fehler wurde an die Serververwalter per E-"
|
||||
msgstr "Ein Fehler ist aufgetreten. Dieser Fehler wurde an die Serververwalter per E-"
|
||||
"Mail weitergegeben und sollte bald behoben sein. Vielen Dank für Ihr "
|
||||
"Verständnis."
|
||||
|
||||
#: contrib/admin/templates/admin/base.html:25
|
||||
#:contrib/admin/templates/admin/base.html:25
|
||||
msgid "Welcome,"
|
||||
msgstr "Willkommen,"
|
||||
|
||||
#: contrib/admin/templates/admin/base.html:25
|
||||
#: contrib/admin/templates/admin/change_form.html:10
|
||||
#: contrib/admin/templates/admin/change_list.html:5
|
||||
#: contrib/admin/templates/admin/delete_confirmation.html:3
|
||||
#: contrib/admin/templates/admin/object_history.html:3
|
||||
#: contrib/admin/templates/admin/auth/user/change_password.html:9
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:3
|
||||
#: contrib/admin/templates/registration/password_change_done.html:3
|
||||
#: contrib/admin/templates/registration/password_change_form.html:3
|
||||
#:contrib/admin/templates/admin/base.html:25
|
||||
#:contrib/admin/templates/admin/change_form.html:10
|
||||
#:contrib/admin/templates/admin/change_list.html:5
|
||||
#:contrib/admin/templates/admin/delete_confirmation.html:3
|
||||
#:contrib/admin/templates/admin/object_history.html:3
|
||||
#:contrib/admin/templates/admin/auth/user/change_password.html:9
|
||||
#:contrib/admin/templates/admin_doc/bookmarklets.html:3
|
||||
#:contrib/admin/templates/registration/password_change_done.html:3
|
||||
#:contrib/admin/templates/registration/password_change_form.html:3
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentation"
|
||||
|
||||
#: contrib/admin/templates/admin/base.html:25
|
||||
#: contrib/admin/templates/admin/change_form.html:10
|
||||
#: contrib/admin/templates/admin/change_list.html:5
|
||||
#: contrib/admin/templates/admin/delete_confirmation.html:3
|
||||
#: contrib/admin/templates/admin/object_history.html:3
|
||||
#: contrib/admin/templates/admin/auth/user/change_password.html:9
|
||||
#: contrib/admin/templates/admin/auth/user/change_password.html:15
|
||||
#: contrib/admin/templates/admin/auth/user/change_password.html:46
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:4
|
||||
#: contrib/admin/templates/admin_doc/index.html:4
|
||||
#: contrib/admin/templates/admin_doc/missing_docutils.html:4
|
||||
#: contrib/admin/templates/admin_doc/model_detail.html:3
|
||||
#: contrib/admin/templates/admin_doc/model_index.html:5
|
||||
#: contrib/admin/templates/admin_doc/template_detail.html:4
|
||||
#: contrib/admin/templates/admin_doc/template_filter_index.html:5
|
||||
#: contrib/admin/templates/admin_doc/template_tag_index.html:5
|
||||
#: contrib/admin/templates/admin_doc/view_detail.html:4
|
||||
#: contrib/admin/templates/admin_doc/view_index.html:5
|
||||
#: contrib/admin/templates/registration/password_change_done.html:3
|
||||
#: contrib/admin/templates/registration/password_change_form.html:3
|
||||
#:contrib/admin/templates/admin/base.html:25
|
||||
#:contrib/admin/templates/admin/change_form.html:10
|
||||
#:contrib/admin/templates/admin/change_list.html:5
|
||||
#:contrib/admin/templates/admin/delete_confirmation.html:3
|
||||
#:contrib/admin/templates/admin/object_history.html:3
|
||||
#:contrib/admin/templates/admin/auth/user/change_password.html:9
|
||||
#:contrib/admin/templates/admin/auth/user/change_password.html:15
|
||||
#:contrib/admin/templates/admin/auth/user/change_password.html:46
|
||||
#:contrib/admin/templates/admin_doc/bookmarklets.html:4
|
||||
#:contrib/admin/templates/admin_doc/index.html:4
|
||||
#:contrib/admin/templates/admin_doc/missing_docutils.html:4
|
||||
#:contrib/admin/templates/admin_doc/model_detail.html:3
|
||||
#:contrib/admin/templates/admin_doc/model_index.html:5
|
||||
#:contrib/admin/templates/admin_doc/template_detail.html:4
|
||||
#:contrib/admin/templates/admin_doc/template_filter_index.html:5
|
||||
#:contrib/admin/templates/admin_doc/template_tag_index.html:5
|
||||
#:contrib/admin/templates/admin_doc/view_detail.html:4
|
||||
#:contrib/admin/templates/admin_doc/view_index.html:5
|
||||
#:contrib/admin/templates/registration/password_change_done.html:3
|
||||
#:contrib/admin/templates/registration/password_change_form.html:3
|
||||
msgid "Change password"
|
||||
msgstr "Passwort ändern"
|
||||
|
||||
#: contrib/admin/templates/admin/base.html:25
|
||||
#: contrib/admin/templates/admin/change_form.html:10
|
||||
#: contrib/admin/templates/admin/change_list.html:5
|
||||
#: contrib/admin/templates/admin/delete_confirmation.html:3
|
||||
#: contrib/admin/templates/admin/object_history.html:3
|
||||
#: contrib/admin/templates/admin/auth/user/change_password.html:9
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:4
|
||||
#: contrib/admin/templates/admin_doc/index.html:4
|
||||
#: contrib/admin/templates/admin_doc/missing_docutils.html:4
|
||||
#: contrib/admin/templates/admin_doc/model_detail.html:3
|
||||
#: contrib/admin/templates/admin_doc/model_index.html:5
|
||||
#: contrib/admin/templates/admin_doc/template_detail.html:4
|
||||
#: contrib/admin/templates/admin_doc/template_filter_index.html:5
|
||||
#: contrib/admin/templates/admin_doc/template_tag_index.html:5
|
||||
#: contrib/admin/templates/admin_doc/view_detail.html:4
|
||||
#: contrib/admin/templates/admin_doc/view_index.html:5
|
||||
#: contrib/admin/templates/registration/password_change_done.html:3
|
||||
#: contrib/admin/templates/registration/password_change_form.html:3
|
||||
#: contrib/comments/templates/comments/form.html:6
|
||||
#:contrib/admin/templates/admin/base.html:25
|
||||
#:contrib/admin/templates/admin/change_form.html:10
|
||||
#:contrib/admin/templates/admin/change_list.html:5
|
||||
#:contrib/admin/templates/admin/delete_confirmation.html:3
|
||||
#:contrib/admin/templates/admin/object_history.html:3
|
||||
#:contrib/admin/templates/admin/auth/user/change_password.html:9
|
||||
#:contrib/admin/templates/admin_doc/bookmarklets.html:4
|
||||
#:contrib/admin/templates/admin_doc/index.html:4
|
||||
#:contrib/admin/templates/admin_doc/missing_docutils.html:4
|
||||
#:contrib/admin/templates/admin_doc/model_detail.html:3
|
||||
#:contrib/admin/templates/admin_doc/model_index.html:5
|
||||
#:contrib/admin/templates/admin_doc/template_detail.html:4
|
||||
#:contrib/admin/templates/admin_doc/template_filter_index.html:5
|
||||
#:contrib/admin/templates/admin_doc/template_tag_index.html:5
|
||||
#:contrib/admin/templates/admin_doc/view_detail.html:4
|
||||
#:contrib/admin/templates/admin_doc/view_index.html:5
|
||||
#:contrib/admin/templates/registration/password_change_done.html:3
|
||||
#:contrib/admin/templates/registration/password_change_form.html:3
|
||||
#:contrib/comments/templates/comments/form.html:6
|
||||
msgid "Log out"
|
||||
msgstr "Abmelden"
|
||||
|
||||
#: contrib/admin/templates/admin/base_site.html:4
|
||||
#:contrib/admin/templates/admin/base_site.html:4
|
||||
msgid "Django site admin"
|
||||
msgstr "Django-Systemverwaltung"
|
||||
|
||||
#: contrib/admin/templates/admin/base_site.html:7
|
||||
#:contrib/admin/templates/admin/base_site.html:7
|
||||
msgid "Django administration"
|
||||
msgstr "Django-Verwaltung"
|
||||
|
||||
#: contrib/admin/templates/admin/change_form.html:15
|
||||
#: contrib/admin/templates/admin/index.html:28
|
||||
#:contrib/admin/templates/admin/change_form.html:15
|
||||
#:contrib/admin/templates/admin/index.html:28
|
||||
msgid "Add"
|
||||
msgstr "Hinzufügen"
|
||||
|
||||
#: contrib/admin/templates/admin/change_form.html:21
|
||||
#: contrib/admin/templates/admin/object_history.html:5
|
||||
#:contrib/admin/templates/admin/change_form.html:21
|
||||
#:contrib/admin/templates/admin/object_history.html:5
|
||||
msgid "History"
|
||||
msgstr "Geschichte"
|
||||
|
||||
#: contrib/admin/templates/admin/change_form.html:22
|
||||
#:contrib/admin/templates/admin/change_form.html:22
|
||||
msgid "View on site"
|
||||
msgstr "Im Web anzeigen"
|
||||
|
||||
#: contrib/admin/templates/admin/change_form.html:32
|
||||
#: contrib/admin/templates/admin/auth/user/change_password.html:24
|
||||
#:contrib/admin/templates/admin/change_form.html:32
|
||||
#:contrib/admin/templates/admin/auth/user/change_password.html:24
|
||||
msgid "Please correct the error below."
|
||||
msgid_plural "Please correct the errors below."
|
||||
msgstr[0] "Bitte den aufgeführten Fehler korrigieren."
|
||||
msgstr[1] "Bitte die aufgeführten Fehler korrigieren."
|
||||
|
||||
#: contrib/admin/templates/admin/change_form.html:50
|
||||
#:contrib/admin/templates/admin/change_form.html:50
|
||||
msgid "Ordering"
|
||||
msgstr "Sortierung"
|
||||
|
||||
#: contrib/admin/templates/admin/change_form.html:53
|
||||
#:contrib/admin/templates/admin/change_form.html:53
|
||||
msgid "Order:"
|
||||
msgstr "Reihenfolge:"
|
||||
|
||||
#: contrib/admin/templates/admin/change_list.html:12
|
||||
#, python-format
|
||||
#:contrib/admin/templates/admin/change_list.html:12
|
||||
#,python-format
|
||||
msgid "Add %(name)s"
|
||||
msgstr "%(name)s hinzufügen"
|
||||
|
||||
#: contrib/admin/templates/admin/delete_confirmation.html:9
|
||||
#: contrib/admin/templates/admin/submit_line.html:3
|
||||
#:contrib/admin/templates/admin/delete_confirmation.html:9
|
||||
#:contrib/admin/templates/admin/submit_line.html:3
|
||||
msgid "Delete"
|
||||
msgstr "Löschen"
|
||||
|
||||
#: contrib/admin/templates/admin/delete_confirmation.html:14
|
||||
#, python-format
|
||||
#:contrib/admin/templates/admin/delete_confirmation.html:14
|
||||
#,python-format
|
||||
msgid ""
|
||||
"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting "
|
||||
"related objects, but your account doesn't have permission to delete the "
|
||||
"following types of objects:"
|
||||
msgstr ""
|
||||
"Die Löschung des %(object_name)s '%(escaped_object)s' hätte die Löschung von "
|
||||
msgstr "Die Löschung des %(object_name)s '%(escaped_object)s' hätte die Löschung von "
|
||||
"abhängigen Daten zur Folge, aber Sie haben nicht die nötigen Rechte um die "
|
||||
"folgenden abhängigen Daten zu löschen:"
|
||||
|
||||
#: contrib/admin/templates/admin/delete_confirmation.html:21
|
||||
#, python-format
|
||||
#:contrib/admin/templates/admin/delete_confirmation.html:21
|
||||
#,python-format
|
||||
msgid ""
|
||||
"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? "
|
||||
"All of the following related items will be deleted:"
|
||||
msgstr ""
|
||||
"Sind Sie sicher, dass Sie %(object_name)s \"%(escaped_object)s\" löschen "
|
||||
msgstr "Sind Sie sicher, dass Sie %(object_name)s \"%(escaped_object)s\" löschen "
|
||||
"wollen? Es werden zusätzlich die folgenden abhängigen Daten mit gelöscht:"
|
||||
|
||||
#: contrib/admin/templates/admin/delete_confirmation.html:26
|
||||
#:contrib/admin/templates/admin/delete_confirmation.html:26
|
||||
msgid "Yes, I'm sure"
|
||||
msgstr "Ja, ich bin sicher"
|
||||
|
||||
#: contrib/admin/templates/admin/filter.html:2
|
||||
#, python-format
|
||||
#:contrib/admin/templates/admin/filter.html:2
|
||||
#,python-format
|
||||
msgid " By %(filter_title)s "
|
||||
msgstr " Nach %(filter_title)s "
|
||||
|
||||
#: contrib/admin/templates/admin/filters.html:4
|
||||
#:contrib/admin/templates/admin/filters.html:4
|
||||
msgid "Filter"
|
||||
msgstr "Filter"
|
||||
|
||||
#: contrib/admin/templates/admin/index.html:17
|
||||
#, python-format
|
||||
#:contrib/admin/templates/admin/index.html:17
|
||||
#,python-format
|
||||
msgid "Models available in the %(name)s application."
|
||||
msgstr "Modelle, die in der Anwendung %(name)s vorhanden sind."
|
||||
|
||||
#: contrib/admin/templates/admin/index.html:18
|
||||
#, python-format
|
||||
#:contrib/admin/templates/admin/index.html:18
|
||||
#,python-format
|
||||
msgid "%(name)s"
|
||||
msgstr "%(name)s"
|
||||
|
||||
#: contrib/admin/templates/admin/index.html:34
|
||||
#:contrib/admin/templates/admin/index.html:34
|
||||
msgid "Change"
|
||||
msgstr "Ändern"
|
||||
|
||||
#: contrib/admin/templates/admin/index.html:44
|
||||
#:contrib/admin/templates/admin/index.html:44
|
||||
msgid "You don't have permission to edit anything."
|
||||
msgstr "Sie haben keine Berechtigung irgendwas zu ändern."
|
||||
|
||||
#: contrib/admin/templates/admin/index.html:52
|
||||
#:contrib/admin/templates/admin/index.html:52
|
||||
msgid "Recent Actions"
|
||||
msgstr "Kürzliche Aktionen"
|
||||
|
||||
#: contrib/admin/templates/admin/index.html:53
|
||||
#:contrib/admin/templates/admin/index.html:53
|
||||
msgid "My Actions"
|
||||
msgstr "Meine Aktionen"
|
||||
|
||||
#: contrib/admin/templates/admin/index.html:57
|
||||
#:contrib/admin/templates/admin/index.html:57
|
||||
msgid "None available"
|
||||
msgstr "Keine vorhanden"
|
||||
|
||||
#: contrib/admin/templates/admin/invalid_setup.html:8
|
||||
#:contrib/admin/templates/admin/invalid_setup.html:8
|
||||
msgid ""
|
||||
"Something's wrong with your database installation. Make sure the appropriate "
|
||||
"database tables have been created, and make sure the database is readable by "
|
||||
"the appropriate user."
|
||||
msgstr ""
|
||||
"Etwas stimmt nicht mit der Datenbankkonfiguration. Bitte sicherstellen, dass "
|
||||
"die richtigen Datenbanktabellen angelegt wurden und "
|
||||
"die Datenbank vom verwendeten Datenbankbenutzer auch lesbar ist."
|
||||
msgstr "Etwas stimmt nicht mit der Datenbankkonfiguration. Bitte sicherstellen, dass "
|
||||
"die richtigen Datenbanktabellen angelegt wurden und die Datenbank vom "
|
||||
"verwendeten Datenbankbenutzer auch lesbar ist."
|
||||
|
||||
#: contrib/admin/templates/admin/login.html:17
|
||||
#: contrib/comments/templates/comments/form.html:6
|
||||
#: contrib/comments/templates/comments/form.html:8
|
||||
#:contrib/admin/templates/admin/login.html:17
|
||||
#:contrib/comments/templates/comments/form.html:6
|
||||
#:contrib/comments/templates/comments/form.html:8
|
||||
msgid "Username:"
|
||||
msgstr "Benutzername:"
|
||||
|
||||
#: contrib/admin/templates/admin/login.html:20
|
||||
#: contrib/comments/templates/comments/form.html:8
|
||||
#:contrib/admin/templates/admin/login.html:20
|
||||
#:contrib/comments/templates/comments/form.html:8
|
||||
msgid "Password:"
|
||||
msgstr "Passwort:"
|
||||
|
||||
#: contrib/admin/templates/admin/login.html:25
|
||||
#: contrib/admin/views/decorators.py:24
|
||||
#:contrib/admin/templates/admin/login.html:25
|
||||
#:contrib/admin/views/decorators.py:24
|
||||
msgid "Log in"
|
||||
msgstr "Anmelden"
|
||||
|
||||
#: contrib/admin/templates/admin/object_history.html:18
|
||||
#:contrib/admin/templates/admin/object_history.html:18
|
||||
msgid "Date/time"
|
||||
msgstr "Datum/Zeit"
|
||||
|
||||
#: contrib/admin/templates/admin/object_history.html:19
|
||||
#:contrib/admin/templates/admin/object_history.html:19
|
||||
msgid "User"
|
||||
msgstr "Benutzer"
|
||||
|
||||
#: contrib/admin/templates/admin/object_history.html:20
|
||||
#:contrib/admin/templates/admin/object_history.html:20
|
||||
msgid "Action"
|
||||
msgstr "Aktion"
|
||||
|
||||
#: contrib/admin/templates/admin/object_history.html:26
|
||||
#:contrib/admin/templates/admin/object_history.html:26
|
||||
msgid "DATE_WITH_TIME_FULL"
|
||||
msgstr "j. N Y, H:i"
|
||||
|
||||
#: contrib/admin/templates/admin/object_history.html:36
|
||||
#:contrib/admin/templates/admin/object_history.html:36
|
||||
msgid ""
|
||||
"This object doesn't have a change history. It probably wasn't added via this "
|
||||
"admin site."
|
||||
msgstr ""
|
||||
"Dieses Objekt hat keine Änderungsgeschichte. Es wurde möglicherweise nicht "
|
||||
msgstr "Dieses Objekt hat keine Änderungsgeschichte. Es wurde möglicherweise nicht "
|
||||
"über diese Verwaltungsseiten angelegt."
|
||||
|
||||
#: contrib/admin/templates/admin/pagination.html:10
|
||||
#:contrib/admin/templates/admin/pagination.html:10
|
||||
msgid "Show all"
|
||||
msgstr "Zeige alle"
|
||||
|
||||
#: contrib/admin/templates/admin/search_form.html:8
|
||||
#:contrib/admin/templates/admin/search_form.html:8
|
||||
msgid "Go"
|
||||
msgstr "Los"
|
||||
|
||||
#: contrib/admin/templates/admin/search_form.html:10
|
||||
#, python-format
|
||||
#:contrib/admin/templates/admin/search_form.html:10
|
||||
#,python-format
|
||||
msgid "1 result"
|
||||
msgid_plural "%(counter)s results"
|
||||
msgstr[0] "Ein Ergebnis"
|
||||
msgstr[1] "%(counter)s Ergebnisse"
|
||||
|
||||
#: contrib/admin/templates/admin/search_form.html:10
|
||||
#, python-format
|
||||
#:contrib/admin/templates/admin/search_form.html:10
|
||||
#,python-format
|
||||
msgid "%(full_result_count)s total"
|
||||
msgstr "%(full_result_count)s gesamt"
|
||||
|
||||
#: contrib/admin/templates/admin/submit_line.html:4
|
||||
#:contrib/admin/templates/admin/submit_line.html:4
|
||||
msgid "Save as new"
|
||||
msgstr "Als neu sichern"
|
||||
|
||||
#: contrib/admin/templates/admin/submit_line.html:5
|
||||
#:contrib/admin/templates/admin/submit_line.html:5
|
||||
msgid "Save and add another"
|
||||
msgstr "Sichern und neu hinzufügen"
|
||||
|
||||
#: contrib/admin/templates/admin/submit_line.html:6
|
||||
#:contrib/admin/templates/admin/submit_line.html:6
|
||||
msgid "Save and continue editing"
|
||||
msgstr "Sichern und weiter bearbeiten"
|
||||
|
||||
#: contrib/admin/templates/admin/submit_line.html:7
|
||||
#:contrib/admin/templates/admin/submit_line.html:7
|
||||
msgid "Save"
|
||||
msgstr "Sichern"
|
||||
|
||||
#: contrib/admin/templates/admin/auth/user/add_form.html:6
|
||||
#:contrib/admin/templates/admin/auth/user/add_form.html:6
|
||||
msgid ""
|
||||
"First, enter a username and password. Then, you'll be able to edit more user "
|
||||
"options."
|
||||
msgstr ""
|
||||
"Zuerst einen Benutzer und ein Passwort eingeben. Danach können weitere "
|
||||
msgstr "Zuerst einen Benutzer und ein Passwort eingeben. Danach können weitere "
|
||||
"Optionen für den Benutzer geändert werden."
|
||||
|
||||
#: contrib/admin/templates/admin/auth/user/add_form.html:12
|
||||
#:contrib/admin/templates/admin/auth/user/add_form.html:12
|
||||
msgid "Username"
|
||||
msgstr "Benutzername"
|
||||
|
||||
#: contrib/admin/templates/admin/auth/user/add_form.html:18
|
||||
#: contrib/admin/templates/admin/auth/user/change_password.html:34
|
||||
#:contrib/admin/templates/admin/auth/user/add_form.html:18
|
||||
#:contrib/admin/templates/admin/auth/user/change_password.html:34
|
||||
msgid "Password"
|
||||
msgstr "Passwort"
|
||||
|
||||
#: contrib/admin/templates/admin/auth/user/add_form.html:23
|
||||
#: contrib/admin/templates/admin/auth/user/change_password.html:39
|
||||
#:contrib/admin/templates/admin/auth/user/add_form.html:23
|
||||
#:contrib/admin/templates/admin/auth/user/change_password.html:39
|
||||
msgid "Password (again)"
|
||||
msgstr "Passwort (wiederholen)"
|
||||
|
||||
#: contrib/admin/templates/admin/auth/user/add_form.html:24
|
||||
#: contrib/admin/templates/admin/auth/user/change_password.html:40
|
||||
#:contrib/admin/templates/admin/auth/user/add_form.html:24
|
||||
#:contrib/admin/templates/admin/auth/user/change_password.html:40
|
||||
msgid "Enter the same password as above, for verification."
|
||||
msgstr "Bitte das gleiche Passwort zur Überprüfung nochmal eingeben."
|
||||
|
||||
#: contrib/admin/templates/admin/auth/user/change_password.html:28
|
||||
#, python-format
|
||||
#:contrib/admin/templates/admin/auth/user/change_password.html:28
|
||||
#,python-format
|
||||
msgid "Enter a new password for the user <strong>%(username)s</strong>."
|
||||
msgstr ""
|
||||
"Bitte geben Sie ein neues Passwort für den Benutzer <strong>%(username)s</"
|
||||
msgstr "Bitte geben Sie ein neues Passwort für den Benutzer <strong>%(username)s</"
|
||||
"strong> ein."
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:3
|
||||
#:contrib/admin/templates/admin_doc/bookmarklets.html:3
|
||||
msgid "Bookmarklets"
|
||||
msgstr "Bookmarklets"
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:5
|
||||
#:contrib/admin/templates/admin_doc/bookmarklets.html:5
|
||||
msgid "Documentation bookmarklets"
|
||||
msgstr "Dokumentations-Bookmarklets"
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:9
|
||||
#:contrib/admin/templates/admin_doc/bookmarklets.html:9
|
||||
msgid ""
|
||||
"\n"
|
||||
"<p class=\"help\">To install bookmarklets, drag the link to your bookmarks\n"
|
||||
@ -612,9 +611,9 @@ msgid ""
|
||||
"bookmarklets require you to be viewing the site from a computer designated\n"
|
||||
"as \"internal\" (talk to your system administrator if you aren't sure if\n"
|
||||
"your computer is \"internal\").</p>\n"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"<p class=\"help\">Um Bookmarklets zu installieren, müssen diese Links in die\n"
|
||||
msgstr "\n"
|
||||
"<p class=\"help\">Um Bookmarklets zu installieren, müssen diese Links in "
|
||||
"die\n"
|
||||
"Browser-Werkzeugleiste gezogen werden, oder mittels rechter Maustaste in "
|
||||
"die\n"
|
||||
"Bookmarks gespeichert werden. Danach können die Bookmarklets von jeder "
|
||||
@ -830,7 +829,7 @@ msgid ""
|
||||
"Please enter a correct username and password. Note that both fields are case-"
|
||||
"sensitive."
|
||||
msgstr ""
|
||||
"Bitte einen Benutzernamen und ein Passwort eingeben. Beide Felder "
|
||||
"Bitte einen gültigen Benutzernamen und ein Passwort eingeben. Beide Felder "
|
||||
"berücksichtigen die Groß-/Kleinschreibung."
|
||||
|
||||
#: contrib/admin/views/decorators.py:62
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -2862,7 +2862,7 @@ msgstr "jul"
|
||||
|
||||
#: utils/dates.py:24
|
||||
msgid "aug"
|
||||
msgstr "aout"
|
||||
msgstr "août"
|
||||
|
||||
#: utils/dates.py:24
|
||||
msgid "sep"
|
||||
@ -2890,7 +2890,7 @@ msgstr "Fév."
|
||||
|
||||
#: utils/dates.py:32
|
||||
msgid "Aug."
|
||||
msgstr "Aôut"
|
||||
msgstr "Août"
|
||||
|
||||
#: utils/dates.py:32
|
||||
msgid "Sept."
|
||||
|
Binary file not shown.
@ -35,7 +35,7 @@ msgstr "Dimanche Lundi Mardi Mercredi Jeudi Vendredi Samedi"
|
||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||
#, perl-format
|
||||
msgid "Available %s"
|
||||
msgstr "Disponible %s"
|
||||
msgstr "%s disponible(s)"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:41
|
||||
msgid "Choose all"
|
||||
@ -52,7 +52,7 @@ msgstr "Enlever"
|
||||
#: contrib/admin/media/js/SelectFilter2.js:53
|
||||
#, perl-format
|
||||
msgid "Chosen %s"
|
||||
msgstr "Choisi %s"
|
||||
msgstr "%s choisi(es)"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:54
|
||||
msgid "Select your choice(s) and click "
|
||||
|
BIN
django/conf/locale/hr/LC_MESSAGES/django.mo
Normal file
BIN
django/conf/locale/hr/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
3282
django/conf/locale/hr/LC_MESSAGES/django.po
Normal file
3282
django/conf/locale/hr/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
BIN
django/conf/locale/hr/LC_MESSAGES/djangojs.mo
Normal file
BIN
django/conf/locale/hr/LC_MESSAGES/djangojs.mo
Normal file
Binary file not shown.
118
django/conf/locale/hr/LC_MESSAGES/djangojs.po
Normal file
118
django/conf/locale/hr/LC_MESSAGES/djangojs.po
Normal file
@ -0,0 +1,118 @@
|
||||
# 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.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-08-13 11:13+1000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||
#, perl-format
|
||||
msgid "Available %s"
|
||||
msgstr ""
|
||||
|
||||
#: 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 ""
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:54
|
||||
msgid "Select your choice(s) and click "
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:59
|
||||
msgid "Clear all"
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:32
|
||||
#: contrib/admin/media/js/calendar.js:24
|
||||
msgid ""
|
||||
"January February March April May June July August September October November "
|
||||
"December"
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:33
|
||||
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/calendar.js:25
|
||||
msgid "S M T W T F S"
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
|
||||
msgid "Now"
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
|
||||
msgid "Clock"
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
|
||||
msgid "Choose a time"
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
||||
msgid "Midnight"
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
|
||||
msgid "6 a.m."
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
|
||||
msgid "Noon"
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
|
||||
msgid "Today"
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
|
||||
msgid "Calendar"
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
|
||||
msgid "Yesterday"
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
|
||||
msgid "Tomorrow"
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
|
||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
|
||||
msgid "Show"
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
|
||||
msgid "Hide"
|
||||
msgstr ""
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -38,7 +38,7 @@ msgstr "Domenica Lunedì Martedì Mercoledì Giovedì Venerdì Sabato"
|
||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||
#, perl-format
|
||||
msgid "Available %s"
|
||||
msgstr "Disponibile %s"
|
||||
msgstr "%s disponibili"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:41
|
||||
msgid "Choose all"
|
||||
@ -55,11 +55,11 @@ msgstr "Rimuovi"
|
||||
#: contrib/admin/media/js/SelectFilter2.js:53
|
||||
#, perl-format
|
||||
msgid "Chosen %s"
|
||||
msgstr "Scelto %s"
|
||||
msgstr "%s scelti"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:54
|
||||
msgid "Select your choice(s) and click "
|
||||
msgstr "Seleziona le tue scelte e clicca "
|
||||
msgstr "Fai le tue scelte e clicca "
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:59
|
||||
msgid "Clear all"
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -40,6 +40,10 @@ var RUSSIAN_MAP = {
|
||||
'Ч':'Ch', 'Ш':'Sh', 'Щ':'Sh', 'Ъ':'', 'Ы':'Y', 'Ь':'', 'Э':'E', 'Ю':'Yu',
|
||||
'Я':'Ya'
|
||||
}
|
||||
var CZECH_MAP = {
|
||||
'č':'c', 'ď':'d', 'ě':'e', 'ň': 'n', 'ř':'r', 'š':'s', 'ť':'t', 'ů':'u',
|
||||
'ž':'z'
|
||||
}
|
||||
|
||||
var ALL_DOWNCODE_MAPS=new Array()
|
||||
ALL_DOWNCODE_MAPS[0]=LATIN_MAP
|
||||
@ -47,6 +51,7 @@ ALL_DOWNCODE_MAPS[1]=LATIN_SYMBOLS_MAP
|
||||
ALL_DOWNCODE_MAPS[2]=GREEK_MAP
|
||||
ALL_DOWNCODE_MAPS[3]=TURKISH_MAP
|
||||
ALL_DOWNCODE_MAPS[4]=RUSSIAN_MAP
|
||||
ALL_DOWNCODE_MAPS[5]=CZECH_MAP
|
||||
|
||||
var Downcoder = new Object();
|
||||
Downcoder.Initialize = function()
|
||||
|
@ -6,7 +6,7 @@
|
||||
{% endblock %}
|
||||
{% block stylesheet %}{% admin_media_prefix %}css/forms.css{% endblock %}
|
||||
{% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %}
|
||||
{% block userlinks %}<a href="../../../../doc/">{% trans 'Documentation' %}</a> / <a href="../../../password_change/">{% trans 'Change password' %}</a> / <a href="../../../logout/">{% trans 'Log out' %}</a>{% endblock %}
|
||||
{% block userlinks %}<a href="../../../../doc/">{% trans 'Documentation' %}</a> / <a href="../../../../password_change/">{% trans 'Change password' %}</a> / <a href="../../../../logout/">{% trans 'Log out' %}</a>{% endblock %}
|
||||
{% block breadcrumbs %}{% if not is_popup %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="../../../../">{% trans "Home" %}</a> ›
|
||||
|
@ -3,7 +3,7 @@ from django.contrib.auth.forms import PasswordResetForm, PasswordChangeForm
|
||||
from django import oldforms
|
||||
from django.shortcuts import render_to_response
|
||||
from django.template import RequestContext
|
||||
from django.contrib.sites.models import Site
|
||||
from django.contrib.sites.models import Site, RequestSite
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||
@ -27,10 +27,16 @@ def login(request, template_name='registration/login.html'):
|
||||
else:
|
||||
errors = {}
|
||||
request.session.set_test_cookie()
|
||||
|
||||
if Site._meta.installed:
|
||||
current_site = Site.objects.get_current()
|
||||
else:
|
||||
current_site = RequestSite(request)
|
||||
|
||||
return render_to_response(template_name, {
|
||||
'form': oldforms.FormWrapper(manipulator, request.POST, errors),
|
||||
REDIRECT_FIELD_NAME: redirect_to,
|
||||
'site_name': Site.objects.get_current().name,
|
||||
'site_name': current_site.name,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
def logout(request, next_page=None, template_name='registration/logged_out.html'):
|
||||
|
@ -96,7 +96,10 @@ class Comment(models.Model):
|
||||
return "%s: %s..." % (self.user.username, self.comment[:100])
|
||||
|
||||
def get_absolute_url(self):
|
||||
return self.get_content_object().get_absolute_url() + "#c" + str(self.id)
|
||||
try:
|
||||
return self.get_content_object().get_absolute_url() + "#c" + str(self.id)
|
||||
except AttributeError:
|
||||
return ""
|
||||
|
||||
def get_crossdomain_url(self):
|
||||
return "/r/%d/%d/" % (self.content_type_id, self.object_id)
|
||||
@ -172,7 +175,10 @@ class FreeComment(models.Model):
|
||||
return "%s: %s..." % (self.person_name, self.comment[:100])
|
||||
|
||||
def get_absolute_url(self):
|
||||
return self.get_content_object().get_absolute_url() + "#c" + str(self.id)
|
||||
try:
|
||||
return self.get_content_object().get_absolute_url() + "#c" + str(self.id)
|
||||
except AttributeError:
|
||||
return ""
|
||||
|
||||
def get_content_object(self):
|
||||
"""
|
||||
|
@ -112,9 +112,9 @@ class CommentListNode(template.Node):
|
||||
'site__id__exact': settings.SITE_ID,
|
||||
}
|
||||
kwargs.update(self.extra_kwargs)
|
||||
if not self.free and settings.COMMENTS_BANNED_USERS_GROUP:
|
||||
kwargs['select'] = {'is_hidden': 'user_id IN (SELECT user_id FROM auth_user_groups WHERE group_id = %s)' % settings.COMMENTS_BANNED_USERS_GROUP}
|
||||
comment_list = get_list_function(**kwargs).order_by(self.ordering + 'submit_date').select_related()
|
||||
if not self.free and settings.COMMENTS_BANNED_USERS_GROUP:
|
||||
comment_list = comment_list.extra(select={'is_hidden': 'user_id IN (SELECT user_id FROM auth_user_groups WHERE group_id = %s)' % settings.COMMENTS_BANNED_USERS_GROUP})
|
||||
|
||||
if not self.free:
|
||||
if 'user' in context and context['user'].is_authenticated():
|
||||
|
@ -113,7 +113,7 @@ class PublicCommentManipulator(AuthenticationForm):
|
||||
'This comment was posted by a user who has posted fewer than %(count)s comments:\n\n%(text)s', settings.COMMENTS_FIRST_FEW) % \
|
||||
{'count': settings.COMMENTS_FIRST_FEW, 'text': c.get_as_text()}
|
||||
mail_managers("Comment posted by rookie user", message)
|
||||
if settings.COMMENTS_SKETCHY_USERS_GROUP and settings.COMMENTS_SKETCHY_USERS_GROUP in [g.id for g in self.user_cache.get_group_list()]:
|
||||
if settings.COMMENTS_SKETCHY_USERS_GROUP and settings.COMMENTS_SKETCHY_USERS_GROUP in [g.id for g in self.user_cache.groups.all()]:
|
||||
message = _('This comment was posted by a sketchy user:\n\n%(text)s') % {'text': c.get_as_text()}
|
||||
mail_managers("Comment posted by sketchy user (%s)" % self.user_cache.username, c.get_as_text())
|
||||
return c
|
||||
|
0
django/contrib/localflavor/in_/__init__.py
Normal file
0
django/contrib/localflavor/in_/__init__.py
Normal file
49
django/contrib/localflavor/in_/forms.py
Normal file
49
django/contrib/localflavor/in_/forms.py
Normal file
@ -0,0 +1,49 @@
|
||||
"""
|
||||
India-specific Form helpers.
|
||||
"""
|
||||
|
||||
from django.newforms import ValidationError
|
||||
from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
|
||||
from django.utils.encoding import smart_unicode
|
||||
from django.utils.translation import gettext
|
||||
import re
|
||||
|
||||
|
||||
class INZipCodeField(RegexField):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(INZipCodeField, self).__init__(r'^\d{6}$',
|
||||
max_length=None, min_length=None,
|
||||
error_message=gettext(u'Enter a zip code in the format XXXXXXX.'),
|
||||
*args, **kwargs)
|
||||
|
||||
class INStateField(Field):
|
||||
"""
|
||||
A form field that validates its input is a Indian state name or
|
||||
abbreviation. It normalizes the input to the standard two-letter vehicle
|
||||
registration abbreviation for the given state or union territory
|
||||
"""
|
||||
def clean(self, value):
|
||||
from in_states import STATES_NORMALIZED
|
||||
super(INStateField, self).clean(value)
|
||||
if value in EMPTY_VALUES:
|
||||
return u''
|
||||
try:
|
||||
value = value.strip().lower()
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
return smart_unicode(STATES_NORMALIZED[value.strip().lower()])
|
||||
except KeyError:
|
||||
pass
|
||||
raise ValidationError(u'Enter a Indian state or territory.')
|
||||
|
||||
class INStateSelect(Select):
|
||||
"""
|
||||
A Select widget that uses a list of Indian states/territories as its
|
||||
choices.
|
||||
"""
|
||||
def __init__(self, attrs=None):
|
||||
from in_states import STATE_CHOICES
|
||||
super(INStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
|
||||
|
84
django/contrib/localflavor/in_/in_states.py
Normal file
84
django/contrib/localflavor/in_/in_states.py
Normal file
@ -0,0 +1,84 @@
|
||||
"""
|
||||
A mapping of state misspellings/abbreviations to normalized abbreviations, and
|
||||
an alphabetical list of states for use as `choices` in a formfield.
|
||||
|
||||
This exists in this standalone file so that it's only imported into memory
|
||||
when explicitly needed.
|
||||
"""
|
||||
|
||||
STATE_CHOICES = (
|
||||
'KA', 'Karnataka',
|
||||
'AP', 'Andhra Pradesh',
|
||||
'KL', 'Kerala',
|
||||
'TN', 'Tamil Nadu',
|
||||
'MH', 'Maharashtra',
|
||||
'UP', 'Uttar Pradesh',
|
||||
'GA', 'Goa',
|
||||
'GJ', 'Gujarat',
|
||||
'RJ', 'Rajasthan',
|
||||
'HP', 'Himachal Pradesh',
|
||||
'JK', 'Jammu and Kashmir',
|
||||
'AR', 'Arunachal Pradesh',
|
||||
'AS', 'Assam',
|
||||
'BR', 'Bihar',
|
||||
'CG', 'Chattisgarh',
|
||||
'HR', 'Haryana',
|
||||
'JH', 'Jharkhand',
|
||||
'MP', 'Madhya Pradesh',
|
||||
'MN', 'Manipur',
|
||||
'ML', 'Meghalaya',
|
||||
'MZ', 'Mizoram',
|
||||
'NL', 'Nagaland',
|
||||
'OR', 'Orissa',
|
||||
'PB', 'Punjab',
|
||||
'SK', 'Sikkim',
|
||||
'TR', 'Tripura',
|
||||
'UA', 'Uttarakhand',
|
||||
'WB', 'West Bengal',
|
||||
|
||||
# Union Territories
|
||||
'AN', 'Andaman and Nicobar',
|
||||
'CH', 'Chandigarh',
|
||||
'DN', 'Dadra and Nagar Haveli',
|
||||
'DD', 'Daman and Diu',
|
||||
'DL', 'Delhi',
|
||||
'LD', 'Lakshadweep',
|
||||
'PY', 'Pondicherry',
|
||||
)
|
||||
|
||||
STATES_NORMALIZED = {
|
||||
'ka': 'KA',
|
||||
'karnatka': 'KA',
|
||||
'tn': 'TN',
|
||||
'tamilnad': 'TN',
|
||||
'tamilnadu': 'TN',
|
||||
'andra pradesh': 'AP',
|
||||
'andrapradesh': 'AP',
|
||||
'andhrapradesh': 'AP',
|
||||
'maharastra': 'MH',
|
||||
'mh': 'MH',
|
||||
'ap': 'AP',
|
||||
'dl': 'DL',
|
||||
'dd': 'DD',
|
||||
'br': 'BR',
|
||||
'ar': 'AR',
|
||||
'sk': 'SK',
|
||||
'kl': 'KL',
|
||||
'ga': 'GA',
|
||||
'rj': 'RJ',
|
||||
'rajastan': 'RJ',
|
||||
'rajasthan': 'RJ',
|
||||
'hp': 'HP',
|
||||
'ua': 'UA',
|
||||
'up': 'UP',
|
||||
'mp': 'MP',
|
||||
'mz': 'MZ',
|
||||
'bengal': 'WB',
|
||||
'westbengal': 'WB',
|
||||
'mizo': 'MZ',
|
||||
'orisa': 'OR',
|
||||
'odisa': 'OR',
|
||||
'or': 'OR',
|
||||
'ar': 'AR',
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ from django.utils.encoding import force_unicode
|
||||
from django import http
|
||||
from pprint import pformat
|
||||
from shutil import copyfileobj
|
||||
from threading import Lock
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except ImportError:
|
||||
@ -176,13 +177,19 @@ class WSGIRequest(http.HttpRequest):
|
||||
raw_post_data = property(_get_raw_post_data)
|
||||
|
||||
class WSGIHandler(BaseHandler):
|
||||
initLock = Lock()
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
from django.conf import settings
|
||||
|
||||
# Set up middleware if needed. We couldn't do this earlier, because
|
||||
# settings weren't available.
|
||||
if self._request_middleware is None:
|
||||
self.load_middleware()
|
||||
self.initLock.acquire()
|
||||
# Check that middleware is still uninitialised.
|
||||
if self._request_middleware is None:
|
||||
self.load_middleware()
|
||||
self.initLock.release()
|
||||
|
||||
dispatcher.send(signal=signals.request_started)
|
||||
try:
|
||||
|
@ -287,7 +287,8 @@ class EmailMessage(object):
|
||||
mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
|
||||
basetype, subtype = mimetype.split('/', 1)
|
||||
if basetype == 'text':
|
||||
attachment = SafeMIMEText(content, subtype, settings.DEFAULT_CHARSET)
|
||||
attachment = SafeMIMEText(smart_str(content,
|
||||
settings.DEFAULT_CHARSET), subtype, settings.DEFAULT_CHARSET)
|
||||
else:
|
||||
# Encode non-text attachments with base64.
|
||||
attachment = MIMEBase(basetype, subtype)
|
||||
|
File diff suppressed because it is too large
Load Diff
180
django/core/management/__init__.py
Normal file
180
django/core/management/__init__.py
Normal file
@ -0,0 +1,180 @@
|
||||
import django
|
||||
from optparse import OptionParser
|
||||
import os
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
# For backwards compatibility: get_version() used to be in this module.
|
||||
get_version = django.get_version
|
||||
|
||||
def load_command_class(name):
|
||||
"""
|
||||
Given a command name, returns the Command class instance. Raises
|
||||
ImportError if it doesn't exist.
|
||||
"""
|
||||
# Let the ImportError propogate.
|
||||
return getattr(__import__('django.core.management.commands.%s' % name, {}, {}, ['Command']), 'Command')()
|
||||
|
||||
def call_command(name, *args, **options):
|
||||
"""
|
||||
Calls the given command, with the given options and args/kwargs.
|
||||
|
||||
This is the primary API you should use for calling specific commands.
|
||||
|
||||
Some examples:
|
||||
call_command('syncdb')
|
||||
call_command('shell', plain=True)
|
||||
call_command('sqlall', 'myapp')
|
||||
"""
|
||||
klass = load_command_class(name)
|
||||
return klass.execute(*args, **options)
|
||||
|
||||
class ManagementUtility(object):
|
||||
"""
|
||||
Encapsulates the logic of the django-admin.py and manage.py utilities.
|
||||
|
||||
A ManagementUtility has a number of commands, which can be manipulated
|
||||
by editing the self.commands dictionary.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.commands = self.default_commands()
|
||||
|
||||
def default_commands(self):
|
||||
"""
|
||||
Returns a dictionary of instances of all available Command classes.
|
||||
|
||||
This works by looking for and loading all Python modules in the
|
||||
django.core.management.commands package.
|
||||
|
||||
The dictionary is in the format {name: command_instance}.
|
||||
"""
|
||||
command_dir = os.path.join(__path__[0], 'commands')
|
||||
names = [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')]
|
||||
return dict([(name, load_command_class(name)) for name in names])
|
||||
|
||||
def usage(self):
|
||||
"""
|
||||
Returns a usage string, for use with optparse.
|
||||
|
||||
The string doesn't include the options (e.g., "--verbose"), because
|
||||
optparse puts those in automatically.
|
||||
"""
|
||||
usage = ["%prog command [options]\nactions:"]
|
||||
commands = self.commands.items()
|
||||
commands.sort()
|
||||
for name, cmd in commands:
|
||||
usage.append(' %s %s' % (name, cmd.args))
|
||||
usage.extend(textwrap.wrap(cmd.help, initial_indent=' ', subsequent_indent=' '))
|
||||
usage.append('')
|
||||
return '\n'.join(usage[:-1]) # Cut off the last list element, an empty space.
|
||||
|
||||
def execute(self, argv=None):
|
||||
"""
|
||||
Parses the given argv from the command line, determines which command
|
||||
to run and runs the command.
|
||||
"""
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
|
||||
# Create the parser object and parse the command-line args.
|
||||
# TODO: Ideally each Command class would register its own options for
|
||||
# add_option(), but we'd need to figure out how to allow for multiple
|
||||
# Commands using the same options. The optparse library gets in the way
|
||||
# by checking for conflicts:
|
||||
# http://docs.python.org/lib/optparse-conflicts-between-options.html
|
||||
parser = OptionParser(usage=self.usage(), version=get_version())
|
||||
parser.add_option('--settings',
|
||||
help='The Python path to a settings module, e.g. "myproject.settings.main". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.')
|
||||
parser.add_option('--pythonpath',
|
||||
help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".')
|
||||
parser.add_option('--plain', action='store_true', dest='plain',
|
||||
help='When using "shell": Tells Django to use plain Python, not IPython.')
|
||||
parser.add_option('--noinput', action='store_false', dest='interactive', default=True,
|
||||
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='When using "runserver": Tells Django to NOT use the auto-reloader.')
|
||||
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')
|
||||
parser.add_option('--adminmedia', dest='admin_media_path', default='',
|
||||
help='When using "runserver": Specifies the directory from which to serve admin media.')
|
||||
options, args = parser.parse_args(argv[1:])
|
||||
|
||||
# If the 'settings' or 'pythonpath' options were submitted, activate those.
|
||||
if options.settings:
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
|
||||
if options.pythonpath:
|
||||
sys.path.insert(0, options.pythonpath)
|
||||
|
||||
# Run the appropriate command.
|
||||
try:
|
||||
command_name = args[0]
|
||||
except IndexError:
|
||||
sys.stderr.write("Type '%s --help' for usage.\n" % os.path.basename(argv[0]))
|
||||
sys.exit(1)
|
||||
try:
|
||||
command = self.commands[command_name]
|
||||
except KeyError:
|
||||
sys.stderr.write("Unknown command: %r\nType '%s --help' for usage.\n" % (command_name, os.path.basename(argv[0])))
|
||||
sys.exit(1)
|
||||
command.execute(*args[1:], **options.__dict__)
|
||||
|
||||
class ProjectManagementUtility(ManagementUtility):
|
||||
"""
|
||||
A ManagementUtility that is specific to a particular Django project.
|
||||
As such, its commands are slightly different than those of its parent
|
||||
class.
|
||||
|
||||
In practice, this class represents manage.py, whereas ManagementUtility
|
||||
represents django-admin.py.
|
||||
"""
|
||||
def __init__(self, project_directory):
|
||||
super(ProjectManagementUtility, self).__init__()
|
||||
|
||||
# Remove the "startproject" command from self.commands, because
|
||||
# that's a django-admin.py command, not a manage.py command.
|
||||
del self.commands['startproject']
|
||||
|
||||
# Override the startapp command so that it always uses the
|
||||
# project_directory, not the current working directory (which is default).
|
||||
from django.core.management.commands.startapp import ProjectCommand
|
||||
self.commands['startapp'] = ProjectCommand(project_directory)
|
||||
|
||||
def setup_environ(settings_mod):
|
||||
"""
|
||||
Configure the runtime environment. This can also be used by external
|
||||
scripts wanting to set up a similar environment to manage.py.
|
||||
"""
|
||||
# Add this project to sys.path so that it's importable in the conventional
|
||||
# way. For example, if this file (manage.py) lives in a directory
|
||||
# "myproject", this code would add "/path/to/myproject" to sys.path.
|
||||
project_directory, settings_filename = os.path.split(settings_mod.__file__)
|
||||
project_name = os.path.basename(project_directory)
|
||||
settings_name = os.path.splitext(settings_filename)[0]
|
||||
sys.path.append(os.path.join(project_directory, '..'))
|
||||
project_module = __import__(project_name, {}, {}, [''])
|
||||
sys.path.pop()
|
||||
|
||||
# Set DJANGO_SETTINGS_MODULE appropriately.
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = '%s.%s' % (project_name, settings_name)
|
||||
return project_directory
|
||||
|
||||
def execute_from_command_line(argv=None):
|
||||
"""
|
||||
A simple method that runs a ManagementUtility.
|
||||
"""
|
||||
utility = ManagementUtility()
|
||||
utility.execute(argv)
|
||||
|
||||
def execute_manager(settings_mod, argv=None):
|
||||
"""
|
||||
Like execute_from_command_line(), but for use by manage.py, a
|
||||
project-specific django-admin.py utility.
|
||||
"""
|
||||
project_directory = setup_environ(settings_mod)
|
||||
utility = ProjectManagementUtility(project_directory)
|
||||
utility.execute(argv)
|
159
django/core/management/base.py
Normal file
159
django/core/management/base.py
Normal file
@ -0,0 +1,159 @@
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.management.color import color_style
|
||||
import sys
|
||||
|
||||
class CommandError(Exception):
|
||||
pass
|
||||
|
||||
class BaseCommand(object):
|
||||
# Metadata about this command.
|
||||
help = ''
|
||||
args = ''
|
||||
|
||||
# Configuration shortcuts that alter various logic.
|
||||
can_import_settings = True
|
||||
requires_model_validation = True
|
||||
output_transaction = False # Whether to wrap the output in a "BEGIN; COMMIT;"
|
||||
|
||||
def __init__(self):
|
||||
self.style = color_style()
|
||||
|
||||
def execute(self, *args, **options):
|
||||
# Switch to English, because django-admin.py creates database content
|
||||
# like permissions, and those shouldn't contain any translations.
|
||||
# But only do this if we can assume we have a working settings file,
|
||||
# because django.utils.translation requires settings.
|
||||
if self.can_import_settings:
|
||||
from django.utils import translation
|
||||
translation.activate('en-us')
|
||||
|
||||
try:
|
||||
if self.requires_model_validation:
|
||||
self.validate()
|
||||
output = self.handle(*args, **options)
|
||||
if output:
|
||||
if self.output_transaction:
|
||||
# This needs to be imported here, because it relies on settings.
|
||||
from django.db import backend
|
||||
if backend.get_start_transaction_sql():
|
||||
print self.style.SQL_KEYWORD(backend.get_start_transaction_sql())
|
||||
print output
|
||||
if self.output_transaction:
|
||||
print self.style.SQL_KEYWORD("COMMIT;")
|
||||
except CommandError, e:
|
||||
sys.stderr.write(self.style.ERROR(str('Error: %s\n' % e)))
|
||||
sys.exit(1)
|
||||
|
||||
def validate(self, app=None):
|
||||
"""
|
||||
Validates the given app, raising CommandError for any errors.
|
||||
|
||||
If app is None, then this will validate all installed apps.
|
||||
"""
|
||||
from django.core.management.validation import get_validation_errors
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except ImportError:
|
||||
from StringIO import StringIO
|
||||
s = StringIO()
|
||||
num_errors = get_validation_errors(s, app)
|
||||
if num_errors:
|
||||
s.seek(0)
|
||||
error_text = s.read()
|
||||
raise CommandError("One or more models did not validate:\n%s" % error_text)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
raise NotImplementedError()
|
||||
|
||||
class AppCommand(BaseCommand):
|
||||
args = '[appname ...]'
|
||||
|
||||
def handle(self, *app_labels, **options):
|
||||
from django.db import models
|
||||
if not app_labels:
|
||||
raise CommandError('Enter at least one appname.')
|
||||
try:
|
||||
app_list = [models.get_app(app_label) for app_label in app_labels]
|
||||
except (ImproperlyConfigured, ImportError), e:
|
||||
raise CommandError("%s. Are you sure your INSTALLED_APPS setting is correct?" % e)
|
||||
output = []
|
||||
for app in app_list:
|
||||
app_output = self.handle_app(app, **options)
|
||||
if app_output:
|
||||
output.append(app_output)
|
||||
return '\n'.join(output)
|
||||
|
||||
def handle_app(self, app, **options):
|
||||
raise NotImplementedError()
|
||||
|
||||
class LabelCommand(BaseCommand):
|
||||
args = '[label ...]'
|
||||
label = 'label'
|
||||
|
||||
def handle(self, *labels, **options):
|
||||
if not labels:
|
||||
raise CommandError('Enter at least one %s.' % self.label)
|
||||
|
||||
output = []
|
||||
for label in labels:
|
||||
label_output = self.handle_label(label, **options)
|
||||
if label_output:
|
||||
output.append(label_output)
|
||||
return '\n'.join(output)
|
||||
|
||||
def handle_label(self, label, **options):
|
||||
raise NotImplementedError()
|
||||
|
||||
class NoArgsCommand(BaseCommand):
|
||||
args = ''
|
||||
|
||||
def handle(self, *args, **options):
|
||||
from django.db import models
|
||||
if len(args) != 0:
|
||||
raise CommandError("Command doesn't accept any arguments")
|
||||
|
||||
return self.handle_noargs(**options)
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
raise NotImplementedError()
|
||||
|
||||
def copy_helper(style, app_or_project, name, directory, other_name=''):
|
||||
import django
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
other = {'project': 'app', 'app': 'project'}[app_or_project]
|
||||
if not re.search(r'^\w+$', name): # If it's not a valid directory name.
|
||||
raise CommandError("%r is not a valid %s name. Please use only numbers, letters and underscores." % (name, app_or_project))
|
||||
top_dir = os.path.join(directory, name)
|
||||
try:
|
||||
os.mkdir(top_dir)
|
||||
except OSError, e:
|
||||
raise CommandError(e)
|
||||
|
||||
# Determine where the app or project templates are. Use
|
||||
# django.__path__[0] because we don't know into which directory
|
||||
# django has been installed.
|
||||
template_dir = os.path.join(django.__path__[0], 'conf', '%s_template' % app_or_project)
|
||||
|
||||
for d, subdirs, files in os.walk(template_dir):
|
||||
relative_dir = d[len(template_dir)+1:].replace('%s_name' % app_or_project, name)
|
||||
if relative_dir:
|
||||
os.mkdir(os.path.join(top_dir, relative_dir))
|
||||
for i, subdir in enumerate(subdirs):
|
||||
if subdir.startswith('.'):
|
||||
del subdirs[i]
|
||||
for f in files:
|
||||
if f.endswith('.pyc'):
|
||||
continue
|
||||
path_old = os.path.join(d, f)
|
||||
path_new = os.path.join(top_dir, relative_dir, f.replace('%s_name' % app_or_project, name))
|
||||
fp_old = open(path_old, 'r')
|
||||
fp_new = open(path_new, 'w')
|
||||
fp_new.write(fp_old.read().replace('{{ %s_name }}' % app_or_project, name).replace('{{ %s_name }}' % other, other_name))
|
||||
fp_old.close()
|
||||
fp_new.close()
|
||||
try:
|
||||
shutil.copymode(path_old, path_new)
|
||||
except OSError:
|
||||
sys.stderr.write(style.NOTICE("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new))
|
28
django/core/management/color.py
Normal file
28
django/core/management/color.py
Normal file
@ -0,0 +1,28 @@
|
||||
"""
|
||||
Sets up the terminal color scheme.
|
||||
"""
|
||||
|
||||
from django.utils import termcolors
|
||||
import sys
|
||||
|
||||
def color_style():
|
||||
"Returns a Style object with the Django color scheme."
|
||||
if sys.platform == 'win32' or sys.platform == 'Pocket PC' or not sys.stdout.isatty():
|
||||
return no_style()
|
||||
class dummy: pass
|
||||
style = dummy()
|
||||
style.ERROR = termcolors.make_style(fg='red', opts=('bold',))
|
||||
style.ERROR_OUTPUT = termcolors.make_style(fg='red', opts=('bold',))
|
||||
style.NOTICE = termcolors.make_style(fg='red')
|
||||
style.SQL_FIELD = termcolors.make_style(fg='green', opts=('bold',))
|
||||
style.SQL_COLTYPE = termcolors.make_style(fg='green')
|
||||
style.SQL_KEYWORD = termcolors.make_style(fg='yellow')
|
||||
style.SQL_TABLE = termcolors.make_style(opts=('bold',))
|
||||
return style
|
||||
|
||||
def no_style():
|
||||
"Returns a Style object that has no colors."
|
||||
class dummy:
|
||||
def __getattr__(self, attr):
|
||||
return lambda x: x
|
||||
return dummy()
|
0
django/core/management/commands/__init__.py
Normal file
0
django/core/management/commands/__init__.py
Normal file
33
django/core/management/commands/adminindex.py
Normal file
33
django/core/management/commands/adminindex.py
Normal file
@ -0,0 +1,33 @@
|
||||
from django.core.management.base import AppCommand
|
||||
from django.utils.text import capfirst
|
||||
|
||||
MODULE_TEMPLATE = ''' {%% if perms.%(app)s.%(addperm)s or perms.%(app)s.%(changeperm)s %%}
|
||||
<tr>
|
||||
<th>{%% if perms.%(app)s.%(changeperm)s %%}<a href="%(app)s/%(mod)s/">{%% endif %%}%(name)s{%% if perms.%(app)s.%(changeperm)s %%}</a>{%% endif %%}</th>
|
||||
<td class="x50">{%% if perms.%(app)s.%(addperm)s %%}<a href="%(app)s/%(mod)s/add/" class="addlink">{%% endif %%}Add{%% if perms.%(app)s.%(addperm)s %%}</a>{%% endif %%}</td>
|
||||
<td class="x75">{%% if perms.%(app)s.%(changeperm)s %%}<a href="%(app)s/%(mod)s/" class="changelink">{%% endif %%}Change{%% if perms.%(app)s.%(changeperm)s %%}</a>{%% endif %%}</td>
|
||||
</tr>
|
||||
{%% endif %%}'''
|
||||
|
||||
class Command(AppCommand):
|
||||
help = 'Prints the admin-index template snippet for the given app name(s).'
|
||||
|
||||
def handle_app(self, app, **options):
|
||||
from django.db.models import get_models
|
||||
output = []
|
||||
app_models = get_models(app)
|
||||
app_label = app_models[0]._meta.app_label
|
||||
output.append('{%% if perms.%s %%}' % app_label)
|
||||
output.append('<div class="module"><h2>%s</h2><table>' % app_label.title())
|
||||
for model in app_models:
|
||||
if model._meta.admin:
|
||||
output.append(MODULE_TEMPLATE % {
|
||||
'app': app_label,
|
||||
'mod': model._meta.module_name,
|
||||
'name': capfirst(model._meta.verbose_name_plural),
|
||||
'addperm': model._meta.get_add_permission(),
|
||||
'changeperm': model._meta.get_change_permission(),
|
||||
})
|
||||
output.append('</table></div>')
|
||||
output.append('{% endif %}')
|
||||
return '\n'.join(output)
|
41
django/core/management/commands/createcachetable.py
Normal file
41
django/core/management/commands/createcachetable.py
Normal file
@ -0,0 +1,41 @@
|
||||
from django.core.management.base import LabelCommand
|
||||
|
||||
class Command(LabelCommand):
|
||||
help = "Creates the table needed to use the SQL cache backend."
|
||||
args = "[tablename]"
|
||||
label = 'tablename'
|
||||
|
||||
requires_model_validation = False
|
||||
|
||||
def handle_label(self, tablename, **options):
|
||||
from django.db import backend, connection, transaction, models
|
||||
fields = (
|
||||
# "key" is a reserved word in MySQL, so use "cache_key" instead.
|
||||
models.CharField(name='cache_key', max_length=255, unique=True, primary_key=True),
|
||||
models.TextField(name='value'),
|
||||
models.DateTimeField(name='expires', db_index=True),
|
||||
)
|
||||
table_output = []
|
||||
index_output = []
|
||||
for f in fields:
|
||||
field_output = [backend.quote_name(f.name), f.db_type()]
|
||||
field_output.append("%sNULL" % (not f.null and "NOT " or ""))
|
||||
if f.unique:
|
||||
field_output.append("UNIQUE")
|
||||
if f.primary_key:
|
||||
field_output.append("PRIMARY KEY")
|
||||
if f.db_index:
|
||||
unique = f.unique and "UNIQUE " or ""
|
||||
index_output.append("CREATE %sINDEX %s_%s ON %s (%s);" % \
|
||||
(unique, tablename, f.name, backend.quote_name(tablename),
|
||||
backend.quote_name(f.name)))
|
||||
table_output.append(" ".join(field_output))
|
||||
full_statement = ["CREATE TABLE %s (" % backend.quote_name(tablename)]
|
||||
for i, line in enumerate(table_output):
|
||||
full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
|
||||
full_statement.append(');')
|
||||
curs = connection.cursor()
|
||||
curs.execute("\n".join(full_statement))
|
||||
for statement in index_output:
|
||||
curs.execute(statement)
|
||||
transaction.commit_unless_managed()
|
10
django/core/management/commands/dbshell.py
Normal file
10
django/core/management/commands/dbshell.py
Normal file
@ -0,0 +1,10 @@
|
||||
from django.core.management.base import NoArgsCommand
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
help = "Runs the command-line client for the current DATABASE_ENGINE."
|
||||
|
||||
requires_model_validation = False
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
from django.db import runshell
|
||||
runshell()
|
32
django/core/management/commands/diffsettings.py
Normal file
32
django/core/management/commands/diffsettings.py
Normal file
@ -0,0 +1,32 @@
|
||||
from django.core.management.base import NoArgsCommand
|
||||
|
||||
def module_to_dict(module, omittable=lambda k: k.startswith('_')):
|
||||
"Converts a module namespace to a Python dictionary. Used by get_settings_diff."
|
||||
return dict([(k, repr(v)) for k, v in module.__dict__.items() if not omittable(k)])
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
help = """Displays differences between the current settings.py and Django's
|
||||
default settings. Settings that don't appear in the defaults are
|
||||
followed by "###"."""
|
||||
|
||||
requires_model_validation = False
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
# Inspired by Postfix's "postconf -n".
|
||||
from django.conf import settings, global_settings
|
||||
|
||||
# Because settings are imported lazily, we need to explicitly load them.
|
||||
settings._import_settings()
|
||||
|
||||
user_settings = module_to_dict(settings._target)
|
||||
default_settings = module_to_dict(global_settings)
|
||||
|
||||
output = []
|
||||
keys = user_settings.keys()
|
||||
keys.sort()
|
||||
for key in keys:
|
||||
if key not in default_settings:
|
||||
output.append("%s = %s ###" % (key, user_settings[key]))
|
||||
elif user_settings[key] != default_settings[key]:
|
||||
output.append("%s = %s" % (key, user_settings[key]))
|
||||
print '\n'.join(output)
|
33
django/core/management/commands/dumpdata.py
Normal file
33
django/core/management/commands/dumpdata.py
Normal file
@ -0,0 +1,33 @@
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Output the contents of the database as a fixture of the given format.'
|
||||
args = '[--format] [--indent] [appname ...]'
|
||||
|
||||
def handle(self, *app_labels, **options):
|
||||
from django.db.models import get_app, get_apps, get_models
|
||||
from django.core import serializers
|
||||
|
||||
format = options.get('format', 'json')
|
||||
indent = options.get('indent', None)
|
||||
|
||||
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:
|
||||
raise CommandError("Unknown serialization format: %s" % 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:
|
||||
raise CommandError("Unable to serialize database: %s" % e)
|
64
django/core/management/commands/flush.py
Normal file
64
django/core/management/commands/flush.py
Normal file
@ -0,0 +1,64 @@
|
||||
from django.core.management.base import NoArgsCommand, CommandError
|
||||
from django.core.management.color import no_style
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
help = "Executes ``sqlflush`` on the current database."
|
||||
args = '[--verbosity] [--noinput]'
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
from django.conf import settings
|
||||
from django.db import connection, transaction, models
|
||||
from django.dispatch import dispatcher
|
||||
from django.core.management.sql import sql_flush, emit_post_sync_signal
|
||||
|
||||
verbosity = int(options.get('verbosity', 1))
|
||||
interactive = options.get('interactive')
|
||||
|
||||
self.style = no_style()
|
||||
|
||||
# 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 = sql_flush(self.style)
|
||||
|
||||
if interactive:
|
||||
confirm = raw_input("""You have requested a flush of the database.
|
||||
This will IRREVERSIBLY DESTROY all data currently in the %r 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: """ % settings.DATABASE_NAME)
|
||||
else:
|
||||
confirm = 'yes'
|
||||
|
||||
if confirm == 'yes':
|
||||
try:
|
||||
cursor = connection.cursor()
|
||||
for sql in sql_list:
|
||||
cursor.execute(sql)
|
||||
except Exception, e:
|
||||
transaction.rollback_unless_managed()
|
||||
raise CommandError("""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: %s""" % (settings.DATABASE_NAME, e))
|
||||
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.
|
||||
from django.core.management import call_command
|
||||
call_command('loaddata', 'initial_data', **options)
|
||||
|
||||
else:
|
||||
print "Flush cancelled."
|
120
django/core/management/commands/inspectdb.py
Normal file
120
django/core/management/commands/inspectdb.py
Normal file
@ -0,0 +1,120 @@
|
||||
from django.core.management.base import NoArgsCommand, CommandError
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
help = "Introspects the database tables in the given database and outputs a Django model module."
|
||||
|
||||
requires_model_validation = False
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
try:
|
||||
for line in self.handle_inspection():
|
||||
print line
|
||||
except NotImplementedError:
|
||||
raise CommandError("Database inspection isn't supported for the currently selected database backend.")
|
||||
|
||||
def handle_inspection(self):
|
||||
from django.db import connection, get_introspection_module
|
||||
import keyword
|
||||
|
||||
introspection_module = get_introspection_module()
|
||||
|
||||
table2model = lambda table_name: table_name.title().replace('_', '')
|
||||
|
||||
cursor = connection.cursor()
|
||||
yield "# This is an auto-generated Django model module."
|
||||
yield "# You'll have to do the following manually to clean this up:"
|
||||
yield "# * Rearrange models' order"
|
||||
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 sqlcustom [appname]'"
|
||||
yield "# into your database."
|
||||
yield ''
|
||||
yield 'from django.db import models'
|
||||
yield ''
|
||||
for table_name in introspection_module.get_table_list(cursor):
|
||||
yield 'class %s(models.Model):' % table2model(table_name)
|
||||
try:
|
||||
relations = introspection_module.get_relations(cursor, table_name)
|
||||
except NotImplementedError:
|
||||
relations = {}
|
||||
try:
|
||||
indexes = introspection_module.get_indexes(cursor, table_name)
|
||||
except NotImplementedError:
|
||||
indexes = {}
|
||||
for i, row in enumerate(introspection_module.get_table_description(cursor, table_name)):
|
||||
att_name = row[0].lower()
|
||||
comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
|
||||
extra_params = {} # Holds Field parameters such as 'db_column'.
|
||||
|
||||
if ' ' in att_name:
|
||||
extra_params['db_column'] = att_name
|
||||
att_name = att_name.replace(' ', '')
|
||||
comment_notes.append('Field renamed to remove spaces.')
|
||||
if keyword.iskeyword(att_name):
|
||||
extra_params['db_column'] = att_name
|
||||
att_name += '_field'
|
||||
comment_notes.append('Field renamed because it was a Python reserved word.')
|
||||
|
||||
if i in relations:
|
||||
rel_to = relations[i][1] == table_name and "'self'" or table2model(relations[i][1])
|
||||
field_type = 'ForeignKey(%s' % rel_to
|
||||
if att_name.endswith('_id'):
|
||||
att_name = att_name[:-3]
|
||||
else:
|
||||
extra_params['db_column'] = att_name
|
||||
else:
|
||||
try:
|
||||
field_type = introspection_module.DATA_TYPES_REVERSE[row[1]]
|
||||
except KeyError:
|
||||
field_type = 'TextField'
|
||||
comment_notes.append('This field type is a guess.')
|
||||
|
||||
# This is a hook for DATA_TYPES_REVERSE to return a tuple of
|
||||
# (field_type, extra_params_dict).
|
||||
if type(field_type) is tuple:
|
||||
field_type, new_params = field_type
|
||||
extra_params.update(new_params)
|
||||
|
||||
# Add max_length for all CharFields.
|
||||
if field_type == 'CharField' and row[3]:
|
||||
extra_params['max_length'] = row[3]
|
||||
|
||||
if field_type == 'DecimalField':
|
||||
extra_params['max_digits'] = row[4]
|
||||
extra_params['decimal_places'] = row[5]
|
||||
|
||||
# Add primary_key and unique, if necessary.
|
||||
column_name = extra_params.get('db_column', att_name)
|
||||
if column_name in indexes:
|
||||
if indexes[column_name]['primary_key']:
|
||||
extra_params['primary_key'] = True
|
||||
elif indexes[column_name]['unique']:
|
||||
extra_params['unique'] = True
|
||||
|
||||
field_type += '('
|
||||
|
||||
# Don't output 'id = meta.AutoField(primary_key=True)', because
|
||||
# that's assumed if it doesn't exist.
|
||||
if att_name == 'id' and field_type == 'AutoField(' and extra_params == {'primary_key': True}:
|
||||
continue
|
||||
|
||||
# Add 'null' and 'blank', if the 'null_ok' flag was present in the
|
||||
# table description.
|
||||
if row[6]: # If it's NULL...
|
||||
extra_params['blank'] = True
|
||||
if not field_type in ('TextField(', 'CharField('):
|
||||
extra_params['null'] = True
|
||||
|
||||
field_desc = '%s = models.%s' % (att_name, field_type)
|
||||
if extra_params:
|
||||
if not field_desc.endswith('('):
|
||||
field_desc += ', '
|
||||
field_desc += ', '.join(['%s=%r' % (k, v) for k, v in extra_params.items()])
|
||||
field_desc += ')'
|
||||
if comment_notes:
|
||||
field_desc += ' # ' + ' '.join(comment_notes)
|
||||
yield ' %s' % field_desc
|
||||
yield ' class Meta:'
|
||||
yield ' db_table = %r' % table_name
|
||||
yield ''
|
123
django/core/management/commands/loaddata.py
Normal file
123
django/core/management/commands/loaddata.py
Normal file
@ -0,0 +1,123 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.core.management.color import no_style
|
||||
import sys
|
||||
import os
|
||||
|
||||
try:
|
||||
set
|
||||
except NameError:
|
||||
from sets import Set as set # Python 2.3 fallback
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Installs the named fixture(s) in the database.'
|
||||
args = "[--verbosity] fixture, fixture, ..."
|
||||
|
||||
def handle(self, *fixture_labels, **options):
|
||||
from django.db.models import get_apps
|
||||
from django.core import serializers
|
||||
from django.db import connection, transaction, backend
|
||||
from django.conf import settings
|
||||
|
||||
self.style = no_style()
|
||||
|
||||
verbosity = int(options.get('verbosity', 1))
|
||||
|
||||
# Keep a count of the installed objects and fixtures
|
||||
count = [0, 0]
|
||||
models = set()
|
||||
|
||||
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:
|
||||
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]
|
||||
if format in serializers.get_serializer_formats():
|
||||
formats = [format]
|
||||
else:
|
||||
formats = []
|
||||
|
||||
if verbosity > 0:
|
||||
if formats:
|
||||
print "Loading '%s' fixtures..." % fixture_name
|
||||
else:
|
||||
print "Skipping fixture '%s': %s is not a known serialization format" % (fixture_name, format)
|
||||
|
||||
for fixture_dir in app_fixtures + list(settings.FIXTURE_DIRS) + ['']:
|
||||
if verbosity > 1:
|
||||
print "Checking %s for fixtures..." % humanize(fixture_dir)
|
||||
|
||||
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 self.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
|
||||
models.add(obj.object.__class__)
|
||||
obj.save()
|
||||
label_found = True
|
||||
except Exception, e:
|
||||
fixture.close()
|
||||
sys.stderr.write(
|
||||
self.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:
|
||||
sequence_sql = backend.get_sql_sequence_reset(self.style, models)
|
||||
if sequence_sql:
|
||||
if verbosity > 1:
|
||||
print "Resetting sequences"
|
||||
for line in sequence_sql:
|
||||
cursor.execute(line)
|
||||
|
||||
transaction.commit()
|
||||
transaction.leave_transaction_management()
|
||||
|
||||
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)
|
47
django/core/management/commands/reset.py
Normal file
47
django/core/management/commands/reset.py
Normal file
@ -0,0 +1,47 @@
|
||||
from django.core.management.base import AppCommand, CommandError
|
||||
from django.core.management.color import no_style
|
||||
|
||||
class Command(AppCommand):
|
||||
help = "Executes ``sqlreset`` for the given app(s) in the current database."
|
||||
args = '[--noinput] [appname ...]'
|
||||
|
||||
output_transaction = True
|
||||
|
||||
def handle_app(self, app, **options):
|
||||
from django.db import connection, transaction
|
||||
from django.conf import settings
|
||||
from django.core.management.sql import sql_reset
|
||||
|
||||
app_name = app.__name__.split('.')[-2]
|
||||
|
||||
self.style = no_style()
|
||||
|
||||
sql_list = sql_reset(app, self.style)
|
||||
|
||||
if options.get('interactive'):
|
||||
confirm = raw_input("""
|
||||
You have requested a database reset.
|
||||
This will IRREVERSIBLY DESTROY any data for
|
||||
the "%s" application in the database "%s".
|
||||
Are you sure you want to do this?
|
||||
|
||||
Type 'yes' to continue, or 'no' to cancel: """ % (app_name, settings.DATABASE_NAME))
|
||||
else:
|
||||
confirm = 'yes'
|
||||
|
||||
if confirm == 'yes':
|
||||
try:
|
||||
cursor = connection.cursor()
|
||||
for sql in sql_list:
|
||||
cursor.execute(sql)
|
||||
except Exception, e:
|
||||
transaction.rollback_unless_managed()
|
||||
raise CommandError("""Error: %s couldn't be reset. Possible reasons:
|
||||
* The database isn't running or isn't configured correctly.
|
||||
* At least one of the database tables doesn't exist.
|
||||
* The SQL was invalid.
|
||||
Hint: Look at the output of 'django-admin.py sqlreset %s'. That's the SQL this command wasn't able to run.
|
||||
The full error: %s""" % (app_name, app_name, e))
|
||||
transaction.commit_unless_managed()
|
||||
else:
|
||||
print "Reset cancelled."
|
16
django/core/management/commands/runfcgi.py
Normal file
16
django/core/management/commands/runfcgi.py
Normal file
@ -0,0 +1,16 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Runs this project as a FastCGI application. Requires flup."
|
||||
args = '[various KEY=val options, use `runfcgi help` for help]'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
from django.conf import settings
|
||||
from django.utils import translation
|
||||
# Activate the current language, because it won't get activated later.
|
||||
try:
|
||||
translation.activate(settings.LANGUAGE_CODE)
|
||||
except AttributeError:
|
||||
pass
|
||||
from django.core.servers.fastcgi import runfastcgi
|
||||
runfastcgi(args)
|
70
django/core/management/commands/runserver.py
Normal file
70
django/core/management/commands/runserver.py
Normal file
@ -0,0 +1,70 @@
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
import os
|
||||
import sys
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Starts a lightweight Web server for development."
|
||||
args = '[--noreload] [--adminmedia=ADMIN_MEDIA_PATH] [optional port number, or ipaddr:port]'
|
||||
|
||||
# Validation is called explicitly each time the server is reloaded.
|
||||
requires_model_validation = False
|
||||
|
||||
def handle(self, addrport='', *args, **options):
|
||||
import django
|
||||
from django.core.servers.basehttp import run, AdminMediaHandler, WSGIServerException
|
||||
from django.core.handlers.wsgi import WSGIHandler
|
||||
if len(args) != 0:
|
||||
raise CommandError('Usage is runserver %s' % self.args)
|
||||
if not addrport:
|
||||
addr = ''
|
||||
port = '8000'
|
||||
else:
|
||||
try:
|
||||
addr, port = addrport.split(':')
|
||||
except ValueError:
|
||||
addr, port = '', addrport
|
||||
if not addr:
|
||||
addr = '127.0.0.1'
|
||||
|
||||
if not port.isdigit():
|
||||
raise CommandError("%r is not a valid port number." % port)
|
||||
|
||||
use_reloader = options.get('use_reloader', True)
|
||||
admin_media_dir = options.get('admin_media_dir', '')
|
||||
shutdown_message = options.get('shutdown_message', '')
|
||||
quit_command = (sys.platform == 'win32') and 'CTRL-BREAK' or 'CONTROL-C'
|
||||
|
||||
def inner_run():
|
||||
from django.conf import settings
|
||||
print "Validating models..."
|
||||
self.validate()
|
||||
print "\nDjango version %s, using settings %r" % (django.get_version(), settings.SETTINGS_MODULE)
|
||||
print "Development server is running at http://%s:%s/" % (addr, port)
|
||||
print "Quit the server with %s." % quit_command
|
||||
try:
|
||||
path = admin_media_dir or django.__path__[0] + '/contrib/admin/media'
|
||||
handler = AdminMediaHandler(WSGIHandler(), path)
|
||||
run(addr, int(port), handler)
|
||||
except WSGIServerException, e:
|
||||
# Use helpful error messages instead of ugly tracebacks.
|
||||
ERRORS = {
|
||||
13: "You don't have permission to access that port.",
|
||||
98: "That port is already in use.",
|
||||
99: "That IP address can't be assigned-to.",
|
||||
}
|
||||
try:
|
||||
error_text = ERRORS[e.args[0].args[0]]
|
||||
except (AttributeError, KeyError):
|
||||
error_text = str(e)
|
||||
sys.stderr.write(self.style.ERROR("Error: %s" % error_text) + '\n')
|
||||
# Need to use an OS exit because sys.exit doesn't work in a thread
|
||||
os._exit(1)
|
||||
except KeyboardInterrupt:
|
||||
if shutdown_message:
|
||||
print shutdown_message
|
||||
sys.exit(0)
|
||||
if use_reloader:
|
||||
from django.utils import autoreload
|
||||
autoreload.main(inner_run)
|
||||
else:
|
||||
inner_run()
|
42
django/core/management/commands/shell.py
Normal file
42
django/core/management/commands/shell.py
Normal file
@ -0,0 +1,42 @@
|
||||
from django.core.management.base import NoArgsCommand
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
help = "Runs a Python interactive interpreter. Tries to use IPython, if it's available."
|
||||
args = '[--plain]'
|
||||
|
||||
requires_model_validation = False
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
# XXX: (Temporary) workaround for ticket #1796: force early loading of all
|
||||
# models from installed apps.
|
||||
from django.db.models.loading import get_models
|
||||
loaded_models = get_models()
|
||||
|
||||
use_plain = options.get('plain', False)
|
||||
|
||||
try:
|
||||
if use_plain:
|
||||
# Don't bother loading IPython, because the user wants plain Python.
|
||||
raise ImportError
|
||||
import IPython
|
||||
# Explicitly pass an empty list as arguments, because otherwise IPython
|
||||
# would use sys.argv from this script.
|
||||
shell = IPython.Shell.IPShell(argv=[])
|
||||
shell.mainloop()
|
||||
except ImportError:
|
||||
import code
|
||||
# Set up a dictionary to serve as the environment for the shell, so
|
||||
# that tab completion works on objects that are imported at runtime.
|
||||
# See ticket 5082.
|
||||
imported_objects = {}
|
||||
try: # Try activating rlcompleter, because it's handy.
|
||||
import readline
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
# We don't have to wrap the following import in a 'try', because
|
||||
# we already know 'readline' was imported successfully.
|
||||
import rlcompleter
|
||||
readline.set_completer(rlcompleter.Completer(imported_objects).complete)
|
||||
readline.parse_and_bind("tab:complete")
|
||||
code.interact(local=imported_objects)
|
10
django/core/management/commands/sql.py
Normal file
10
django/core/management/commands/sql.py
Normal file
@ -0,0 +1,10 @@
|
||||
from django.core.management.base import AppCommand
|
||||
|
||||
class Command(AppCommand):
|
||||
help = "Prints the CREATE TABLE SQL statements for the given app name(s)."
|
||||
|
||||
output_transaction = True
|
||||
|
||||
def handle_app(self, app, **options):
|
||||
from django.core.management.sql import sql_create
|
||||
return '\n'.join(sql_create(app, self.style))
|
10
django/core/management/commands/sqlall.py
Normal file
10
django/core/management/commands/sqlall.py
Normal file
@ -0,0 +1,10 @@
|
||||
from django.core.management.base import AppCommand
|
||||
|
||||
class Command(AppCommand):
|
||||
help = "Prints the CREATE TABLE, initial-data and CREATE INDEX SQL statements for the given model module name(s)."
|
||||
|
||||
output_transaction = True
|
||||
|
||||
def handle_app(self, app, **options):
|
||||
from django.core.management.sql import sql_all
|
||||
return '\n'.join(sql_all(app, self.style))
|
10
django/core/management/commands/sqlclear.py
Normal file
10
django/core/management/commands/sqlclear.py
Normal file
@ -0,0 +1,10 @@
|
||||
from django.core.management.base import AppCommand
|
||||
|
||||
class Command(AppCommand):
|
||||
help = "Prints the DROP TABLE SQL statements for the given app name(s)."
|
||||
|
||||
output_transaction = True
|
||||
|
||||
def handle_app(self, app, **options):
|
||||
from django.core.management.sql import sql_delete
|
||||
return '\n'.join(sql_delete(app, self.style))
|
10
django/core/management/commands/sqlcustom.py
Normal file
10
django/core/management/commands/sqlcustom.py
Normal file
@ -0,0 +1,10 @@
|
||||
from django.core.management.base import AppCommand
|
||||
|
||||
class Command(AppCommand):
|
||||
help = "Prints the custom table modifying SQL statements for the given app name(s)."
|
||||
|
||||
output_transaction = True
|
||||
|
||||
def handle_app(self, app, **options):
|
||||
from django.core.management.sql import sql_custom
|
||||
return '\n'.join(sql_custom(app))
|
10
django/core/management/commands/sqlflush.py
Normal file
10
django/core/management/commands/sqlflush.py
Normal file
@ -0,0 +1,10 @@
|
||||
from django.core.management.base import NoArgsCommand
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
help = "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."
|
||||
|
||||
output_transaction = True
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
from django.core.management.sql import sql_flush
|
||||
return '\n'.join(sql_flush(self.style))
|
10
django/core/management/commands/sqlindexes.py
Normal file
10
django/core/management/commands/sqlindexes.py
Normal file
@ -0,0 +1,10 @@
|
||||
from django.core.management.base import AppCommand
|
||||
|
||||
class Command(AppCommand):
|
||||
help = "Prints the CREATE INDEX SQL statements for the given model module name(s)."
|
||||
|
||||
output_transaction = True
|
||||
|
||||
def handle_app(self, app, **options):
|
||||
from django.core.management.sql import sql_indexes
|
||||
return '\n'.join(sql_indexes(app, self.style))
|
7
django/core/management/commands/sqlinitialdata.py
Normal file
7
django/core/management/commands/sqlinitialdata.py
Normal file
@ -0,0 +1,7 @@
|
||||
from django.core.management.base import AppCommand, CommandError
|
||||
|
||||
class Command(AppCommand):
|
||||
help = "RENAMED: see 'sqlcustom'"
|
||||
|
||||
def handle(self, *apps, **options):
|
||||
raise CommandError("This command has been renamed. Use the 'sqlcustom' command instead.")
|
10
django/core/management/commands/sqlreset.py
Normal file
10
django/core/management/commands/sqlreset.py
Normal file
@ -0,0 +1,10 @@
|
||||
from django.core.management.base import AppCommand
|
||||
|
||||
class Command(AppCommand):
|
||||
help = "Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given app name(s)."
|
||||
|
||||
output_transaction = True
|
||||
|
||||
def handle_app(self, app, **options):
|
||||
from django.core.management.sql import sql_reset
|
||||
return '\n'.join(sql_reset(app, self.style))
|
9
django/core/management/commands/sqlsequencereset.py
Normal file
9
django/core/management/commands/sqlsequencereset.py
Normal file
@ -0,0 +1,9 @@
|
||||
from django.core.management.base import AppCommand
|
||||
|
||||
class Command(AppCommand):
|
||||
help = 'Prints the SQL statements for resetting sequences for the given app name(s).'
|
||||
output_transaction = True
|
||||
|
||||
def handle_app(self, app, **options):
|
||||
from django.db import backend, models
|
||||
return '\n'.join(backend.get_sql_sequence_reset(self.style, models.get_models(app)))
|
34
django/core/management/commands/startapp.py
Normal file
34
django/core/management/commands/startapp.py
Normal file
@ -0,0 +1,34 @@
|
||||
from django.core.management.base import copy_helper, CommandError, LabelCommand
|
||||
import os
|
||||
|
||||
class Command(LabelCommand):
|
||||
help = "Creates a Django app directory structure for the given app name in the current directory."
|
||||
args = "[appname]"
|
||||
label = 'application name'
|
||||
|
||||
requires_model_validation = False
|
||||
# Can't import settings during this command, because they haven't
|
||||
# necessarily been created.
|
||||
can_import_settings = False
|
||||
|
||||
def handle_label(self, app_name, directory=None, **options):
|
||||
if directory is None:
|
||||
directory = os.getcwd()
|
||||
# Determine the project_name a bit naively -- by looking at the name of
|
||||
# the parent directory.
|
||||
project_dir = os.path.normpath(os.path.join(directory, '..'))
|
||||
parent_dir = os.path.basename(project_dir)
|
||||
project_name = os.path.basename(directory)
|
||||
if app_name == project_name:
|
||||
raise CommandError("You cannot create an app with the same name (%r) as your project." % app_name)
|
||||
copy_helper(self.style, 'app', app_name, directory, parent_dir)
|
||||
|
||||
class ProjectCommand(Command):
|
||||
help = "Creates a Django app directory structure for the given app name in this project's directory."
|
||||
|
||||
def __init__(self, project_directory):
|
||||
super(ProjectCommand, self).__init__()
|
||||
self.project_directory = project_directory
|
||||
|
||||
def handle_label(self, app_name, **options):
|
||||
super(ProjectCommand, self).handle_label(app_name, self.project_directory, **options)
|
40
django/core/management/commands/startproject.py
Normal file
40
django/core/management/commands/startproject.py
Normal file
@ -0,0 +1,40 @@
|
||||
from django.core.management.base import copy_helper, CommandError, LabelCommand
|
||||
import os
|
||||
import re
|
||||
from random import choice
|
||||
|
||||
INVALID_PROJECT_NAMES = ('django', 'site', 'test')
|
||||
|
||||
class Command(LabelCommand):
|
||||
help = "Creates a Django project directory structure for the given project name in the current directory."
|
||||
args = "[projectname]"
|
||||
label = 'project name'
|
||||
|
||||
requires_model_validation = False
|
||||
# Can't import settings during this command, because they haven't
|
||||
# necessarily been created.
|
||||
can_import_settings = False
|
||||
|
||||
def handle_label(self, project_name, **options):
|
||||
# Determine the project_name a bit naively -- by looking at the name of
|
||||
# the parent directory.
|
||||
directory = os.getcwd()
|
||||
|
||||
if project_name in INVALID_PROJECT_NAMES:
|
||||
raise CommandError("%r conflicts with the name of an existing Python module and cannot be used as a project name. Please try another name." % project_name)
|
||||
|
||||
copy_helper(self.style, 'project', project_name, directory)
|
||||
|
||||
# Create a random SECRET_KEY hash, and put it in the main settings.
|
||||
main_settings_file = os.path.join(directory, project_name, 'settings.py')
|
||||
settings_contents = open(main_settings_file, 'r').read()
|
||||
|
||||
# If settings.py was copied from a read-only source, make it writeable.
|
||||
if not os.access(main_settings_file, os.W_OK):
|
||||
os.chmod(main_settings_file, 0600)
|
||||
|
||||
fp = open(main_settings_file, 'w')
|
||||
secret_key = ''.join([choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') for i in range(50)])
|
||||
settings_contents = re.sub(r"(?<=SECRET_KEY = ')'", secret_key + "'", settings_contents)
|
||||
fp.write(settings_contents)
|
||||
fp.close()
|
130
django/core/management/commands/syncdb.py
Normal file
130
django/core/management/commands/syncdb.py
Normal file
@ -0,0 +1,130 @@
|
||||
from django.core.management.base import NoArgsCommand
|
||||
from django.core.management.color import no_style
|
||||
import sys
|
||||
|
||||
try:
|
||||
set
|
||||
except NameError:
|
||||
from sets import Set as set # Python 2.3 fallback
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
help = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
|
||||
args = '[--verbosity] [--noinput]'
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
from django.db import backend, connection, transaction, models
|
||||
from django.conf import settings
|
||||
from django.core.management.sql import table_list, installed_models, sql_model_create, sql_for_pending_references, many_to_many_sql_for_model, custom_sql_for_model, sql_indexes_for_model, emit_post_sync_signal
|
||||
|
||||
verbosity = int(options.get('verbosity', 1))
|
||||
interactive = options.get('interactive')
|
||||
|
||||
self.style = no_style()
|
||||
|
||||
# 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
|
||||
|
||||
cursor = connection.cursor()
|
||||
|
||||
# Get a list of all existing database tables,
|
||||
# so we know what needs to be added.
|
||||
table_list = table_list()
|
||||
if backend.uses_case_insensitive_names:
|
||||
table_name_converter = str.upper
|
||||
else:
|
||||
table_name_converter = lambda x: x
|
||||
|
||||
# Get a list of already installed *models* so that references work right.
|
||||
seen_models = installed_models(table_list)
|
||||
created_models = set()
|
||||
pending_references = {}
|
||||
|
||||
# Create the tables for each model
|
||||
for app in models.get_apps():
|
||||
app_name = app.__name__.split('.')[-2]
|
||||
model_list = models.get_models(app)
|
||||
for model in model_list:
|
||||
# Create the model's database table, if it doesn't already exist.
|
||||
if verbosity >= 2:
|
||||
print "Processing %s.%s model" % (app_name, model._meta.object_name)
|
||||
if table_name_converter(model._meta.db_table) in table_list:
|
||||
continue
|
||||
sql, references = sql_model_create(model, self.style, seen_models)
|
||||
seen_models.add(model)
|
||||
created_models.add(model)
|
||||
for refto, refs in references.items():
|
||||
pending_references.setdefault(refto, []).extend(refs)
|
||||
sql.extend(sql_for_pending_references(model, self.style, pending_references))
|
||||
if verbosity >= 1:
|
||||
print "Creating table %s" % model._meta.db_table
|
||||
for statement in sql:
|
||||
cursor.execute(statement)
|
||||
table_list.append(table_name_converter(model._meta.db_table))
|
||||
|
||||
# Create the m2m tables. This must be done after all tables have been created
|
||||
# to ensure that all referred tables will exist.
|
||||
for app in models.get_apps():
|
||||
app_name = app.__name__.split('.')[-2]
|
||||
model_list = models.get_models(app)
|
||||
for model in model_list:
|
||||
if model in created_models:
|
||||
sql = many_to_many_sql_for_model(model, self.style)
|
||||
if sql:
|
||||
if verbosity >= 2:
|
||||
print "Creating many-to-many tables for %s.%s model" % (app_name, model._meta.object_name)
|
||||
for statement in sql:
|
||||
cursor.execute(statement)
|
||||
|
||||
transaction.commit_unless_managed()
|
||||
|
||||
# Send the post_syncdb signal, so individual apps can do whatever they need
|
||||
# to do at this point.
|
||||
emit_post_sync_signal(created_models, verbosity, interactive)
|
||||
|
||||
# Install custom SQL for the app (but only if this
|
||||
# is a model we've just created)
|
||||
for app in models.get_apps():
|
||||
app_name = app.__name__.split('.')[-2]
|
||||
for model in models.get_models(app):
|
||||
if model in created_models:
|
||||
custom_sql = custom_sql_for_model(model)
|
||||
if custom_sql:
|
||||
if verbosity >= 1:
|
||||
print "Installing custom SQL for %s.%s model" % (app_name, model._meta.object_name)
|
||||
try:
|
||||
for sql in custom_sql:
|
||||
cursor.execute(sql)
|
||||
except Exception, e:
|
||||
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:
|
||||
transaction.commit_unless_managed()
|
||||
|
||||
# Install SQL indicies for all newly created models
|
||||
for app in models.get_apps():
|
||||
app_name = app.__name__.split('.')[-2]
|
||||
for model in models.get_models(app):
|
||||
if model in created_models:
|
||||
index_sql = sql_indexes_for_model(model, self.style)
|
||||
if index_sql:
|
||||
if verbosity >= 1:
|
||||
print "Installing index for %s.%s model" % (app_name, model._meta.object_name)
|
||||
try:
|
||||
for sql in index_sql:
|
||||
cursor.execute(sql)
|
||||
except Exception, e:
|
||||
sys.stderr.write("Failed to install index for %s.%s model: %s" % \
|
||||
(app_name, model._meta.object_name, e))
|
||||
transaction.rollback_unless_managed()
|
||||
else:
|
||||
transaction.commit_unless_managed()
|
||||
|
||||
# Install the 'initialdata' fixture, using format discovery
|
||||
from django.core.management import call_command
|
||||
call_command('loaddata', 'initial_data', **options)
|
28
django/core/management/commands/test.py
Normal file
28
django/core/management/commands/test.py
Normal file
@ -0,0 +1,28 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
import sys
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Runs the test suite for the specified applications, or the entire site if no apps are specified.'
|
||||
args = '[--verbosity] [--noinput] [appname ...]'
|
||||
|
||||
requires_model_validation = False
|
||||
|
||||
def handle(self, *test_labels, **options):
|
||||
from django.conf import settings
|
||||
from django.db.models import get_app, get_apps
|
||||
|
||||
verbosity = int(options.get('verbosity', 1))
|
||||
interactive = options.get('interactive', True)
|
||||
|
||||
test_path = settings.TEST_RUNNER.split('.')
|
||||
# Allow for Python 2.5 relative paths
|
||||
if len(test_path) > 1:
|
||||
test_module_name = '.'.join(test_path[:-1])
|
||||
else:
|
||||
test_module_name = '.'
|
||||
test_module = __import__(test_module_name, {}, {}, test_path[-1])
|
||||
test_runner = getattr(test_module, test_path[-1])
|
||||
|
||||
failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive)
|
||||
if failures:
|
||||
sys.exit(failures)
|
26
django/core/management/commands/testserver.py
Normal file
26
django/core/management/commands/testserver.py
Normal file
@ -0,0 +1,26 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Runs a development server with data from the given fixture(s).'
|
||||
args = '[fixture ...]'
|
||||
|
||||
requires_model_validation = False
|
||||
|
||||
def handle(self, *fixture_labels, **options):
|
||||
from django.conf import settings
|
||||
from django.core.management import call_command
|
||||
from django.test.utils import create_test_db
|
||||
|
||||
verbosity = int(options.get('verbosity', 1))
|
||||
|
||||
# Create a test database.
|
||||
db_name = create_test_db(verbosity=verbosity)
|
||||
|
||||
# Import the fixture data into the test database.
|
||||
call_command('loaddata', *fixture_labels, **{'verbosity': verbosity})
|
||||
|
||||
# Run the development server. Turn off auto-reloading because it causes
|
||||
# a strange error -- it causes this handle() method to be called
|
||||
# multiple times.
|
||||
shutdown_message = '\nServer stopped.\nNote that the test database, %r, has not been deleted. You can explore it on your own.' % db_name
|
||||
call_command('runserver', shutdown_message=shutdown_message, use_reloader=False)
|
9
django/core/management/commands/validate.py
Normal file
9
django/core/management/commands/validate.py
Normal file
@ -0,0 +1,9 @@
|
||||
from django.core.management.base import NoArgsCommand
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
help = "Validates all installed models."
|
||||
|
||||
requires_model_validation = False
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
self.validate()
|
420
django/core/management/sql.py
Normal file
420
django/core/management/sql.py
Normal file
@ -0,0 +1,420 @@
|
||||
from django.core.management.base import CommandError
|
||||
import os
|
||||
import re
|
||||
|
||||
try:
|
||||
set
|
||||
except NameError:
|
||||
from sets import Set as set # Python 2.3 fallback
|
||||
|
||||
def table_list():
|
||||
"Returns a list of all table names that exist in the database."
|
||||
from django.db import connection, get_introspection_module
|
||||
cursor = connection.cursor()
|
||||
return get_introspection_module().get_table_list(cursor)
|
||||
|
||||
def installed_models(table_list):
|
||||
"Returns a set of all models that are installed, given a list of existing table names."
|
||||
from django.db import backend, models
|
||||
all_models = []
|
||||
for app in models.get_apps():
|
||||
for model in models.get_models(app):
|
||||
all_models.append(model)
|
||||
if backend.uses_case_insensitive_names:
|
||||
converter = lambda x: x.upper()
|
||||
else:
|
||||
converter = lambda x: x
|
||||
return set([m for m in all_models if converter(m._meta.db_table) in map(converter, table_list)])
|
||||
|
||||
def 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
|
||||
|
||||
def sql_create(app, style):
|
||||
"Returns a list of the CREATE TABLE SQL statements for the given app."
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
if settings.DATABASE_ENGINE == 'dummy':
|
||||
# This must be the "dummy" database backend, which means the user
|
||||
# hasn't set DATABASE_ENGINE.
|
||||
raise CommandError("Django doesn't know which syntax to use for your SQL statements,\n" +
|
||||
"because you haven't specified the DATABASE_ENGINE setting.\n" +
|
||||
"Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.")
|
||||
|
||||
# Get installed models, so we generate REFERENCES right.
|
||||
# We trim models from the current app so that the sqlreset command does not
|
||||
# generate invalid SQL (leaving models out of known_models is harmless, so
|
||||
# we can be conservative).
|
||||
app_models = models.get_models(app)
|
||||
final_output = []
|
||||
known_models = set([model for model in installed_models(table_list()) if model not in app_models])
|
||||
pending_references = {}
|
||||
|
||||
for model in app_models:
|
||||
output, references = sql_model_create(model, style, known_models)
|
||||
final_output.extend(output)
|
||||
for refto, refs in references.items():
|
||||
pending_references.setdefault(refto, []).extend(refs)
|
||||
final_output.extend(sql_for_pending_references(model, style, pending_references))
|
||||
# Keep track of the fact that we've created the table for this model.
|
||||
known_models.add(model)
|
||||
|
||||
# Create the many-to-many join tables.
|
||||
for model in app_models:
|
||||
final_output.extend(many_to_many_sql_for_model(model, style))
|
||||
|
||||
# Handle references to tables that are from other apps
|
||||
# but don't exist physically.
|
||||
not_installed_models = set(pending_references.keys())
|
||||
if not_installed_models:
|
||||
alter_sql = []
|
||||
for model in not_installed_models:
|
||||
alter_sql.extend(['-- ' + sql for sql in
|
||||
sql_for_pending_references(model, style, pending_references)])
|
||||
if alter_sql:
|
||||
final_output.append('-- The following references should be added but depend on non-existent tables:')
|
||||
final_output.extend(alter_sql)
|
||||
|
||||
return final_output
|
||||
|
||||
def sql_delete(app, style):
|
||||
"Returns a list of the DROP TABLE SQL statements for the given app."
|
||||
from django.db import backend, connection, models, get_introspection_module
|
||||
from django.db.backends.util import truncate_name
|
||||
introspection = get_introspection_module()
|
||||
|
||||
# This should work even if a connection isn't available
|
||||
try:
|
||||
cursor = connection.cursor()
|
||||
except:
|
||||
cursor = None
|
||||
|
||||
# Figure out which tables already exist
|
||||
if cursor:
|
||||
table_names = introspection.get_table_list(cursor)
|
||||
else:
|
||||
table_names = []
|
||||
if backend.uses_case_insensitive_names:
|
||||
table_name_converter = str.upper
|
||||
else:
|
||||
table_name_converter = lambda x: x
|
||||
|
||||
output = []
|
||||
|
||||
# Output DROP TABLE statements for standard application tables.
|
||||
to_delete = set()
|
||||
|
||||
references_to_delete = {}
|
||||
app_models = models.get_models(app)
|
||||
for model in app_models:
|
||||
if cursor and table_name_converter(model._meta.db_table) in table_names:
|
||||
# The table exists, so it needs to be dropped
|
||||
opts = model._meta
|
||||
for f in opts.fields:
|
||||
if f.rel and f.rel.to not in to_delete:
|
||||
references_to_delete.setdefault(f.rel.to, []).append( (model, f) )
|
||||
|
||||
to_delete.add(model)
|
||||
|
||||
for model in app_models:
|
||||
if cursor and table_name_converter(model._meta.db_table) in table_names:
|
||||
# Drop the table now
|
||||
output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
|
||||
style.SQL_TABLE(backend.quote_name(model._meta.db_table))))
|
||||
if backend.supports_constraints and model in references_to_delete:
|
||||
for rel_class, f in references_to_delete[model]:
|
||||
table = rel_class._meta.db_table
|
||||
col = f.column
|
||||
r_table = model._meta.db_table
|
||||
r_col = model._meta.get_field(f.rel.field_name).column
|
||||
r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))
|
||||
output.append('%s %s %s %s;' % \
|
||||
(style.SQL_KEYWORD('ALTER TABLE'),
|
||||
style.SQL_TABLE(backend.quote_name(table)),
|
||||
style.SQL_KEYWORD(backend.get_drop_foreignkey_sql()),
|
||||
style.SQL_FIELD(truncate_name(r_name, backend.get_max_name_length()))))
|
||||
del references_to_delete[model]
|
||||
if model._meta.has_auto_field and hasattr(backend, 'get_drop_sequence'):
|
||||
output.append(backend.get_drop_sequence(model._meta.db_table))
|
||||
|
||||
# Output DROP TABLE statements for many-to-many tables.
|
||||
for model in app_models:
|
||||
opts = model._meta
|
||||
for f in opts.many_to_many:
|
||||
if cursor and table_name_converter(f.m2m_db_table()) in table_names:
|
||||
output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
|
||||
style.SQL_TABLE(backend.quote_name(f.m2m_db_table()))))
|
||||
if hasattr(backend, 'get_drop_sequence'):
|
||||
output.append(backend.get_drop_sequence("%s_%s" % (model._meta.db_table, f.column)))
|
||||
|
||||
app_label = app_models[0]._meta.app_label
|
||||
|
||||
# Close database connection explicitly, in case this output is being piped
|
||||
# directly into a database client, to avoid locking issues.
|
||||
if cursor:
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
return output[::-1] # Reverse it, to deal with table dependencies.
|
||||
|
||||
def sql_reset(app, style):
|
||||
"Returns a list of the DROP TABLE SQL, then the CREATE TABLE SQL, for the given module."
|
||||
return sql_delete(app, style) + sql_all(app, style)
|
||||
|
||||
def sql_flush(style):
|
||||
"Returns a list of the SQL statements used to flush the database"
|
||||
from django.db import backend
|
||||
statements = backend.get_sql_flush(style, table_list(), sequence_list())
|
||||
return statements
|
||||
|
||||
def sql_custom(app):
|
||||
"Returns a list of the custom table modifying SQL statements for the given app."
|
||||
from django.db.models import get_models
|
||||
output = []
|
||||
|
||||
app_models = get_models(app)
|
||||
app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
|
||||
|
||||
for model in app_models:
|
||||
output.extend(custom_sql_for_model(model))
|
||||
|
||||
return output
|
||||
|
||||
def sql_indexes(app, style):
|
||||
"Returns a list of the CREATE INDEX SQL statements for all models in the given app."
|
||||
from django.db import models
|
||||
output = []
|
||||
for model in models.get_models(app):
|
||||
output.extend(sql_indexes_for_model(model, style))
|
||||
return output
|
||||
|
||||
def sql_all(app, style):
|
||||
"Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
|
||||
return sql_create(app, style) + sql_custom(app) + sql_indexes(app, style)
|
||||
|
||||
def sql_model_create(model, style, known_models=set()):
|
||||
"""
|
||||
Returns the SQL required to create a single model, as a tuple of:
|
||||
(list_of_sql, pending_references_dict)
|
||||
"""
|
||||
from django.db import backend, models
|
||||
|
||||
opts = model._meta
|
||||
final_output = []
|
||||
table_output = []
|
||||
pending_references = {}
|
||||
for f in opts.fields:
|
||||
col_type = f.db_type()
|
||||
tablespace = f.db_tablespace or opts.db_tablespace
|
||||
if col_type is None:
|
||||
# Skip ManyToManyFields, because they're not represented as
|
||||
# database columns in this table.
|
||||
continue
|
||||
# Make the definition (e.g. 'foo VARCHAR(30)') for this field.
|
||||
field_output = [style.SQL_FIELD(backend.quote_name(f.column)),
|
||||
style.SQL_COLTYPE(col_type)]
|
||||
field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
|
||||
if f.unique and (not f.primary_key or backend.allows_unique_and_pk):
|
||||
field_output.append(style.SQL_KEYWORD('UNIQUE'))
|
||||
if f.primary_key:
|
||||
field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
|
||||
if tablespace and backend.supports_tablespaces and (f.unique or f.primary_key) and backend.autoindexes_primary_keys:
|
||||
# We must specify the index tablespace inline, because we
|
||||
# won't be generating a CREATE INDEX statement for this field.
|
||||
field_output.append(backend.get_tablespace_sql(tablespace, inline=True))
|
||||
if f.rel:
|
||||
if f.rel.to in known_models:
|
||||
field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
|
||||
style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)) + ' (' + \
|
||||
style.SQL_FIELD(backend.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
|
||||
backend.get_deferrable_sql()
|
||||
)
|
||||
else:
|
||||
# We haven't yet created the table to which this field
|
||||
# is related, so save it for later.
|
||||
pr = pending_references.setdefault(f.rel.to, []).append((model, f))
|
||||
table_output.append(' '.join(field_output))
|
||||
if opts.order_with_respect_to:
|
||||
table_output.append(style.SQL_FIELD(backend.quote_name('_order')) + ' ' + \
|
||||
style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \
|
||||
style.SQL_KEYWORD('NULL'))
|
||||
for field_constraints in opts.unique_together:
|
||||
table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
|
||||
", ".join([backend.quote_name(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints]))
|
||||
|
||||
full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(backend.quote_name(opts.db_table)) + ' (']
|
||||
for i, line in enumerate(table_output): # Combine and add commas.
|
||||
full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
|
||||
full_statement.append(')')
|
||||
if opts.db_tablespace and backend.supports_tablespaces:
|
||||
full_statement.append(backend.get_tablespace_sql(opts.db_tablespace))
|
||||
full_statement.append(';')
|
||||
final_output.append('\n'.join(full_statement))
|
||||
|
||||
if opts.has_auto_field and hasattr(backend, 'get_autoinc_sql'):
|
||||
# Add any extra SQL needed to support auto-incrementing primary keys
|
||||
autoinc_sql = backend.get_autoinc_sql(opts.db_table)
|
||||
if autoinc_sql:
|
||||
for stmt in autoinc_sql:
|
||||
final_output.append(stmt)
|
||||
|
||||
return final_output, pending_references
|
||||
|
||||
def sql_for_pending_references(model, style, pending_references):
|
||||
"""
|
||||
Returns any ALTER TABLE statements to add constraints after the fact.
|
||||
"""
|
||||
from django.db import backend
|
||||
from django.db.backends.util import truncate_name
|
||||
|
||||
final_output = []
|
||||
if backend.supports_constraints:
|
||||
opts = model._meta
|
||||
if model in pending_references:
|
||||
for rel_class, f in pending_references[model]:
|
||||
rel_opts = rel_class._meta
|
||||
r_table = rel_opts.db_table
|
||||
r_col = f.column
|
||||
table = opts.db_table
|
||||
col = opts.get_field(f.rel.field_name).column
|
||||
# For MySQL, r_name must be unique in the first 64 characters.
|
||||
# So we are careful with character usage here.
|
||||
r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
|
||||
final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
|
||||
(backend.quote_name(r_table), truncate_name(r_name, backend.get_max_name_length()),
|
||||
backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col),
|
||||
backend.get_deferrable_sql()))
|
||||
del pending_references[model]
|
||||
return final_output
|
||||
|
||||
def many_to_many_sql_for_model(model, style):
|
||||
from django.db import backend, models
|
||||
from django.contrib.contenttypes import generic
|
||||
|
||||
opts = model._meta
|
||||
final_output = []
|
||||
for f in opts.many_to_many:
|
||||
if not isinstance(f.rel, generic.GenericRel):
|
||||
tablespace = f.db_tablespace or opts.db_tablespace
|
||||
if tablespace and backend.supports_tablespaces and backend.autoindexes_primary_keys:
|
||||
tablespace_sql = ' ' + backend.get_tablespace_sql(tablespace, inline=True)
|
||||
else:
|
||||
tablespace_sql = ''
|
||||
table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
|
||||
style.SQL_TABLE(backend.quote_name(f.m2m_db_table())) + ' (']
|
||||
table_output.append(' %s %s %s%s,' % \
|
||||
(style.SQL_FIELD(backend.quote_name('id')),
|
||||
style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),
|
||||
style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
|
||||
tablespace_sql))
|
||||
table_output.append(' %s %s %s %s (%s)%s,' % \
|
||||
(style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
|
||||
style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
|
||||
style.SQL_KEYWORD('NOT NULL REFERENCES'),
|
||||
style.SQL_TABLE(backend.quote_name(opts.db_table)),
|
||||
style.SQL_FIELD(backend.quote_name(opts.pk.column)),
|
||||
backend.get_deferrable_sql()))
|
||||
table_output.append(' %s %s %s %s (%s)%s,' % \
|
||||
(style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())),
|
||||
style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
|
||||
style.SQL_KEYWORD('NOT NULL REFERENCES'),
|
||||
style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)),
|
||||
style.SQL_FIELD(backend.quote_name(f.rel.to._meta.pk.column)),
|
||||
backend.get_deferrable_sql()))
|
||||
table_output.append(' %s (%s, %s)%s' % \
|
||||
(style.SQL_KEYWORD('UNIQUE'),
|
||||
style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
|
||||
style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())),
|
||||
tablespace_sql))
|
||||
table_output.append(')')
|
||||
if opts.db_tablespace and backend.supports_tablespaces:
|
||||
# f.db_tablespace is only for indices, so ignore its value here.
|
||||
table_output.append(backend.get_tablespace_sql(opts.db_tablespace))
|
||||
table_output.append(';')
|
||||
final_output.append('\n'.join(table_output))
|
||||
|
||||
# Add any extra SQL needed to support auto-incrementing PKs
|
||||
autoinc_sql = backend.get_autoinc_sql(f.m2m_db_table())
|
||||
if autoinc_sql:
|
||||
for stmt in autoinc_sql:
|
||||
final_output.append(stmt)
|
||||
|
||||
return final_output
|
||||
|
||||
def custom_sql_for_model(model):
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
opts = model._meta
|
||||
app_dir = os.path.normpath(os.path.join(os.path.dirname(models.get_app(model._meta.app_label).__file__), 'sql'))
|
||||
output = []
|
||||
|
||||
# Some backends can't execute more than one SQL statement at a time,
|
||||
# so split into separate statements.
|
||||
statements = re.compile(r";[ \t]*$", re.M)
|
||||
|
||||
# Find custom SQL, if it's available.
|
||||
sql_files = [os.path.join(app_dir, "%s.%s.sql" % (opts.object_name.lower(), settings.DATABASE_ENGINE)),
|
||||
os.path.join(app_dir, "%s.sql" % opts.object_name.lower())]
|
||||
for sql_file in sql_files:
|
||||
if os.path.exists(sql_file):
|
||||
fp = open(sql_file, 'U')
|
||||
for statement in statements.split(fp.read().decode(settings.FILE_CHARSET)):
|
||||
# Remove any comments from the file
|
||||
statement = re.sub(ur"--.*[\n\Z]", "", statement)
|
||||
if statement.strip():
|
||||
output.append(statement + u";")
|
||||
fp.close()
|
||||
|
||||
return output
|
||||
|
||||
def sql_indexes_for_model(model, style):
|
||||
"Returns the CREATE INDEX SQL statements for a single model"
|
||||
from django.db import backend
|
||||
output = []
|
||||
|
||||
for f in model._meta.fields:
|
||||
if f.db_index and not ((f.primary_key or f.unique) and backend.autoindexes_primary_keys):
|
||||
unique = f.unique and 'UNIQUE ' or ''
|
||||
tablespace = f.db_tablespace or model._meta.db_tablespace
|
||||
if tablespace and backend.supports_tablespaces:
|
||||
tablespace_sql = ' ' + backend.get_tablespace_sql(tablespace)
|
||||
else:
|
||||
tablespace_sql = ''
|
||||
output.append(
|
||||
style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
|
||||
style.SQL_TABLE(backend.quote_name('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
|
||||
style.SQL_KEYWORD('ON') + ' ' + \
|
||||
style.SQL_TABLE(backend.quote_name(model._meta.db_table)) + ' ' + \
|
||||
"(%s)" % style.SQL_FIELD(backend.quote_name(f.column)) + \
|
||||
"%s;" % tablespace_sql
|
||||
)
|
||||
return output
|
||||
|
||||
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)
|
221
django/core/management/validation.py
Normal file
221
django/core/management/validation.py
Normal file
@ -0,0 +1,221 @@
|
||||
import sys
|
||||
from django.core.management.color import color_style
|
||||
|
||||
class ModelErrorCollection:
|
||||
def __init__(self, outfile=sys.stdout):
|
||||
self.errors = []
|
||||
self.outfile = outfile
|
||||
self.style = color_style()
|
||||
|
||||
def add(self, context, error):
|
||||
self.errors.append((context, error))
|
||||
self.outfile.write(self.style.ERROR("%s: %s\n" % (context, error)))
|
||||
|
||||
def get_validation_errors(outfile, app=None):
|
||||
"""
|
||||
Validates all models that are part of the specified app. If no app name is provided,
|
||||
validates all models of all installed apps. Writes errors, if any, to outfile.
|
||||
Returns number of errors.
|
||||
"""
|
||||
from django.conf import settings
|
||||
from django.db import models, connection
|
||||
from django.db.models.loading import get_app_errors
|
||||
from django.db.models.fields.related import RelatedObject
|
||||
|
||||
e = ModelErrorCollection(outfile)
|
||||
|
||||
for (app_name, error) in get_app_errors().items():
|
||||
e.add(app_name, error)
|
||||
|
||||
for cls in models.get_models(app):
|
||||
opts = cls._meta
|
||||
|
||||
# Do field-specific validation.
|
||||
for f in opts.fields:
|
||||
if f.name == 'id' and not f.primary_key and opts.pk.name == 'id':
|
||||
e.add(opts, '"%s": You can\'t use "id" as a field name, because each model automatically gets an "id" field if none of the fields have primary_key=True. You need to either remove/rename your "id" field or add primary_key=True to a field.' % f.name)
|
||||
if isinstance(f, models.CharField) and f.max_length in (None, 0):
|
||||
e.add(opts, '"%s": CharFields require a "max_length" attribute.' % f.name)
|
||||
if isinstance(f, models.DecimalField):
|
||||
if f.decimal_places is None:
|
||||
e.add(opts, '"%s": DecimalFields require a "decimal_places" attribute.' % f.name)
|
||||
if f.max_digits is None:
|
||||
e.add(opts, '"%s": DecimalFields require a "max_digits" attribute.' % f.name)
|
||||
if isinstance(f, models.FileField) and not f.upload_to:
|
||||
e.add(opts, '"%s": FileFields require an "upload_to" attribute.' % f.name)
|
||||
if isinstance(f, models.ImageField):
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
e.add(opts, '"%s": To use ImageFields, you need to install the Python Imaging Library. Get it at http://www.pythonware.com/products/pil/ .' % f.name)
|
||||
if f.prepopulate_from is not None and type(f.prepopulate_from) not in (list, tuple):
|
||||
e.add(opts, '"%s": prepopulate_from should be a list or tuple.' % f.name)
|
||||
if f.choices:
|
||||
if not hasattr(f.choices, '__iter__'):
|
||||
e.add(opts, '"%s": "choices" should be iterable (e.g., a tuple or list).' % f.name)
|
||||
else:
|
||||
for c in f.choices:
|
||||
if not type(c) in (tuple, list) or len(c) != 2:
|
||||
e.add(opts, '"%s": "choices" should be a sequence of two-tuples.' % f.name)
|
||||
if f.db_index not in (None, True, False):
|
||||
e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name)
|
||||
|
||||
# Check that max_length <= 255 if using older MySQL versions.
|
||||
if settings.DATABASE_ENGINE == 'mysql':
|
||||
db_version = connection.get_server_version()
|
||||
if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.max_length > 255:
|
||||
e.add(opts, '"%s": %s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]])))
|
||||
|
||||
# Check to see if the related field will clash with any
|
||||
# existing fields, m2m fields, m2m related objects or related objects
|
||||
if f.rel:
|
||||
rel_opts = f.rel.to._meta
|
||||
if f.rel.to not in models.get_models():
|
||||
e.add(opts, "'%s' has relation with model %s, which has not been installed" % (f.name, rel_opts.object_name))
|
||||
|
||||
rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name()
|
||||
rel_query_name = f.related_query_name()
|
||||
for r in rel_opts.fields:
|
||||
if r.name == rel_name:
|
||||
e.add(opts, "Accessor for field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
|
||||
if r.name == rel_query_name:
|
||||
e.add(opts, "Reverse query name for field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
|
||||
for r in rel_opts.many_to_many:
|
||||
if r.name == rel_name:
|
||||
e.add(opts, "Accessor for field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
|
||||
if r.name == rel_query_name:
|
||||
e.add(opts, "Reverse query name for field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
|
||||
for r in rel_opts.get_all_related_many_to_many_objects():
|
||||
if r.get_accessor_name() == rel_name:
|
||||
e.add(opts, "Accessor for field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
|
||||
if r.get_accessor_name() == rel_query_name:
|
||||
e.add(opts, "Reverse query name for field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
|
||||
for r in rel_opts.get_all_related_objects():
|
||||
if r.field is not f:
|
||||
if r.get_accessor_name() == rel_name:
|
||||
e.add(opts, "Accessor for field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
|
||||
if r.get_accessor_name() == rel_query_name:
|
||||
e.add(opts, "Reverse query name for field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
|
||||
|
||||
for i, f in enumerate(opts.many_to_many):
|
||||
# Check to see if the related m2m field will clash with any
|
||||
# existing fields, m2m fields, m2m related objects or related objects
|
||||
rel_opts = f.rel.to._meta
|
||||
if f.rel.to not in models.get_models():
|
||||
e.add(opts, "'%s' has m2m relation with model %s, which has not been installed" % (f.name, rel_opts.object_name))
|
||||
|
||||
rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name()
|
||||
rel_query_name = f.related_query_name()
|
||||
# If rel_name is none, there is no reverse accessor.
|
||||
# (This only occurs for symmetrical m2m relations to self).
|
||||
# If this is the case, there are no clashes to check for this field, as
|
||||
# there are no reverse descriptors for this field.
|
||||
if rel_name is not None:
|
||||
for r in rel_opts.fields:
|
||||
if r.name == rel_name:
|
||||
e.add(opts, "Accessor for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
|
||||
if r.name == rel_query_name:
|
||||
e.add(opts, "Reverse query name for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
|
||||
for r in rel_opts.many_to_many:
|
||||
if r.name == rel_name:
|
||||
e.add(opts, "Accessor for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
|
||||
if r.name == rel_query_name:
|
||||
e.add(opts, "Reverse query name for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
|
||||
for r in rel_opts.get_all_related_many_to_many_objects():
|
||||
if r.field is not f:
|
||||
if r.get_accessor_name() == rel_name:
|
||||
e.add(opts, "Accessor for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
|
||||
if r.get_accessor_name() == rel_query_name:
|
||||
e.add(opts, "Reverse query name for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
|
||||
for r in rel_opts.get_all_related_objects():
|
||||
if r.get_accessor_name() == rel_name:
|
||||
e.add(opts, "Accessor for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
|
||||
if r.get_accessor_name() == rel_query_name:
|
||||
e.add(opts, "Reverse query name for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
|
||||
|
||||
# Check admin attribute.
|
||||
if opts.admin is not None:
|
||||
if not isinstance(opts.admin, models.AdminOptions):
|
||||
e.add(opts, '"admin" attribute, if given, must be set to a models.AdminOptions() instance.')
|
||||
else:
|
||||
# list_display
|
||||
if not isinstance(opts.admin.list_display, (list, tuple)):
|
||||
e.add(opts, '"admin.list_display", if given, must be set to a list or tuple.')
|
||||
else:
|
||||
for fn in opts.admin.list_display:
|
||||
try:
|
||||
f = opts.get_field(fn)
|
||||
except models.FieldDoesNotExist:
|
||||
if not hasattr(cls, fn):
|
||||
e.add(opts, '"admin.list_display" refers to %r, which isn\'t an attribute, method or property.' % fn)
|
||||
else:
|
||||
if isinstance(f, models.ManyToManyField):
|
||||
e.add(opts, '"admin.list_display" doesn\'t support ManyToManyFields (%r).' % fn)
|
||||
# list_display_links
|
||||
if opts.admin.list_display_links and not opts.admin.list_display:
|
||||
e.add(opts, '"admin.list_display" must be defined for "admin.list_display_links" to be used.')
|
||||
if not isinstance(opts.admin.list_display_links, (list, tuple)):
|
||||
e.add(opts, '"admin.list_display_links", if given, must be set to a list or tuple.')
|
||||
else:
|
||||
for fn in opts.admin.list_display_links:
|
||||
try:
|
||||
f = opts.get_field(fn)
|
||||
except models.FieldDoesNotExist:
|
||||
if not hasattr(cls, fn):
|
||||
e.add(opts, '"admin.list_display_links" refers to %r, which isn\'t an attribute, method or property.' % fn)
|
||||
if fn not in opts.admin.list_display:
|
||||
e.add(opts, '"admin.list_display_links" refers to %r, which is not defined in "admin.list_display".' % fn)
|
||||
# list_filter
|
||||
if not isinstance(opts.admin.list_filter, (list, tuple)):
|
||||
e.add(opts, '"admin.list_filter", if given, must be set to a list or tuple.')
|
||||
else:
|
||||
for fn in opts.admin.list_filter:
|
||||
try:
|
||||
f = opts.get_field(fn)
|
||||
except models.FieldDoesNotExist:
|
||||
e.add(opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn)
|
||||
# date_hierarchy
|
||||
if opts.admin.date_hierarchy:
|
||||
try:
|
||||
f = opts.get_field(opts.admin.date_hierarchy)
|
||||
except models.FieldDoesNotExist:
|
||||
e.add(opts, '"admin.date_hierarchy" refers to %r, which isn\'t a field.' % opts.admin.date_hierarchy)
|
||||
|
||||
# Check ordering attribute.
|
||||
if opts.ordering:
|
||||
for field_name in opts.ordering:
|
||||
if field_name == '?': continue
|
||||
if field_name.startswith('-'):
|
||||
field_name = field_name[1:]
|
||||
if opts.order_with_respect_to and field_name == '_order':
|
||||
continue
|
||||
if '.' in field_name: continue # Skip ordering in the format 'table.field'.
|
||||
try:
|
||||
opts.get_field(field_name, many_to_many=False)
|
||||
except models.FieldDoesNotExist:
|
||||
e.add(opts, '"ordering" refers to "%s", a field that doesn\'t exist.' % field_name)
|
||||
|
||||
# Check core=True, if needed.
|
||||
for related in opts.get_followed_related_objects():
|
||||
if not related.edit_inline:
|
||||
continue
|
||||
try:
|
||||
for f in related.opts.fields:
|
||||
if f.core:
|
||||
raise StopIteration
|
||||
e.add(related.opts, "At least one field in %s should have core=True, because it's being edited inline by %s.%s." % (related.opts.object_name, opts.module_name, opts.object_name))
|
||||
except StopIteration:
|
||||
pass
|
||||
|
||||
# Check unique_together.
|
||||
for ut in opts.unique_together:
|
||||
for field_name in ut:
|
||||
try:
|
||||
f = opts.get_field(field_name, many_to_many=True)
|
||||
except models.FieldDoesNotExist:
|
||||
e.add(opts, '"unique_together" refers to %s, a field that doesn\'t exist. Check your syntax.' % field_name)
|
||||
else:
|
||||
if isinstance(f.rel, models.ManyToManyRel):
|
||||
e.add(opts, '"unique_together" refers to %s. ManyToManyFields are not supported in unique_together.' % f.name)
|
||||
|
||||
return len(e.errors)
|
@ -269,10 +269,10 @@ def hasNoProfanities(field_data, all_data):
|
||||
words_seen = [w for w in settings.PROFANITIES_LIST if w in field_data]
|
||||
if words_seen:
|
||||
from django.utils.text import get_text_list
|
||||
plural = len(words_seen) > 1
|
||||
plural = len(words_seen)
|
||||
raise ValidationError, ungettext("Watch your mouth! The word %s is not allowed here.",
|
||||
"Watch your mouth! The words %s are not allowed here.", plural) % \
|
||||
get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in words_seen], 'and')
|
||||
get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in words_seen], _('and'))
|
||||
|
||||
class AlwaysMatchesOtherField(object):
|
||||
def __init__(self, other_field_name, error_message=None):
|
||||
|
@ -4,7 +4,7 @@ information about those pages -- namely, the content type and object ID.
|
||||
|
||||
This module contains utility functions for retrieving and doing interesting
|
||||
things with these special "X-Headers" (so called because the HTTP spec demands
|
||||
that custom headers are prefxed with "X-").
|
||||
that custom headers are prefixed with "X-").
|
||||
|
||||
Next time you're at slashdot.org, watch out for X-Fry and X-Bender. :)
|
||||
"""
|
||||
@ -17,6 +17,8 @@ def populate_xheaders(request, response, model, object_id):
|
||||
or if the request is from a logged in staff member.
|
||||
"""
|
||||
from django.conf import settings
|
||||
if request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS or (hasattr(request, 'user') and request.user.is_authenticated() and request.user.is_staff):
|
||||
if (request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS
|
||||
or (hasattr(request, 'user') and request.user.is_authenticated()
|
||||
and request.user.is_staff)):
|
||||
response['X-Object-Type'] = "%s.%s" % (model._meta.app_label, model._meta.object_name.lower())
|
||||
response['X-Object-Id'] = str(object_id)
|
||||
|
@ -109,7 +109,7 @@ def create_test_db(settings, connection, backend, verbosity=1, autoclobber=False
|
||||
settings.DATABASE_USER = TEST_DATABASE_USER
|
||||
settings.DATABASE_PASSWORD = TEST_DATABASE_PASSWD
|
||||
|
||||
management.syncdb(verbosity, interactive=False)
|
||||
management.call_command('syncdb', verbosity=verbosity, interactive=False)
|
||||
|
||||
# Get a cursor (even though we don't need one yet). This has
|
||||
# the side effect of initializing the test database.
|
||||
|
@ -278,7 +278,7 @@ def typecast_string(s):
|
||||
"""
|
||||
Cast all returned strings to unicode strings.
|
||||
"""
|
||||
if not s:
|
||||
if not s and not isinstance(s, str):
|
||||
return s
|
||||
return smart_unicode(s)
|
||||
|
||||
|
@ -218,11 +218,11 @@ class Model(object):
|
||||
record_exists = True
|
||||
if pk_set:
|
||||
# Determine whether a record with the primary key already exists.
|
||||
cursor.execute("SELECT COUNT(*) FROM %s WHERE %s=%%s" % \
|
||||
cursor.execute("SELECT 1 FROM %s WHERE %s=%%s" % \
|
||||
(backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)),
|
||||
self._meta.pk.get_db_prep_lookup('exact', pk_val))
|
||||
# If it does already exist, do an UPDATE.
|
||||
if cursor.fetchone()[0] > 0:
|
||||
if cursor.fetchone():
|
||||
db_values = [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, False)) for f in non_pks]
|
||||
if db_values:
|
||||
cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
|
||||
|
@ -114,7 +114,7 @@ class _QuerySet(object):
|
||||
|
||||
def __getitem__(self, k):
|
||||
"Retrieve an item or slice from the set of results."
|
||||
if not isinstance(k, (slice, int)):
|
||||
if not isinstance(k, (slice, int, long)):
|
||||
raise TypeError
|
||||
assert (not isinstance(k, slice) and (k >= 0)) \
|
||||
or (isinstance(k, slice) and (k.start is None or k.start >= 0) and (k.stop is None or k.stop >= 0)), \
|
||||
|
@ -2,7 +2,7 @@ import os
|
||||
from Cookie import SimpleCookie
|
||||
from pprint import pformat
|
||||
from urllib import urlencode
|
||||
from django.utils.datastructures import MultiValueDict
|
||||
from django.utils.datastructures import MultiValueDict, FileDict
|
||||
from django.utils.encoding import smart_str, iri_to_uri, force_unicode
|
||||
|
||||
RESERVED_CHARS="!*'();:@&=+$,/?%#[]"
|
||||
@ -84,13 +84,15 @@ def parse_file_upload(header_dict, post_data):
|
||||
if not name_dict['filename'].strip():
|
||||
continue
|
||||
# IE submits the full path, so trim everything but the basename.
|
||||
# (We can't use os.path.basename because it expects Linux paths.)
|
||||
# (We can't use os.path.basename because that uses the server's
|
||||
# directory separator, which may not be the same as the
|
||||
# client's one.)
|
||||
filename = name_dict['filename'][name_dict['filename'].rfind("\\")+1:]
|
||||
FILES.appendlist(name_dict['name'], {
|
||||
FILES.appendlist(name_dict['name'], FileDict({
|
||||
'filename': filename,
|
||||
'content-type': 'Content-Type' in submessage and submessage['Content-Type'] or None,
|
||||
'content': submessage.get_payload(),
|
||||
})
|
||||
}))
|
||||
else:
|
||||
POST.appendlist(name_dict['name'], submessage.get_payload())
|
||||
return POST, FILES
|
||||
@ -212,18 +214,22 @@ class HttpResponse(object):
|
||||
|
||||
status_code = 200
|
||||
|
||||
def __init__(self, content='', mimetype=None, status=None):
|
||||
def __init__(self, content='', mimetype=None, status=None,
|
||||
content_type=None):
|
||||
from django.conf import settings
|
||||
self._charset = settings.DEFAULT_CHARSET
|
||||
if not mimetype:
|
||||
mimetype = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE, settings.DEFAULT_CHARSET)
|
||||
if mimetype:
|
||||
content_type = mimetype # For backwards compatibility
|
||||
if not content_type:
|
||||
content_type = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE,
|
||||
settings.DEFAULT_CHARSET)
|
||||
if not isinstance(content, basestring) and hasattr(content, '__iter__'):
|
||||
self._container = content
|
||||
self._is_string = False
|
||||
else:
|
||||
self._container = [content]
|
||||
self._is_string = True
|
||||
self.headers = {'Content-Type': mimetype}
|
||||
self.headers = {'Content-Type': content_type}
|
||||
self.cookies = SimpleCookie()
|
||||
if status:
|
||||
self.status_code = status
|
||||
|
@ -80,7 +80,9 @@ class CommonMiddleware(object):
|
||||
else:
|
||||
etag = md5.new(response.content).hexdigest()
|
||||
if response.status_code >= 200 and response.status_code < 300 and request.META.get('HTTP_IF_NONE_MATCH') == etag:
|
||||
cookies = response.cookies
|
||||
response = http.HttpResponseNotModified()
|
||||
response.cookies = cookies
|
||||
else:
|
||||
response['ETag'] = etag
|
||||
|
||||
|
@ -11,6 +11,11 @@ class GZipMiddleware(object):
|
||||
on the Accept-Encoding header.
|
||||
"""
|
||||
def process_response(self, request, response):
|
||||
if response.status_code != 200 or len(response.content) < 200:
|
||||
# Not worth compressing really short responses or 304 status
|
||||
# responses, etc.
|
||||
return response
|
||||
|
||||
patch_vary_headers(response, ('Accept-Encoding',))
|
||||
|
||||
# Avoid gzipping if we've already got a content-encoding or if the
|
||||
|
@ -57,4 +57,4 @@ class SelectDateWidget(Widget):
|
||||
y, m, d = data.get(self.year_field % name), data.get(self.month_field % name), data.get(self.day_field % name)
|
||||
if y and m and d:
|
||||
return '%s-%s-%s' % (y, m, d)
|
||||
return None
|
||||
return data.get(name, None)
|
||||
|
@ -344,7 +344,7 @@ url_re = re.compile(
|
||||
try:
|
||||
from django.conf import settings
|
||||
URL_VALIDATOR_USER_AGENT = settings.URL_VALIDATOR_USER_AGENT
|
||||
except ImportError:
|
||||
except (ImportError, EnvironmentError):
|
||||
# It's OK if Django settings aren't configured.
|
||||
URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)'
|
||||
|
||||
|
@ -204,7 +204,7 @@ class FormFieldCollection(FormFieldWrapper):
|
||||
def __str__(self):
|
||||
return unicode(self).encode('utf-8')
|
||||
|
||||
def __str__(self):
|
||||
def __unicode__(self):
|
||||
return unicode(self.formfield_dict)
|
||||
|
||||
def __getitem__(self, template_key):
|
||||
|
@ -253,3 +253,14 @@ class Client:
|
||||
else:
|
||||
return False
|
||||
|
||||
def logout(self):
|
||||
"""Removes the authenticated user's cookies.
|
||||
|
||||
Causes the authenticated user to be logged out.
|
||||
"""
|
||||
try:
|
||||
Session.objects.get(session_key=self.cookies['sessionid'].value).delete()
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
self.cookies = SimpleCookie()
|
||||
|
@ -1,7 +1,8 @@
|
||||
import re, unittest
|
||||
from urlparse import urlparse
|
||||
from django.db import transaction
|
||||
from django.core import management, mail
|
||||
from django.core import mail
|
||||
from django.core.management import call_command
|
||||
from django.db.models import get_apps
|
||||
from django.test import _doctest as doctest
|
||||
from django.test.client import Client
|
||||
@ -42,9 +43,11 @@ class TestCase(unittest.TestCase):
|
||||
* Clearing the mail test outbox.
|
||||
|
||||
"""
|
||||
management.flush(verbosity=0, interactive=False)
|
||||
call_command('flush', verbosity=0, interactive=False)
|
||||
if hasattr(self, 'fixtures'):
|
||||
management.load_data(self.fixtures, verbosity=0)
|
||||
# We have to use this slightly awkward syntax due to the fact
|
||||
# that we're using *args and **kwargs together.
|
||||
call_command('loaddata', *self.fixtures, **{'verbosity': 0})
|
||||
mail.outbox = []
|
||||
|
||||
def __call__(self, result=None):
|
||||
@ -88,7 +91,7 @@ class TestCase(unittest.TestCase):
|
||||
self.assertEqual(real_count, count,
|
||||
"Found %d instances of '%s' in response (expected %d)" % (real_count, text, count))
|
||||
else:
|
||||
self.assertTrue(real_count != 0, "Couldn't find '%s' in response" % text)
|
||||
self.failUnless(real_count != 0, "Couldn't find '%s' in response" % text)
|
||||
|
||||
def assertFormError(self, response, form, field, errors):
|
||||
"Assert that a form used to render the response has a specific field error"
|
||||
|
@ -1,8 +1,8 @@
|
||||
import sys, time
|
||||
from django.conf import settings
|
||||
from django.db import connection, backend, get_creation_module
|
||||
from django.core import management, mail
|
||||
from django.core import management, mail
|
||||
from django.core import mail
|
||||
from django.core.management import call_command
|
||||
from django.dispatch import dispatcher
|
||||
from django.test import signals
|
||||
from django.template import Template
|
||||
@ -18,12 +18,12 @@ def instrumented_test_render(self, context):
|
||||
"""
|
||||
dispatcher.send(signal=signals.template_rendered, sender=self, template=self, context=context)
|
||||
return self.nodelist.render(context)
|
||||
|
||||
|
||||
class TestSMTPConnection(object):
|
||||
"""A substitute SMTP connection for use during test sessions.
|
||||
The test connection stores email messages in a dummy outbox,
|
||||
rather than sending them out on the wire.
|
||||
|
||||
|
||||
"""
|
||||
def __init__(*args, **kwargs):
|
||||
pass
|
||||
@ -36,37 +36,38 @@ class TestSMTPConnection(object):
|
||||
def send_messages(self, messages):
|
||||
"Redirect messages to the dummy outbox"
|
||||
mail.outbox.extend(messages)
|
||||
return len(messages)
|
||||
|
||||
def setup_test_environment():
|
||||
"""Perform any global pre-test setup. This involves:
|
||||
|
||||
|
||||
- Installing the instrumented test renderer
|
||||
- Diverting the email sending functions to a test buffer
|
||||
|
||||
|
||||
"""
|
||||
Template.original_render = Template.render
|
||||
Template.render = instrumented_test_render
|
||||
|
||||
|
||||
mail.original_SMTPConnection = mail.SMTPConnection
|
||||
mail.SMTPConnection = TestSMTPConnection
|
||||
|
||||
mail.outbox = []
|
||||
|
||||
|
||||
def teardown_test_environment():
|
||||
"""Perform any global post-test teardown. This involves:
|
||||
|
||||
- Restoring the original test renderer
|
||||
- Restoring the email sending functions
|
||||
|
||||
|
||||
"""
|
||||
Template.render = Template.original_render
|
||||
del Template.original_render
|
||||
|
||||
|
||||
mail.SMTPConnection = mail.original_SMTPConnection
|
||||
del mail.original_SMTPConnection
|
||||
|
||||
|
||||
del mail.outbox
|
||||
|
||||
|
||||
def _set_autocommit(connection):
|
||||
"Make sure a connection is in autocommit mode."
|
||||
if hasattr(connection.connection, "autocommit"):
|
||||
@ -89,12 +90,16 @@ def get_postgresql_create_suffix():
|
||||
return ''
|
||||
|
||||
def create_test_db(verbosity=1, autoclobber=False):
|
||||
"""
|
||||
Creates a test database, prompting the user for confirmation if the
|
||||
database already exists. Returns the name of the test database created.
|
||||
"""
|
||||
# If the database backend wants to create the test DB itself, let it
|
||||
creation_module = get_creation_module()
|
||||
if hasattr(creation_module, "create_test_db"):
|
||||
creation_module.create_test_db(settings, connection, backend, verbosity, autoclobber)
|
||||
return
|
||||
|
||||
|
||||
if verbosity >= 1:
|
||||
print "Creating test database..."
|
||||
# If we're using SQLite, it's more convenient to test against an
|
||||
@ -112,22 +117,22 @@ def create_test_db(verbosity=1, autoclobber=False):
|
||||
TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME
|
||||
else:
|
||||
TEST_DATABASE_NAME = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
|
||||
|
||||
|
||||
# Create the test database and connect to it. We need to autocommit
|
||||
# if the database supports it because PostgreSQL doesn't allow
|
||||
# if the database supports it because PostgreSQL doesn't allow
|
||||
# CREATE/DROP DATABASE statements within transactions.
|
||||
cursor = connection.cursor()
|
||||
_set_autocommit(connection)
|
||||
try:
|
||||
cursor.execute("CREATE DATABASE %s %s" % (backend.quote_name(TEST_DATABASE_NAME), suffix))
|
||||
except Exception, e:
|
||||
except Exception, e:
|
||||
sys.stderr.write("Got an error creating the test database: %s\n" % e)
|
||||
if not autoclobber:
|
||||
confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % TEST_DATABASE_NAME)
|
||||
if autoclobber or confirm == 'yes':
|
||||
try:
|
||||
if verbosity >= 1:
|
||||
print "Destroying old test database..."
|
||||
print "Destroying old test database..."
|
||||
cursor.execute("DROP DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME))
|
||||
if verbosity >= 1:
|
||||
print "Creating test database..."
|
||||
@ -138,27 +143,29 @@ def create_test_db(verbosity=1, autoclobber=False):
|
||||
else:
|
||||
print "Tests cancelled."
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
connection.close()
|
||||
settings.DATABASE_NAME = TEST_DATABASE_NAME
|
||||
|
||||
management.syncdb(verbosity, interactive=False)
|
||||
call_command('syncdb', verbosity=verbosity, interactive=False)
|
||||
|
||||
if settings.CACHE_BACKEND.startswith('db://'):
|
||||
cache_name = settings.CACHE_BACKEND[len('db://'):]
|
||||
management.createcachetable(cache_name)
|
||||
call_command('createcachetable', cache_name)
|
||||
|
||||
# Get a cursor (even though we don't need one yet). This has
|
||||
# the side effect of initializing the test database.
|
||||
cursor = connection.cursor()
|
||||
|
||||
return TEST_DATABASE_NAME
|
||||
|
||||
def destroy_test_db(old_database_name, verbosity=1):
|
||||
# If the database wants to drop the test DB itself, let it
|
||||
creation_module = get_creation_module()
|
||||
if hasattr(creation_module, "destroy_test_db"):
|
||||
creation_module.destroy_test_db(settings, connection, backend, old_database_name, verbosity)
|
||||
return
|
||||
|
||||
|
||||
# Unless we're using SQLite, remove the test database to clean up after
|
||||
# ourselves. Connect to the previous database (not the test database)
|
||||
# to do so, because it's not allowed to delete a database while being
|
||||
|
@ -1,23 +1,23 @@
|
||||
from os.path import join, normcase, abspath, sep
|
||||
|
||||
def safe_join(base, *paths):
|
||||
"""
|
||||
Joins one or more path components to the base path component intelligently.
|
||||
Returns a normalized, absolute version of the final path.
|
||||
|
||||
The final path must be located inside of the base path component (otherwise
|
||||
a ValueError is raised).
|
||||
"""
|
||||
# We need to use normcase to ensure we don't false-negative on case
|
||||
# insensitive operating systems (like Windows).
|
||||
final_path = normcase(abspath(join(base, *paths)))
|
||||
base_path = normcase(abspath(base))
|
||||
base_path_len = len(base_path)
|
||||
# Ensure final_path starts with base_path and that the next character after
|
||||
# the final path is os.sep (or nothing, in which case final_path must be
|
||||
# equal to base_path).
|
||||
if not final_path.startswith(base_path) \
|
||||
or final_path[base_path_len:base_path_len+1] not in ('', sep):
|
||||
raise ValueError('the joined path is located outside of the base path'
|
||||
' component')
|
||||
return final_path
|
||||
from os.path import join, normcase, abspath, sep
|
||||
|
||||
def safe_join(base, *paths):
|
||||
"""
|
||||
Joins one or more path components to the base path component intelligently.
|
||||
Returns a normalized, absolute version of the final path.
|
||||
|
||||
The final path must be located inside of the base path component (otherwise
|
||||
a ValueError is raised).
|
||||
"""
|
||||
# We need to use normcase to ensure we don't false-negative on case
|
||||
# insensitive operating systems (like Windows).
|
||||
final_path = normcase(abspath(join(base, *paths)))
|
||||
base_path = normcase(abspath(base))
|
||||
base_path_len = len(base_path)
|
||||
# Ensure final_path starts with base_path and that the next character after
|
||||
# the final path is os.sep (or nothing, in which case final_path must be
|
||||
# equal to base_path).
|
||||
if not final_path.startswith(base_path) \
|
||||
or final_path[base_path_len:base_path_len+1] not in ('', sep):
|
||||
raise ValueError('the joined path is located outside of the base path'
|
||||
' component')
|
||||
return final_path
|
||||
|
@ -267,3 +267,16 @@ class DotExpandedDict(dict):
|
||||
current[bits[-1]] = v
|
||||
except TypeError: # Special-case if current isn't a dict.
|
||||
current = {bits[-1] : v}
|
||||
|
||||
class FileDict(dict):
|
||||
"""
|
||||
A dictionary used to hold uploaded file contents. The only special feature
|
||||
here is that repr() of this object won't dump the entire contents of the
|
||||
file to the output. A handy safeguard for a large file upload.
|
||||
"""
|
||||
def __repr__(self):
|
||||
if 'content' in self:
|
||||
d = dict(self, content='<omitted>')
|
||||
return dict.__repr__(d)
|
||||
return dict.__repr__(self)
|
||||
|
||||
|
@ -2,6 +2,7 @@ import re
|
||||
from django.conf import settings
|
||||
from django.utils.encoding import force_unicode
|
||||
from django.utils.functional import allow_lazy
|
||||
from django.utils.translation import ugettext_lazy
|
||||
|
||||
# Capitalizes the first letter of a string.
|
||||
capfirst = lambda x: x and force_unicode(x)[0].upper() + force_unicode(x)[1:]
|
||||
@ -123,7 +124,7 @@ def get_valid_filename(s):
|
||||
return re.sub(r'[^-A-Za-z0-9_.]', '', s)
|
||||
get_valid_filename = allow_lazy(get_valid_filename, unicode)
|
||||
|
||||
def get_text_list(list_, last_word=u'or'):
|
||||
def get_text_list(list_, last_word=ugettext_lazy(u'or')):
|
||||
"""
|
||||
>>> get_text_list(['a', 'b', 'c', 'd'])
|
||||
'a, b, c or d'
|
||||
|
@ -123,10 +123,20 @@ def technical_500_response(request, exc_type, exc_value, tb):
|
||||
'function': '?',
|
||||
'lineno': '?',
|
||||
}]
|
||||
|
||||
unicode_hint = ''
|
||||
if issubclass(exc_type, UnicodeError):
|
||||
start = getattr(exc_value, 'start', None)
|
||||
end = getattr(exc_value, 'end', None)
|
||||
if start is not None and end is not None:
|
||||
unicode_str = exc_value.args[1]
|
||||
unicode_hint = smart_unicode(unicode_str[max(start-5, 0):min(end+5, len(unicode_str))], 'ascii', errors='replace')
|
||||
|
||||
t = Template(TECHNICAL_500_TEMPLATE, name='Technical 500 template')
|
||||
c = Context({
|
||||
'exception_type': exc_type.__name__,
|
||||
'exception_value': smart_unicode(exc_value, errors='replace'),
|
||||
'unicode_hint': unicode_hint,
|
||||
'frames': frames,
|
||||
'lastframe': frames[-1],
|
||||
'request': request,
|
||||
@ -258,6 +268,7 @@ TECHNICAL_500_TEMPLATE = """
|
||||
#explanation { background:#eee; }
|
||||
#template, #template-not-exist { background:#f6f6f6; }
|
||||
#template-not-exist ul { margin: 0 0 0 20px; }
|
||||
#unicode-hint { background:#eee; }
|
||||
#traceback { background:#eee; }
|
||||
#requestinfo { background:#f6f6f6; padding-left:120px; }
|
||||
#summary table { border:none; background:transparent; }
|
||||
@ -358,6 +369,12 @@ TECHNICAL_500_TEMPLATE = """
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% if unicode_hint %}
|
||||
<div id="unicode-hint">
|
||||
<h2>Unicode error hint</h2>
|
||||
<p>The string that could not be encoded/decoded was: <strong>{{ unicode_hint|escape }}</strong></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if template_does_not_exist %}
|
||||
<div id="template-not-exist">
|
||||
<h2>Template-loader postmortem</h2>
|
||||
|
@ -71,7 +71,7 @@ def create_object(request, model, template_name=None,
|
||||
return HttpResponse(t.render(c))
|
||||
|
||||
def update_object(request, model, object_id=None, slug=None,
|
||||
slug_field=None, template_name=None, template_loader=loader,
|
||||
slug_field='slug', template_name=None, template_loader=loader,
|
||||
extra_context=None, post_save_redirect=None,
|
||||
login_required=False, follow=None, context_processors=None,
|
||||
template_object_name='object'):
|
||||
@ -146,7 +146,7 @@ def update_object(request, model, object_id=None, slug=None,
|
||||
return response
|
||||
|
||||
def delete_object(request, model, post_delete_redirect,
|
||||
object_id=None, slug=None, slug_field=None, template_name=None,
|
||||
object_id=None, slug=None, slug_field='slug', template_name=None,
|
||||
template_loader=loader, extra_context=None,
|
||||
login_required=False, context_processors=None, template_object_name='object'):
|
||||
"""
|
||||
|
@ -286,7 +286,7 @@ def archive_today(request, **kwargs):
|
||||
|
||||
def object_detail(request, year, month, day, queryset, date_field,
|
||||
month_format='%b', day_format='%d', object_id=None, slug=None,
|
||||
slug_field=None, template_name=None, template_name_field=None,
|
||||
slug_field='slug', template_name=None, template_name_field=None,
|
||||
template_loader=loader, extra_context=None, context_processors=None,
|
||||
template_object_name='object', mimetype=None, allow_future=False):
|
||||
"""
|
||||
|
@ -87,7 +87,7 @@ def object_list(request, queryset, paginate_by=None, page=None,
|
||||
return HttpResponse(t.render(c), mimetype=mimetype)
|
||||
|
||||
def object_detail(request, queryset, object_id=None, slug=None,
|
||||
slug_field=None, template_name=None, template_name_field=None,
|
||||
slug_field='slug', template_name=None, template_name_field=None,
|
||||
template_loader=loader, extra_context=None,
|
||||
context_processors=None, template_object_name='object',
|
||||
mimetype=None):
|
||||
|
@ -69,9 +69,9 @@ function pluralidx(count) { return (count == 1) ? 0 : 1; }
|
||||
InterPolate = r"""
|
||||
function interpolate(fmt, obj, named) {
|
||||
if (named) {
|
||||
return fmt.replace(/%\(\w+\)s/, function(match){return String(obj[match.slice(2,-2)])});
|
||||
return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])});
|
||||
} else {
|
||||
return fmt.replace(/%s/, function(match){return String(obj.shift())});
|
||||
return fmt.replace(/%s/g, function(match){return String(obj.shift())});
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
@ -436,7 +436,10 @@ template context variables:
|
||||
* ``next``: The URL to redirect to after successful login. This may contain
|
||||
a query string, too.
|
||||
* ``site_name``: The name of the current ``Site``, according to the
|
||||
``SITE_ID`` setting. See the `site framework docs`_.
|
||||
``SITE_ID`` setting. If you're using the Django development version and
|
||||
you don't have the site framework installed, this will be set to the
|
||||
value of ``request.META['SERVER_NAME']``. For more on sites, see the
|
||||
`site framework docs`_.
|
||||
|
||||
If you'd prefer not to call the template ``registration/login.html``, you can
|
||||
pass the ``template_name`` parameter via the extra arguments to the view in
|
||||
@ -675,8 +678,6 @@ Example in Python 2.4 syntax::
|
||||
The permission_required decorator
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
It's a relatively common task to check whether a user has a particular
|
||||
permission. For that reason, Django provides a shortcut for that case: the
|
||||
``permission_required()`` decorator. Using this decorator, the earlier example
|
||||
|
@ -67,6 +67,13 @@ particular:
|
||||
likely to get lost. If a particular ticket is controversial, please move
|
||||
discussion to `django-developers`_.
|
||||
|
||||
* **Don't** post to django-developers just to announce that you have filed
|
||||
a bug report. All the tickets are mailed to another list
|
||||
(`django-updates`_), which is tracked by developers and triagers, so we
|
||||
see them as they are filed.
|
||||
|
||||
.. _django-updates: http://groups.google.com/group/django-updates
|
||||
|
||||
Reporting security issues
|
||||
=========================
|
||||
|
||||
|
@ -41,10 +41,10 @@ CsrfMiddleware does two things:
|
||||
This ensures that only forms that have originated from your web site
|
||||
can be used to POST data back.
|
||||
|
||||
It deliberately only targets HTTP POST requests (and the corresponding
|
||||
POST forms). GET requests ought never to have side effects (if you are
|
||||
using HTTP GET and POST correctly), and so a CSRF attack with a GET
|
||||
request will always be harmless.
|
||||
It deliberately only targets HTTP POST requests (and the corresponding POST
|
||||
forms). GET requests ought never to have any potentially dangerous side
|
||||
effects (see `9.1.1 Safe Methods, HTTP 1.1, RFC 2616`_), and so a
|
||||
CSRF attack with a GET request ought to be harmless.
|
||||
|
||||
POST requests that are not accompanied by a session cookie are not protected,
|
||||
but they do not need to be protected, since the 'attacking' web site
|
||||
@ -54,6 +54,8 @@ The Content-Type is checked before modifying the response, and only
|
||||
pages that are served as 'text/html' or 'application/xml+xhtml'
|
||||
are modified.
|
||||
|
||||
.. _9.1.1 Safe Methods, HTTP 1.1, RFC 2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
|
||||
|
||||
Limitations
|
||||
===========
|
||||
|
||||
|
@ -35,6 +35,7 @@ How to use Databrowse
|
||||
2. Register a number of models with the Databrowse site::
|
||||
|
||||
from django.contrib import databrowse
|
||||
from myapp.models import SomeModel, SomeOtherModel
|
||||
|
||||
databrowse.site.register(SomeModel)
|
||||
databrowse.site.register(SomeOtherModel)
|
||||
|
@ -235,6 +235,7 @@ The ``dumpdata`` command can be used to generate input for ``loaddata``.
|
||||
|
||||
reset [appname appname ...]
|
||||
---------------------------
|
||||
|
||||
Executes the equivalent of ``sqlreset`` for the given appnames.
|
||||
|
||||
runfcgi [options]
|
||||
@ -426,7 +427,46 @@ test
|
||||
|
||||
Discover and run tests for all installed models. See `Testing Django applications`_ for more information.
|
||||
|
||||
.. _testing django applications: ../testing/
|
||||
.. _testing Django applications: ../testing/
|
||||
|
||||
testserver [fixture fixture ...]
|
||||
--------------------------------
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Runs a Django development server (as in ``runserver``) using data from the
|
||||
given fixture(s).
|
||||
|
||||
For example, this command::
|
||||
|
||||
django-admin.py testserver mydata.json
|
||||
|
||||
...would perform the following steps:
|
||||
|
||||
1. Create a test database, as described in `testing Django applications`_.
|
||||
2. Populate the test database with fixture data from the given fixtures.
|
||||
(For more on fixtures, see the documentation for ``loaddata`` above.)
|
||||
3. Runs the Django development server (as in ``runserver``), pointed at
|
||||
this newly created test database instead of your production database.
|
||||
|
||||
This is useful in a number of ways:
|
||||
|
||||
* When you're writing `unit tests`_ of how your views act with certain
|
||||
fixture data, you can use ``testserver`` to interact with the views in
|
||||
a Web browser, manually.
|
||||
|
||||
* Let's say you're developing your Django application and have a "pristine"
|
||||
copy of a database that you'd like to interact with. You can dump your
|
||||
database to a fixture (using the ``dumpdata`` command, explained above),
|
||||
then use ``testserver`` to run your Web application with that data. With
|
||||
this arrangement, you have the flexibility of messing up your data
|
||||
in any way, knowing that whatever data changes you're making are only
|
||||
being made to a test database.
|
||||
|
||||
Note that this server can only run on the default port on localhost; it does
|
||||
not yet accept a ``host`` or ``port`` parameter.
|
||||
|
||||
.. _unit tests: ../testing/
|
||||
|
||||
validate
|
||||
--------
|
||||
|
@ -40,7 +40,7 @@ simple weblog app that drives the blog on djangoproject.com::
|
||||
}
|
||||
|
||||
urlpatterns = patterns('django.views.generic.date_based',
|
||||
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/(?P<slug>[-\w]+)/$', 'object_detail', dict(info_dict, slug_field='slug')),
|
||||
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/(?P<slug>[-\w]+)/$', 'object_detail', info_dict),
|
||||
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/$', 'archive_day', info_dict),
|
||||
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', 'archive_month', info_dict),
|
||||
(r'^(?P<year>\d{4})/$', 'archive_year', info_dict),
|
||||
@ -603,7 +603,7 @@ future, the view will throw a 404 error by default, unless you set
|
||||
|
||||
Otherwise, ``slug`` should be the slug of the given object, and
|
||||
``slug_field`` should be the name of the slug field in the ``QuerySet``'s
|
||||
model.
|
||||
model. By default, ``slug_field`` is ``'slug'``.
|
||||
|
||||
**Optional arguments:**
|
||||
|
||||
@ -804,7 +804,7 @@ A page representing an individual object.
|
||||
|
||||
Otherwise, ``slug`` should be the slug of the given object, and
|
||||
``slug_field`` should be the name of the slug field in the ``QuerySet``'s
|
||||
model.
|
||||
model. By default, ``slug_field`` is ``'slug'``.
|
||||
|
||||
**Optional arguments:**
|
||||
|
||||
@ -948,7 +948,7 @@ object. This uses the automatic manipulators that come with Django models.
|
||||
|
||||
Otherwise, ``slug`` should be the slug of the given object, and
|
||||
``slug_field`` should be the name of the slug field in the ``QuerySet``'s
|
||||
model.
|
||||
model. By default, ``slug_field`` is ``'slug'``.
|
||||
|
||||
**Optional arguments:**
|
||||
|
||||
@ -1033,7 +1033,7 @@ contain a form that POSTs to the same URL.
|
||||
|
||||
Otherwise, ``slug`` should be the slug of the given object, and
|
||||
``slug_field`` should be the name of the slug field in the ``QuerySet``'s
|
||||
model.
|
||||
model. By default, ``slug_field`` is ``'slug'``.
|
||||
|
||||
* ``post_delete_redirect``: A URL to which the view will redirect after
|
||||
deleting the object.
|
||||
|
@ -91,6 +91,12 @@ django.middleware.gzip.GZipMiddleware
|
||||
Compresses content for browsers that understand gzip compression (all modern
|
||||
browsers).
|
||||
|
||||
It is suggested to place this first in the middleware list, so that the
|
||||
compression of the response content is the last thing that happens. Will not
|
||||
compress content bodies less than 200 bytes long, when the response code is
|
||||
something other than 200, Javascript files (for IE compatibitility), or
|
||||
responses that have the ``Content-Encoding`` header already specified.
|
||||
|
||||
django.middleware.http.ConditionalGetMiddleware
|
||||
-----------------------------------------------
|
||||
|
||||
|
@ -415,7 +415,8 @@ form::
|
||||
|
||||
models.SlugField(prepopulate_from=("pre_name", "name"))
|
||||
|
||||
``prepopulate_from`` doesn't accept DateTimeFields.
|
||||
``prepopulate_from`` doesn't accept DateTimeFields, ForeignKeys nor
|
||||
ManyToManyFields.
|
||||
|
||||
The admin represents ``SlugField`` as an ``<input type="text">`` (a
|
||||
single-line input).
|
||||
|
@ -63,6 +63,30 @@ computer, you'll have to tell mod_python where your project can be found:
|
||||
**PythonPath "['/path/to/project'] + sys.path"**
|
||||
</Location>
|
||||
|
||||
The value you use for ``PythonPath`` should include the parent directories of
|
||||
all the modules you are going to import in your application. It should also
|
||||
include the parent directory of the ``DJANGO_SETTINGS_MODULE`` location. This
|
||||
is exactly the same situation as setting the Python path for interactive
|
||||
usage. Whenever you try to import something, Python will run through all the
|
||||
directories in ``sys.path`` in turn, from first to last, and try to import
|
||||
from each directory until one succeeds.
|
||||
|
||||
An example might make this clearer. Suppose
|
||||
you have some applications under ``/usr/local/django-apps/`` (for example,
|
||||
``/usr/local/django-apps/weblog/`` and so forth), your settings file is at
|
||||
``/var/www/mysite/settings.py`` and you have specified
|
||||
``DJANGO_SETTINGS_MODULE`` as in the above example. In this case, you would
|
||||
need to write your ``PythonPath`` directive as::
|
||||
|
||||
PythonPath "['/var/production/django-apps/', '/var/www'] + sys.path"
|
||||
|
||||
With this path, ``import weblog`` and ``import mysite.settings`` will both
|
||||
work. If you had ``import blogroll`` in your code somewhere and ``blogroll``
|
||||
lived under the ``weblog/`` directory, you would *also* need to add
|
||||
``/var/production/django-apps/weblog/`` to your ``PythonPath``. Remember: the
|
||||
**parent directories** of anything you import directly must be on the Python
|
||||
path.
|
||||
|
||||
.. caution::
|
||||
|
||||
If you're using Windows, remember that the path will contain backslashes.
|
||||
|
@ -678,7 +678,7 @@ The easiest way is to iterate over the form's fields, with
|
||||
<form method="post" action="">
|
||||
<dl>
|
||||
{% for field in form %}
|
||||
<dt>{{ field.label }}</dt>
|
||||
<dt>{{ field.label_tag }}</dt>
|
||||
<dd>{{ field }}</dd>
|
||||
{% if field.help_text %}<dd>{{ field.help_text }}</dd>{% endif %}
|
||||
{% if field.errors %}<dd class="myerrors">{{ field.errors }}</dd>{% endif %}
|
||||
@ -698,11 +698,11 @@ For example::
|
||||
|
||||
<form method="post" action="">
|
||||
<ul class="myformclass">
|
||||
<li>{{ form.sender.label }} {{ form.sender }}</li>
|
||||
<li>{{ form.sender.label_tag }} {{ form.sender }}</li>
|
||||
<li class="helptext">{{ form.sender.help_text }}</li>
|
||||
{% if form.sender.errors %}<ul class="errorlist">{{ form.sender.errors }}</ul>{% endif %}
|
||||
|
||||
<li>{{ form.subject.label }} {{ form.subject }}</li>
|
||||
<li>{{ form.subject.label_tag }} {{ form.subject }}</li>
|
||||
<li class="helptext">{{ form.subject.help_text }}</li>
|
||||
{% if form.subject.errors %}<ul class="errorlist">{{ form.subject.errors }}</ul>{% endif %}
|
||||
|
||||
@ -962,7 +962,7 @@ validation if a particular field's value is not given. ``initial`` values are
|
||||
~~~~~~~~~~
|
||||
|
||||
The ``widget`` argument lets you specify a ``Widget`` class to use when
|
||||
rendering this ``Field``. See "Widgets" below for more information.
|
||||
rendering this ``Field``. See "Widgets"_ below for more information.
|
||||
|
||||
``help_text``
|
||||
~~~~~~~~~~~~~
|
||||
@ -1129,6 +1129,24 @@ If no ``input_formats`` argument is provided, the default input formats are::
|
||||
'%m/%d/%y %H:%M', # '10/25/06 14:30'
|
||||
'%m/%d/%y', # '10/25/06'
|
||||
|
||||
``DecimalField``
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
* Default widget: ``TextInput``
|
||||
* Empty value: ``None``
|
||||
* Normalizes to: A Python ``decimal``.
|
||||
* Validates that the given value is a decimal. Leading and trailing
|
||||
whitespace is ignored.
|
||||
|
||||
Takes four optional arguments: ``max_value``, ``min_value``, ``max_digits``,
|
||||
and ``decimal_places``. The first two define the limits for the fields value.
|
||||
``max_digits`` is the maximum number of digits (those before the decimal
|
||||
point plus those after the decimal point, with leading zeros stripped)
|
||||
permitted in the value, whilst ``decimal_places`` is the maximum number of
|
||||
decimal places permitted.
|
||||
|
||||
``EmailField``
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
@ -1199,6 +1217,9 @@ When you use a ``FileField`` on a form, you must also remember to
|
||||
* Validates that the given value is an integer. Leading and trailing
|
||||
whitespace is allowed, as in Python's ``int()`` function.
|
||||
|
||||
Takes two optional arguments for validation, ``max_value`` and ``min_value``.
|
||||
These control the range of values permitted in the field.
|
||||
|
||||
``MultipleChoiceField``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -1416,6 +1437,156 @@ like so::
|
||||
senders = MultiEmailField()
|
||||
cc_myself = forms.BooleanField()
|
||||
|
||||
Widgets
|
||||
=======
|
||||
|
||||
A widget is Django's representation of a HTML input element. The widget
|
||||
handles the rendering of the HTML, and the extraction of data from a GET/POST
|
||||
dictionary that corresponds to the widget.
|
||||
|
||||
Django provides a representation of all the basic HTML widgets, plus some
|
||||
commonly used groups of widgets:
|
||||
|
||||
============================ ===========================================
|
||||
Widget HTML Equivalent
|
||||
============================ ===========================================
|
||||
``TextInput`` ``<input type='text' ...``
|
||||
``PasswordInput`` ``<input type='password' ...``
|
||||
``HiddenInput`` ``<input type='hidden' ...``
|
||||
``MultipleHiddenInput`` Multiple ``<input type='hidden' ...``
|
||||
instances.
|
||||
``FileInput`` ``<input type='file' ...``
|
||||
``Textarea`` ``<textarea>...</textarea>``
|
||||
``CheckboxInput`` ``<input type='checkbox' ...``
|
||||
``Select`` ``<select><option ...``
|
||||
``NullBooleanSelect`` Select widget with options 'Unknown',
|
||||
'Yes' and 'No'
|
||||
``SelectMultiple`` ``<select multiple='multiple'><option ...``
|
||||
``RadioSelect`` ``<ul><li><input type='radio' ...``
|
||||
``CheckboxSelectMultiple`` ``<ul><li><input type='checkbox' ...``
|
||||
``MultiWidget`` Wrapper around multiple other widgets
|
||||
``SplitDateTimeWidget`` Wrapper around two ``TextInput`` widgets:
|
||||
one for the Date, and one for the Time.
|
||||
============================ ===========================================
|
||||
|
||||
Specifying widgets
|
||||
------------------
|
||||
|
||||
Whenever you specify a field on a form, Django will use a default widget
|
||||
that is appropriate to the type of data that is to be displayed. To find
|
||||
which widget is used on which field, see the documentation for the
|
||||
built-in Field classes.
|
||||
|
||||
However, if you want to use a different widget for a field, you can -
|
||||
just use the 'widget' argument on the field definition. For example::
|
||||
|
||||
class CommentForm(forms.Form):
|
||||
name = forms.CharField()
|
||||
url = forms.URLField()
|
||||
comment = forms.CharField(widget=forms.Textarea)
|
||||
|
||||
This would specify a form with a comment that uses a larger Textarea widget,
|
||||
rather than the default TextInput widget.
|
||||
|
||||
Customizing widget instances
|
||||
----------------------------
|
||||
|
||||
When Django renders a widget as HTML, it only renders the bare minimum
|
||||
HTML - Django doesn't add a class definition, or any other widget-specific
|
||||
attributes. This means that all 'TextInput' widgets will appear the same
|
||||
on your web page.
|
||||
|
||||
If you want to make one widget look different to another, you need to
|
||||
specify additional attributes for each widget. When you specify a
|
||||
widget, you can provide a list of attributes that will be added to the
|
||||
rendered HTML for the widget.
|
||||
|
||||
For example, take the following simple form::
|
||||
|
||||
class CommentForm(forms.Form):
|
||||
name = forms.CharField()
|
||||
url = forms.URLField()
|
||||
comment = forms.CharField()
|
||||
|
||||
This form will include three default TextInput widgets, with default rendering -
|
||||
no CSS class, no extra attributes. This means that the inputs boxes provided for
|
||||
each widget will be rendered exactly the same::
|
||||
|
||||
>>> f = CommentForm(auto_id=False)
|
||||
>>> f.as_table()
|
||||
<tr><th>Name:</th><td><input type="text" name="name" /></td></tr>
|
||||
<tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
|
||||
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
|
||||
|
||||
On a real web page, you probably don't want every widget to look the same. You
|
||||
might want a larger input element for the comment, and you might want the
|
||||
'name' widget to have some special CSS class. To do this, you specify a
|
||||
custom widget for your fields, and specify some attributes to use
|
||||
when rendering those widgets::
|
||||
|
||||
class CommentForm(forms.Form):
|
||||
name = forms.CharField(
|
||||
widget=forms.TextInput(attrs={'class':'special'}))
|
||||
url = forms.URLField()
|
||||
comment = forms.CharField(
|
||||
widget=forms.TextInput(attrs={'size':'40'}))
|
||||
|
||||
Django will then include the extra attributes in the rendered output::
|
||||
|
||||
>>> f = CommentForm(auto_id=False)
|
||||
>>> f.as_table()
|
||||
<tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr>
|
||||
<tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
|
||||
<tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
|
||||
|
||||
Custom Widgets
|
||||
--------------
|
||||
|
||||
When you start to write a lot of forms, you will probably find that you will
|
||||
reuse certain sets of widget attributes over and over again. Rather than
|
||||
repeat these attribute definitions every time you need them, Django allows
|
||||
you to capture those definitions as a custom widget.
|
||||
|
||||
For example, if you find that you are including a lot of comment fields on forms,
|
||||
you could capture the idea of a ``TextInput`` with a specific ``size`` attribute
|
||||
as a custom extension to the ``TextInput`` widget::
|
||||
|
||||
class CommentWidget(forms.TextInput):
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs.setdefault('attrs',{}).update({'size': '40'})
|
||||
super(forms.TextInput, self).__init__(*args, **kwargs)
|
||||
|
||||
Then you can use this widget in your forms::
|
||||
|
||||
class CommentForm(forms.Form):
|
||||
name = forms.CharField()
|
||||
url = forms.URLField()
|
||||
comment = forms.CharField(widget=CommentWidget)
|
||||
|
||||
You can even customize your custom widget, in the same way as you would
|
||||
any other widget. Adding a once-off class to your ``CommentWidget`` is as
|
||||
simple as adding an attribute definition::
|
||||
|
||||
class CommentForm(forms.Form):
|
||||
name = forms.CharField(max_length=20)
|
||||
url = forms.URLField()
|
||||
comment = forms.CharField(
|
||||
widget=CommentWidget(attrs={'class': 'special'}))
|
||||
|
||||
Django also makes it easy to specify a custom field type that uses your custom
|
||||
widget. For example, you could define a customized field type for comments
|
||||
by defining::
|
||||
|
||||
class CommentInput(forms.CharField):
|
||||
widget = CommentWidget
|
||||
|
||||
You can then use this field whenever you have a form that requires a comment::
|
||||
|
||||
class CommentForm(forms.Form):
|
||||
name = forms.CharField()
|
||||
url = forms.URLField()
|
||||
comment = CommentInput()
|
||||
|
||||
Generating forms for models
|
||||
===========================
|
||||
|
||||
|
@ -38,6 +38,16 @@ All attributes except ``session`` should be considered read-only.
|
||||
elif request.method == 'POST':
|
||||
do_something_else()
|
||||
|
||||
``encoding``
|
||||
**New in Django development version**
|
||||
|
||||
A string representing the current encoding used to decode form submission
|
||||
data (or ``None``, which means the ``DEFAULT_CHARSET`` setting is used).
|
||||
You can write to this attribute to change the encoding used when accessing
|
||||
the form data. Any subsequent attribute accesses (such as reading from
|
||||
``GET`` or ``POST``) will use the new ``encoding`` value. Useful if you
|
||||
know the form data is not in the ``DEFAULT_CHARSET`` encoding.
|
||||
|
||||
``GET``
|
||||
A dictionary-like object containing all given HTTP GET parameters. See the
|
||||
``QueryDict`` documentation below.
|
||||
@ -342,7 +352,7 @@ hard-coded strings. If you use this technique, follow these guidelines:
|
||||
Methods
|
||||
-------
|
||||
|
||||
``__init__(content='', mimetype=DEFAULT_CONTENT_TYPE)``
|
||||
``__init__(content='', mimetype=None, status=200, content_type=DEFAULT_CONTENT_TYPE)``
|
||||
Instantiates an ``HttpResponse`` object with the given page content (a
|
||||
string) and MIME type. The ``DEFAULT_CONTENT_TYPE`` is ``'text/html'``.
|
||||
|
||||
@ -350,6 +360,16 @@ Methods
|
||||
return strings, and those strings will be joined together to form the
|
||||
content of the response.
|
||||
|
||||
``status`` is the `HTTP Status code`_ for the response.
|
||||
|
||||
**(New in Django development version)** ``content_type`` is an alias for
|
||||
``mimetype``. Historically, the parameter was only called ``mimetype``,
|
||||
but since this is actually the value included in the HTTP ``Content-Type``
|
||||
header, it can also include the character set encoding, which makes it
|
||||
more than just a MIME type specification. If ``mimetype`` is specifiedi
|
||||
(not None), that value is used. Otherwise, ``content_type`` is used. If
|
||||
neither is given, the ``DEFAULT_CONTENT_TYPE`` setting is used.
|
||||
|
||||
``__setitem__(header, value)``
|
||||
Sets the given header name to the given value. Both ``header`` and
|
||||
``value`` should be strings.
|
||||
@ -396,6 +416,8 @@ Methods
|
||||
``write(content)``, ``flush()`` and ``tell()``
|
||||
These methods make an ``HttpResponse`` instance a file-like object.
|
||||
|
||||
.. _HTTP Status code: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10
|
||||
|
||||
HttpResponse subclasses
|
||||
-----------------------
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user