1
0
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:
Russell Keith-Magee 2007-08-17 15:05:54 +00:00
parent 0f92ac52cb
commit fcec755f01
112 changed files with 13108 additions and 7247 deletions

11
AUTHORS
View File

@ -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

View File

@ -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:

View File

@ -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.

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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 "At"
#: utils/dates.py:32
msgid "Sept."

View File

@ -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 "

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View 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 ""

File diff suppressed because it is too large Load Diff

View File

@ -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"

File diff suppressed because it is too large Load Diff

View File

@ -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()

View File

@ -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> &rsaquo;

View File

@ -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'):

View File

@ -96,7 +96,10 @@ class Comment(models.Model):
return "%s: %s..." % (self.user.username, self.comment[:100])
def get_absolute_url(self):
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):
try:
return self.get_content_object().get_absolute_url() + "#c" + str(self.id)
except AttributeError:
return ""
def get_content_object(self):
"""

View File

@ -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():

View File

@ -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

View 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)

View 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',
}

View File

@ -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.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:

View File

@ -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

View 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)

View 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))

View 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()

View 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)

View 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()

View 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()

View 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)

View 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)

View 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."

View 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 ''

View 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)

View 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."

View 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)

View 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()

View 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)

View 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))

View 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))

View 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))

View 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))

View 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))

View 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))

View 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.")

View 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))

View 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)))

View 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)

View 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()

View 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)

View 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)

View 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)

View 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()

View 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)

View 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)

View File

@ -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):

View File

@ -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)

View File

@ -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.

View File

@ -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)

View File

@ -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" % \

View File

@ -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)), \

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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/)'

View File

@ -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):

View File

@ -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()

View File

@ -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"

View File

@ -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
@ -36,6 +36,7 @@ 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:
@ -89,6 +90,10 @@ 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"):
@ -142,16 +147,18 @@ def create_test_db(verbosity=1, autoclobber=False):
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()

View File

@ -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)

View File

@ -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'

View File

@ -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>

View File

@ -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'):
"""

View File

@ -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):
"""

View File

@ -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):

View File

@ -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())});
}
}
"""

View File

@ -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

View File

@ -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
=========================

View File

@ -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
===========

View File

@ -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)

View File

@ -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
--------

View File

@ -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.

View File

@ -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
-----------------------------------------------

View File

@ -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).

View File

@ -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.

View File

@ -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
===========================

View File

@ -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
-----------------------

View File

@ -190,6 +190,12 @@ deleted::
# request.session['foo'] instead of request.session.
request.session['foo']['bar'] = 'baz'
In the last case of the above example, we can tell the session object
explicitly that it has been modified by setting the ``modified`` attribute on
the session object::
request.session.modified = True
To change this default behavior, set the ``SESSION_SAVE_EVERY_REQUEST`` setting
to ``True``. If ``SESSION_SAVE_EVERY_REQUEST`` is ``True``, Django will save
the session to the database on every single request.

Some files were not shown because too many files have changed in this diff Show More