1
0
mirror of https://github.com/django/django.git synced 2025-07-06 18:59:13 +00:00

queryset-refactor: Merged changed from trunk up to [6463].

git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6466 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2007-10-08 16:10:39 +00:00
parent 94c320d8a9
commit 7ebf3068c1
75 changed files with 793 additions and 328 deletions

View File

@ -114,6 +114,7 @@ answer newbie questions, and generally made Django that much better:
Enrico <rico.bl@gmail.com> Enrico <rico.bl@gmail.com>
A. Murat Eren <meren@pardus.org.tr> A. Murat Eren <meren@pardus.org.tr>
Ludvig Ericson <ludvig.ericson@gmail.com> Ludvig Ericson <ludvig.ericson@gmail.com>
eriks@win.tue.nl
Dirk Eschler <dirk.eschler@gmx.net> Dirk Eschler <dirk.eschler@gmx.net>
Marc Fargas <telenieko@telenieko.com> Marc Fargas <telenieko@telenieko.com>
Szilveszter Farkas <szilveszter.farkas@gmail.com> Szilveszter Farkas <szilveszter.farkas@gmail.com>
@ -234,6 +235,7 @@ answer newbie questions, and generally made Django that much better:
Jay Parlar <parlar@gmail.com> Jay Parlar <parlar@gmail.com>
pavithran s <pavithran.s@gmail.com> pavithran s <pavithran.s@gmail.com>
Barry Pederson <bp@barryp.org> Barry Pederson <bp@barryp.org>
permonik@mesias.brnonet.cz
petr.marhoun@gmail.com petr.marhoun@gmail.com
pgross@thoughtworks.com pgross@thoughtworks.com
phaedo <http://phaedo.cx/> phaedo <http://phaedo.cx/>
@ -312,7 +314,8 @@ answer newbie questions, and generally made Django that much better:
Vlado <vlado@labath.org> Vlado <vlado@labath.org>
Milton Waddams Milton Waddams
wam-djangobug@wamber.net wam-djangobug@wamber.net
wangchun <yaohua2000@gmail.com> Wang Chun <wangchun@exoweb.net>
Filip Wasilewski <filip.wasilewski@gmail.com>
Filip Wasilewski <filip.wasilewski@gmail.com> Filip Wasilewski <filip.wasilewski@gmail.com>
Dan Watson <http://theidioteque.net/> Dan Watson <http://theidioteque.net/>
Chris Wesseling <Chris.Wesseling@cwi.nl> Chris Wesseling <Chris.Wesseling@cwi.nl>
@ -321,6 +324,7 @@ answer newbie questions, and generally made Django that much better:
Rachel Willmer <http://www.willmer.com/kb/> Rachel Willmer <http://www.willmer.com/kb/>
Gary Wilson <gary.wilson@gmail.com> Gary Wilson <gary.wilson@gmail.com>
Jakub Wiśniowski <restless.being@gmail.com> Jakub Wiśniowski <restless.being@gmail.com>
Maciej Wiśniowski <pigletto@gmail.com>
wojtek wojtek
ye7cakf02@sneakemail.com ye7cakf02@sneakemail.com
ymasuda@ethercube.com ymasuda@ethercube.com

View File

@ -14,7 +14,8 @@ def compile_messages(locale=None):
basedirs = [os.path.join('conf', 'locale'), 'locale'] basedirs = [os.path.join('conf', 'locale'), 'locale']
if os.environ.get('DJANGO_SETTINGS_MODULE'): if os.environ.get('DJANGO_SETTINGS_MODULE'):
from django.conf import settings from django.conf import settings
basedirs += settings.LOCALE_PATHS if hasattr(settings, 'LOCALE_PATHS'):
basedirs += settings.LOCALE_PATHS
# Gather existing directories. # Gather existing directories.
basedirs = set(map(os.path.abspath, filter(os.path.isdir, basedirs))) basedirs = set(map(os.path.abspath, filter(os.path.isdir, basedirs)))

View File

@ -74,59 +74,62 @@ def make_messages():
if os.path.exists(potfile): if os.path.exists(potfile):
os.unlink(potfile) os.unlink(potfile)
all_files = []
for (dirpath, dirnames, filenames) in os.walk("."): for (dirpath, dirnames, filenames) in os.walk("."):
for file in filenames: all_files.extend([(dirpath, f) for f in filenames])
if domain == 'djangojs' and file.endswith('.js'): all_files.sort()
if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath)) for dirpath, file in all_files:
if domain == 'djangojs' and file.endswith('.js'):
if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
src = open(os.path.join(dirpath, file), "rb").read()
src = pythonize_re.sub('\n#', src)
open(os.path.join(dirpath, '%s.py' % file), "wb").write(src)
thefile = '%s.py' % file
cmd = 'xgettext %s -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy: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, 't')
msgs = stdout.read()
errors = stderr.read()
if errors:
print "errors happened while running xgettext on %s" % file
print errors
sys.exit(8)
old = '#: '+os.path.join(dirpath, thefile)[2:]
new = '#: '+os.path.join(dirpath, file)[2:]
msgs = msgs.replace(old, new)
if msgs:
open(potfile, 'ab').write(msgs)
os.unlink(os.path.join(dirpath, thefile))
elif domain == 'django' and (file.endswith('.py') or file.endswith('.html')):
thefile = file
if file.endswith('.html'):
src = open(os.path.join(dirpath, file), "rb").read() src = open(os.path.join(dirpath, file), "rb").read()
src = pythonize_re.sub('\n#', src)
open(os.path.join(dirpath, '%s.py' % file), "wb").write(src)
thefile = '%s.py' % file 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"' % ( open(os.path.join(dirpath, thefile), "wb").write(templatize(src))
os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile)) if verbose:
(stdin, stdout, stderr) = os.popen3(cmd, 't') sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
msgs = stdout.read() 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"' % (
errors = stderr.read() domain, os.path.join(dirpath, thefile))
if errors: (stdin, stdout, stderr) = os.popen3(cmd, 't')
print "errors happened while running xgettext on %s" % file msgs = stdout.read()
print errors errors = stderr.read()
sys.exit(8) if errors:
print "errors happened while running xgettext on %s" % file
print errors
sys.exit(8)
if thefile != file:
old = '#: '+os.path.join(dirpath, thefile)[2:] old = '#: '+os.path.join(dirpath, thefile)[2:]
new = '#: '+os.path.join(dirpath, file)[2:] new = '#: '+os.path.join(dirpath, file)[2:]
msgs = msgs.replace(old, new) msgs = msgs.replace(old, new)
if msgs: if os.path.exists(potfile):
open(potfile, 'ab').write(msgs) # Strip the header
msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
else:
msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
if msgs:
open(potfile, 'ab').write(msgs)
if thefile != file:
os.unlink(os.path.join(dirpath, thefile)) os.unlink(os.path.join(dirpath, thefile))
elif domain == 'django' and (file.endswith('.py') or file.endswith('.html')):
thefile = file
if file.endswith('.html'):
src = open(os.path.join(dirpath, file), "rb").read()
thefile = '%s.py' % file
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, 't')
msgs = stdout.read()
errors = stderr.read()
if errors:
print "errors happened while running xgettext on %s" % file
print errors
sys.exit(8)
if thefile != file:
old = '#: '+os.path.join(dirpath, thefile)[2:]
new = '#: '+os.path.join(dirpath, file)[2:]
msgs = msgs.replace(old, new)
if os.path.exists(potfile):
# Strip the header
msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
else:
msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
if msgs:
open(potfile, 'ab').write(msgs)
if thefile != file:
os.unlink(os.path.join(dirpath, thefile))
if os.path.exists(potfile): if os.path.exists(potfile):
(stdin, stdout, stderr) = os.popen3('msguniq --to-code=utf-8 "%s"' % potfile, 'b') (stdin, stdout, stderr) = os.popen3('msguniq --to-code=utf-8 "%s"' % potfile, 'b')

View File

@ -1,6 +1,7 @@
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # Translation of django.po to German
# This file is distributed under the same license as the PACKAGE package. #
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # Copyright (C) 2005-2007,
# This file is distributed under the same license as the django package.
# #
msgid "" msgid ""
"" ""
@ -1629,76 +1630,76 @@ msgstr "Webseite"
msgid "flat pages" msgid "flat pages"
msgstr "Webseiten" msgstr "Webseiten"
#: contrib/humanize/templatetags/humanize.py:17 #: contrib/humanize/templatetags/humanize.py:20
msgid "th" msgid "th"
msgstr "" msgstr "."
#: contrib/humanize/templatetags/humanize.py:17 #: contrib/humanize/templatetags/humanize.py:20
msgid "st" msgid "st"
msgstr "" msgstr "."
#: contrib/humanize/templatetags/humanize.py:17 #: contrib/humanize/templatetags/humanize.py:20
msgid "nd" msgid "nd"
msgstr "" msgstr "."
#: contrib/humanize/templatetags/humanize.py:17 #: contrib/humanize/templatetags/humanize.py:20
msgid "rd" msgid "rd"
msgstr "" msgstr "."
#: contrib/humanize/templatetags/humanize.py:47
#, python-format
msgid "%(value).1f million"
msgid_plural "%(value).1f million"
msgstr[0] ""
msgstr[1] ""
#: contrib/humanize/templatetags/humanize.py:50 #: contrib/humanize/templatetags/humanize.py:50
#, python-format #, python-format
msgid "%(value).1f billion" msgid "%(value).1f million"
msgid_plural "%(value).1f billion" msgid_plural "%(value).1f million"
msgstr[0] "" msgstr[0] "%(value).1f Million"
msgstr[1] "" msgstr[1] "%(value).1f Millionen"
#: contrib/humanize/templatetags/humanize.py:53 #: contrib/humanize/templatetags/humanize.py:53
#, python-format #, python-format
msgid "%(value).1f billion"
msgid_plural "%(value).1f billion"
msgstr[0] "%(value).1f Milliarde"
msgstr[1] "%(value).1f Milliarden"
#: contrib/humanize/templatetags/humanize.py:56
#, python-format
msgid "%(value).1f trillion" msgid "%(value).1f trillion"
msgid_plural "%(value).1f trillion" msgid_plural "%(value).1f trillion"
msgstr[0] "" msgstr[0] "%(value).1f Billion"
msgstr[1] "" msgstr[1] "%(value).1f Billionen"
#: contrib/humanize/templatetags/humanize.py:68 #: contrib/humanize/templatetags/humanize.py:71
msgid "one" msgid "one"
msgstr "ein" msgstr "ein"
#: contrib/humanize/templatetags/humanize.py:68 #: contrib/humanize/templatetags/humanize.py:71
msgid "two" msgid "two"
msgstr "zwei" msgstr "zwei"
#: contrib/humanize/templatetags/humanize.py:68 #: contrib/humanize/templatetags/humanize.py:71
msgid "three" msgid "three"
msgstr "drei" msgstr "drei"
#: contrib/humanize/templatetags/humanize.py:68 #: contrib/humanize/templatetags/humanize.py:71
msgid "four" msgid "four"
msgstr "vier" msgstr "vier"
#: contrib/humanize/templatetags/humanize.py:68 #: contrib/humanize/templatetags/humanize.py:71
msgid "five" msgid "five"
msgstr "fünf" msgstr "fünf"
#: contrib/humanize/templatetags/humanize.py:68 #: contrib/humanize/templatetags/humanize.py:71
msgid "six" msgid "six"
msgstr "sechs" msgstr "sechs"
#: contrib/humanize/templatetags/humanize.py:68 #: contrib/humanize/templatetags/humanize.py:71
msgid "seven" msgid "seven"
msgstr "sieben" msgstr "sieben"
#: contrib/humanize/templatetags/humanize.py:68 #: contrib/humanize/templatetags/humanize.py:71
msgid "eight" msgid "eight"
msgstr "acht" msgstr "acht"
#: contrib/humanize/templatetags/humanize.py:68 #: contrib/humanize/templatetags/humanize.py:71
msgid "nine" msgid "nine"
msgstr "neun" msgstr "neun"

View File

@ -6,7 +6,6 @@
{% endblock %} {% endblock %}
{% block stylesheet %}{% admin_media_prefix %}css/forms.css{% endblock %} {% block stylesheet %}{% admin_media_prefix %}css/forms.css{% endblock %}
{% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% 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 breadcrumbs %}{% if not is_popup %} {% block breadcrumbs %}{% if not is_popup %}
<div class="breadcrumbs"> <div class="breadcrumbs">
<a href="../../../../">{% trans "Home" %}</a> &rsaquo; <a href="../../../../">{% trans "Home" %}</a> &rsaquo;

View File

@ -22,7 +22,14 @@
{% block branding %}{% endblock %} {% block branding %}{% endblock %}
</div> </div>
{% if user.is_authenticated and user.is_staff %} {% if user.is_authenticated and user.is_staff %}
<div id="user-tools">{% trans 'Welcome,' %} <strong>{% if user.first_name %}{{ user.first_name|escape }}{% else %}{{ user.username }}{% endif %}</strong>. {% block userlinks %}<a href="doc/">{% trans 'Documentation' %}</a> / <a href="password_change/">{% trans 'Change password' %}</a> / <a href="logout/">{% trans 'Log out' %}</a>{% endblock %}</div> <div id="user-tools">
{% trans 'Welcome,' %} <strong>{% if user.first_name %}{{ user.first_name|escape }}{% else %}{{ user.username }}{% endif %}</strong>.
{% block userlinks %}
<a href="{% url django.contrib.admin.views.doc.doc_index %}">{% trans 'Documentation' %}</a>
/ <a href="{% url django.contrib.auth.views.password_change %}">{% trans 'Change password' %}</a>
/ <a href="{% url django.contrib.auth.views.logout %}">{% trans 'Log out' %}</a>
{% endblock %}
</div>
{% endif %} {% endif %}
{% block nav-global %}{% endblock %} {% block nav-global %}{% endblock %}
</div> </div>

View File

@ -7,7 +7,6 @@
{% block stylesheet %}{% admin_media_prefix %}css/forms.css{% endblock %} {% block stylesheet %}{% admin_media_prefix %}css/forms.css{% endblock %}
{% block coltype %}{% if ordered_objects %}colMS{% else %}colM{% endif %}{% endblock %} {% block coltype %}{% if ordered_objects %}colMS{% else %}colM{% endif %}{% endblock %}
{% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% 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 breadcrumbs %}{% if not is_popup %} {% block breadcrumbs %}{% if not is_popup %}
<div class="breadcrumbs"> <div class="breadcrumbs">
<a href="../../../">{% trans "Home" %}</a> &rsaquo; <a href="../../../">{% trans "Home" %}</a> &rsaquo;

View File

@ -2,7 +2,6 @@
{% load adminmedia admin_list i18n %} {% load adminmedia admin_list i18n %}
{% block stylesheet %}{% admin_media_prefix %}css/changelists.css{% endblock %} {% block stylesheet %}{% admin_media_prefix %}css/changelists.css{% endblock %}
{% block bodyclass %}change-list{% endblock %} {% block bodyclass %}change-list{% 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 %}
{% if not is_popup %}{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans "Home" %}</a> &rsaquo; {{ cl.opts.verbose_name_plural|capfirst|escape }}</div>{% endblock %}{% endif %} {% if not is_popup %}{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans "Home" %}</a> &rsaquo; {{ cl.opts.verbose_name_plural|capfirst|escape }}</div>{% endblock %}{% endif %}
{% block coltype %}flex{% endblock %} {% block coltype %}flex{% endblock %}
{% block content %} {% block content %}

View File

@ -1,6 +1,5 @@
{% extends "admin/base_site.html" %} {% extends "admin/base_site.html" %}
{% load i18n %} {% load i18n %}
{% 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 %} {% block breadcrumbs %}
<div class="breadcrumbs"> <div class="breadcrumbs">
<a href="../../../../">{% trans "Home" %}</a> &rsaquo; <a href="../../../../">{% trans "Home" %}</a> &rsaquo;

View File

@ -1,6 +1,5 @@
{% extends "admin/base_site.html" %} {% extends "admin/base_site.html" %}
{% load i18n %} {% load i18n %}
{% 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 %} {% block breadcrumbs %}
<div class="breadcrumbs"><a href="../../../../">{% trans 'Home' %}</a> &rsaquo; <a href="../../">{{ module_name|escape }}</a> &rsaquo; <a href="../">{{ object|escape|truncatewords:"18" }}</a> &rsaquo; {% trans 'History' %}</div> <div class="breadcrumbs"><a href="../../../../">{% trans 'Home' %}</a> &rsaquo; <a href="../../">{{ module_name|escape }}</a> &rsaquo; <a href="../">{{ object|escape|truncatewords:"18" }}</a> &rsaquo; {% trans 'History' %}</div>
{% endblock %} {% endblock %}

View File

@ -1,7 +1,6 @@
{% extends "admin/base_site.html" %} {% extends "admin/base_site.html" %}
{% block breadcrumbs %}{% load i18n %}<div class="breadcrumbs"><a href="../../">{% trans "Home" %}</a> &rsaquo; <a href="../">{% trans "Documentation" %}</a> &rsaquo; {% trans "Bookmarklets" %}</div>{% endblock %} {% block breadcrumbs %}{% load i18n %}<div class="breadcrumbs"><a href="../../">{% trans "Home" %}</a> &rsaquo; <a href="../">{% trans "Documentation" %}</a> &rsaquo; {% trans "Bookmarklets" %}</div>{% endblock %}
{% block userlinks %}<a href="../../password_change/">{% trans 'Change password' %}</a> / <a href="../../logout/">{% trans 'Log out' %}</a>{% endblock %}
{% block title %}{% trans "Documentation bookmarklets" %}{% endblock %} {% block title %}{% trans "Documentation bookmarklets" %}{% endblock %}
{% block content %} {% block content %}

View File

@ -1,7 +1,6 @@
{% extends "admin/base_site.html" %} {% extends "admin/base_site.html" %}
{% load i18n %} {% load i18n %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Documentation</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Documentation</div>{% endblock %}
{% block userlinks %}<a href="../password_change/">{% trans 'Change password' %}</a> / <a href="../logout/">{% trans 'Log out' %}</a>{% endblock %}
{% block title %}Documentation{% endblock %} {% block title %}Documentation{% endblock %}
{% block content %} {% block content %}

View File

@ -1,7 +1,6 @@
{% extends "admin/base_site.html" %} {% extends "admin/base_site.html" %}
{% load i18n %} {% load i18n %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Documentation</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Documentation</div>{% endblock %}
{% block userlinks %}<a href="../password_change/">{% trans 'Change password' %}</a> / <a href="../logout/">{% trans 'Log out' %}</a>{% endblock %}
{% block title %}Please install docutils{% endblock %} {% block title %}Please install docutils{% endblock %}
{% block content %} {% block content %}

View File

@ -1,6 +1,5 @@
{% extends "admin/base_site.html" %} {% extends "admin/base_site.html" %}
{% load i18n %} {% load i18n %}
{% block userlinks %}<a href="../../../password_change/">{% trans 'Change password' %}</a> / <a href="../../../logout/">{% trans 'Log out' %}</a>{% endblock %}
{% block extrahead %} {% block extrahead %}
{{ block.super }} {{ block.super }}
<style type="text/css"> <style type="text/css">

View File

@ -2,7 +2,6 @@
{% load i18n %} {% load i18n %}
{% block coltype %}colSM{% endblock %} {% block coltype %}colSM{% endblock %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; Models</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; Models</div>{% endblock %}
{% block userlinks %}<a href="../../password_change/">{% trans 'Change password' %}</a> / <a href="../../logout/">{% trans 'Log out' %}</a>{% endblock %}
{% block title %}Models{% endblock %} {% block title %}Models{% endblock %}

View File

@ -1,7 +1,6 @@
{% extends "admin/base_site.html" %} {% extends "admin/base_site.html" %}
{% load i18n %} {% load i18n %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> &rsaquo; <a href="../../">Documentation</a> &rsaquo; Templates &rsaquo; {{ name|escape }}</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> &rsaquo; <a href="../../">Documentation</a> &rsaquo; Templates &rsaquo; {{ name|escape }}</div>{% endblock %}
{% block userlinks %}<a href="../../../password_change/">{% trans 'Change password' %}</a> / <a href="../../../logout/">{% trans 'Log out' %}</a>{% endblock %}
{% block title %}Template: {{ name|escape }}{% endblock %} {% block title %}Template: {{ name|escape }}{% endblock %}

View File

@ -2,7 +2,6 @@
{% load i18n %} {% load i18n %}
{% block coltype %}colSM{% endblock %} {% block coltype %}colSM{% endblock %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; filters</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; filters</div>{% endblock %}
{% block userlinks %}<a href="../../password_change/">{% trans 'Change password' %}</a> / <a href="../../logout/">{% trans 'Log out' %}</a>{% endblock %}
{% block title %}Template filters{% endblock %} {% block title %}Template filters{% endblock %}
{% block content %} {% block content %}

View File

@ -2,7 +2,6 @@
{% load i18n %} {% load i18n %}
{% block coltype %}colSM{% endblock %} {% block coltype %}colSM{% endblock %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; Tags</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; Tags</div>{% endblock %}
{% block userlinks %}<a href="../../password_change/">{% trans 'Change password' %}</a> / <a href="../../logout/">{% trans 'Log out' %}</a>{% endblock %}
{% block title %}Template tags{% endblock %} {% block title %}Template tags{% endblock %}
{% block content %} {% block content %}

View File

@ -1,7 +1,6 @@
{% extends "admin/base_site.html" %} {% extends "admin/base_site.html" %}
{% load i18n %} {% load i18n %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> &rsaquo; <a href="../../">Documentation</a> &rsaquo; <a href="../">Views</a> &rsaquo; {{ name }}</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> &rsaquo; <a href="../../">Documentation</a> &rsaquo; <a href="../">Views</a> &rsaquo; {{ name }}</div>{% endblock %}
{% block userlinks %}<a href="../../../password_change/">{% trans 'Change password' %}</a> / <a href="../../../logout/">{% trans 'Log out' %}</a>{% endblock %}
{% block title %}View: {{ name }}{% endblock %} {% block title %}View: {{ name }}{% endblock %}
{% block content %} {% block content %}

View File

@ -2,7 +2,6 @@
{% load i18n %} {% load i18n %}
{% block coltype %}colSM{% endblock %} {% block coltype %}colSM{% endblock %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; Views</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; Views</div>{% endblock %}
{% block userlinks %}<a href="../../password_change/">{% trans 'Change password' %}</a> / <a href="../../logout/">{% trans 'Log out' %}</a>{% endblock %}
{% block title %}Views{% endblock %} {% block title %}Views{% endblock %}
{% block content %} {% block content %}

View File

@ -1,6 +1,5 @@
{% extends "admin/base_site.html" %} {% extends "admin/base_site.html" %}
{% load i18n %} {% load i18n %}
{% block userlinks %}<a href="../../doc/">{% trans 'Documentation' %}</a> / {% trans 'Change password' %} / <a href="../../logout/">{% trans 'Log out' %}</a>{% endblock %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password change' %}</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password change' %}</div>{% endblock %}
{% block title %}{% trans 'Password change successful' %}{% endblock %} {% block title %}{% trans 'Password change successful' %}{% endblock %}

View File

@ -1,6 +1,5 @@
{% extends "admin/base_site.html" %} {% extends "admin/base_site.html" %}
{% load i18n %} {% load i18n %}
{% block userlinks %}<a href="../doc/">{% trans 'Documentation' %}</a> / {% trans 'Change password' %} / <a href="../logout/">{% trans 'Log out' %}</a>{% endblock %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password change' %}</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password change' %}</div>{% endblock %}
{% block title %}{% trans 'Password change' %}{% endblock %} {% block title %}{% trans 'Password change' %}{% endblock %}

View File

@ -72,7 +72,7 @@ class FieldWidgetNode(template.Node):
default = None default = None
def __init__(self, bound_field_var): def __init__(self, bound_field_var):
self.bound_field_var = bound_field_var self.bound_field_var = template.Variable(bound_field_var)
def get_nodelist(cls, klass): def get_nodelist(cls, klass):
if klass not in cls.nodelists: if klass not in cls.nodelists:
@ -96,7 +96,7 @@ class FieldWidgetNode(template.Node):
get_nodelist = classmethod(get_nodelist) get_nodelist = classmethod(get_nodelist)
def render(self, context): def render(self, context):
bound_field = template.resolve_variable(self.bound_field_var, context) bound_field = self.bound_field_var.resolve(context)
context.push() context.push()
context['bound_field'] = bound_field context['bound_field'] = bound_field
@ -156,10 +156,10 @@ class StackedBoundRelatedObject(BoundRelatedObject):
class EditInlineNode(template.Node): class EditInlineNode(template.Node):
def __init__(self, rel_var): def __init__(self, rel_var):
self.rel_var = rel_var self.rel_var = template.Variable(rel_var)
def render(self, context): def render(self, context):
relation = template.resolve_variable(self.rel_var, context) relation = self.rel_var.resolve(context)
context.push() context.push()
if relation.field.rel.edit_inline == models.TABULAR: if relation.field.rel.edit_inline == models.TABULAR:
bound_related_object_class = TabularBoundRelatedObject bound_related_object_class = TabularBoundRelatedObject

View File

@ -1,6 +1,11 @@
from django.db import connection from django.db import connection
from django.contrib.auth.models import User from django.contrib.auth.models import User
try:
set
except NameError:
from sets import Set as set # Python 2.3 fallback
class ModelBackend: class ModelBackend:
""" """
Authenticate against django.contrib.auth.models.User Authenticate against django.contrib.auth.models.User

View File

@ -19,6 +19,8 @@ class CommentFormNode(template.Node):
ratings_optional=False, ratings_required=False, rating_options='', ratings_optional=False, ratings_required=False, rating_options='',
is_public=True): is_public=True):
self.content_type = content_type self.content_type = content_type
if obj_id_lookup_var is not None:
obj_id_lookup_var = template.Variable(obj_id_lookup_var)
self.obj_id_lookup_var, self.obj_id, self.free = obj_id_lookup_var, obj_id, free self.obj_id_lookup_var, self.obj_id, self.free = obj_id_lookup_var, obj_id, free
self.photos_optional, self.photos_required = photos_optional, photos_required self.photos_optional, self.photos_required = photos_optional, photos_required
self.ratings_optional, self.ratings_required = ratings_optional, ratings_required self.ratings_optional, self.ratings_required = ratings_optional, ratings_required
@ -32,7 +34,7 @@ class CommentFormNode(template.Node):
context.push() context.push()
if self.obj_id_lookup_var is not None: if self.obj_id_lookup_var is not None:
try: try:
self.obj_id = template.resolve_variable(self.obj_id_lookup_var, context) self.obj_id = self.obj_id_lookup_var.resolve(context)
except template.VariableDoesNotExist: except template.VariableDoesNotExist:
return '' return ''
# Validate that this object ID is valid for this content-type. # Validate that this object ID is valid for this content-type.
@ -75,6 +77,8 @@ class CommentFormNode(template.Node):
class CommentCountNode(template.Node): class CommentCountNode(template.Node):
def __init__(self, package, module, context_var_name, obj_id, var_name, free): def __init__(self, package, module, context_var_name, obj_id, var_name, free):
self.package, self.module = package, module self.package, self.module = package, module
if context_var_name is not None:
context_var_name = template.Variable(context_var_name)
self.context_var_name, self.obj_id = context_var_name, obj_id self.context_var_name, self.obj_id = context_var_name, obj_id
self.var_name, self.free = var_name, free self.var_name, self.free = var_name, free
@ -82,7 +86,7 @@ class CommentCountNode(template.Node):
from django.conf import settings from django.conf import settings
manager = self.free and FreeComment.objects or Comment.objects manager = self.free and FreeComment.objects or Comment.objects
if self.context_var_name is not None: if self.context_var_name is not None:
self.obj_id = template.resolve_variable(self.context_var_name, context) self.obj_id = self.context_var_name.resolve(context)
comment_count = manager.filter(object_id__exact=self.obj_id, comment_count = manager.filter(object_id__exact=self.obj_id,
content_type__app_label__exact=self.package, content_type__app_label__exact=self.package,
content_type__model__exact=self.module, site__id__exact=settings.SITE_ID).count() content_type__model__exact=self.module, site__id__exact=settings.SITE_ID).count()
@ -92,6 +96,8 @@ class CommentCountNode(template.Node):
class CommentListNode(template.Node): class CommentListNode(template.Node):
def __init__(self, package, module, context_var_name, obj_id, var_name, free, ordering, extra_kwargs=None): def __init__(self, package, module, context_var_name, obj_id, var_name, free, ordering, extra_kwargs=None):
self.package, self.module = package, module self.package, self.module = package, module
if context_var_name is not None:
context_var_name = template.Variable(context_var_name)
self.context_var_name, self.obj_id = context_var_name, obj_id self.context_var_name, self.obj_id = context_var_name, obj_id
self.var_name, self.free = var_name, free self.var_name, self.free = var_name, free
self.ordering = ordering self.ordering = ordering
@ -102,7 +108,7 @@ class CommentListNode(template.Node):
get_list_function = self.free and FreeComment.objects.filter or Comment.objects.get_list_with_karma get_list_function = self.free and FreeComment.objects.filter or Comment.objects.get_list_with_karma
if self.context_var_name is not None: if self.context_var_name is not None:
try: try:
self.obj_id = template.resolve_variable(self.context_var_name, context) self.obj_id = self.context_var_name.resolve(context)
except template.VariableDoesNotExist: except template.VariableDoesNotExist:
return '' return ''
kwargs = { kwargs = {

View File

@ -16,7 +16,6 @@ class SessionBase(object):
""" """
Base class for all Session classes. Base class for all Session classes.
""" """
TEST_COOKIE_NAME = 'testcookie' TEST_COOKIE_NAME = 'testcookie'
TEST_COOKIE_VALUE = 'worked' TEST_COOKIE_VALUE = 'worked'
@ -59,7 +58,7 @@ class SessionBase(object):
def delete_test_cookie(self): def delete_test_cookie(self):
del self[self.TEST_COOKIE_NAME] del self[self.TEST_COOKIE_NAME]
def encode(self, session_dict): def encode(self, session_dict):
"Returns the given session dictionary pickled and encoded as a string." "Returns the given session dictionary pickled and encoded as a string."
pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL) pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
@ -77,28 +76,33 @@ class SessionBase(object):
# just return an empty dictionary (an empty session). # just return an empty dictionary (an empty session).
except: except:
return {} return {}
def _get_new_session_key(self): def _get_new_session_key(self):
"Returns session key that isn't being used." "Returns session key that isn't being used."
# The random module is seeded when this Apache child is created. # The random module is seeded when this Apache child is created.
# Use settings.SECRET_KEY as added salt. # Use settings.SECRET_KEY as added salt.
try:
pid = os.getpid()
except AttributeError:
# No getpid() in Jython, for example
pid = 1
while 1: while 1:
session_key = md5.new("%s%s%s%s" % (random.randint(0, sys.maxint - 1), session_key = md5.new("%s%s%s%s" % (random.randint(0, sys.maxint - 1),
os.getpid(), time.time(), settings.SECRET_KEY)).hexdigest() pid, time.time(), settings.SECRET_KEY)).hexdigest()
if not self.exists(session_key): if not self.exists(session_key):
break break
return session_key return session_key
def _get_session_key(self): def _get_session_key(self):
if self._session_key: if self._session_key:
return self._session_key return self._session_key
else: else:
self._session_key = self._get_new_session_key() self._session_key = self._get_new_session_key()
return self._session_key return self._session_key
def _set_session_key(self, session_key): def _set_session_key(self, session_key):
self._session_key = session_key self._session_key = session_key
session_key = property(_get_session_key, _set_session_key) session_key = property(_get_session_key, _set_session_key)
def _get_session(self): def _get_session(self):
@ -114,9 +118,9 @@ class SessionBase(object):
return self._session_cache return self._session_cache
_session = property(_get_session) _session = property(_get_session)
# Methods that child classes must implement. # Methods that child classes must implement.
def exists(self, session_key): def exists(self, session_key):
""" """
Returns True if the given session_key already exists. Returns True if the given session_key already exists.
@ -140,4 +144,3 @@ class SessionBase(object):
Loads the session data and returns a dictionary. Loads the session data and returns a dictionary.
""" """
raise NotImplementedError raise NotImplementedError

View File

@ -1,5 +1,12 @@
import base64, md5, random, sys, datetime import os
import sys
import time
import datetime
import base64
import md5
import random
import cPickle as pickle import cPickle as pickle
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.conf import settings from django.conf import settings

View File

@ -1,16 +1,16 @@
from threading import Lock
from pprint import pformat
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
from django.core.handlers.base import BaseHandler from django.core.handlers.base import BaseHandler
from django.core import signals from django.core import signals
from django.dispatch import dispatcher from django.dispatch import dispatcher
from django.utils import datastructures from django.utils import datastructures
from django.utils.encoding import force_unicode from django.utils.encoding import force_unicode
from django import http from django import http
from pprint import pformat
from shutil import copyfileobj
from threading import Lock
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
STATUS_CODE_TEXT = { STATUS_CODE_TEXT = {
@ -105,7 +105,8 @@ class WSGIRequest(http.HttpRequest):
return '%s%s' % (self.path, self.environ.get('QUERY_STRING', '') and ('?' + self.environ.get('QUERY_STRING', '')) or '') return '%s%s' % (self.path, self.environ.get('QUERY_STRING', '') and ('?' + self.environ.get('QUERY_STRING', '')) or '')
def is_secure(self): def is_secure(self):
return 'HTTPS' in self.environ and self.environ['HTTPS'] == 'on' return 'wsgi.url_scheme' in self.environ \
and self.environ['wsgi.url_scheme'] == 'https'
def _load_post_and_files(self): def _load_post_and_files(self):
# Populates self._post and self._files # Populates self._post and self._files

View File

@ -1,18 +1,104 @@
import django import django
from django.core.management.base import BaseCommand, CommandError, handle_default_options
from optparse import OptionParser from optparse import OptionParser
import os import os
import sys import sys
from imp import find_module
# For backwards compatibility: get_version() used to be in this module. # For backwards compatibility: get_version() used to be in this module.
get_version = django.get_version get_version = django.get_version
def load_command_class(name): # A cache of loaded commands, so that call_command
# doesn't have to reload every time it is called
_commands = None
def find_commands(management_dir):
""" """
Given a command name, returns the Command class instance. Raises Given a path to a management directory, return a list of all the command names
ImportError if it doesn't exist. that are available. Returns an empty list if no commands are defined.
""" """
# Let the ImportError propogate. command_dir = os.path.join(management_dir,'commands')
return getattr(__import__('django.core.management.commands.%s' % name, {}, {}, ['Command']), 'Command')() try:
return [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')]
except OSError:
return []
def find_management_module(app_name):
"""
Determine the path to the management module for the application named,
without acutally importing the application or the management module.
Raises ImportError if the management module cannot be found for any reason.
"""
parts = app_name.split('.')
parts.append('management')
parts.reverse()
path = None
while parts:
part = parts.pop()
f,path,descr = find_module(part, path and [path] or None)
return path
def load_command_class(app_name, name):
"""
Given a command name and an application name, returns the Command
class instance. All errors raised by the importation process
(ImportError, AttributeError) are allowed to propagate.
"""
return getattr(__import__('%s.management.commands.%s' % (app_name, name),
{}, {}, ['Command']), 'Command')()
def get_commands(load_user_commands=True, project_directory=None):
"""
Returns a dictionary of commands against the application in which
those commands can be found. This works by looking for a
management.commands package in django.core, and in each installed
application -- if a commands package exists, all commands in that
package are registered.
Core commands are always included; user-defined commands will also
be included if ``load_user_commands`` is True. If a project directory
is provided, the startproject command will be disabled, and the
startapp command will be modified to use that directory.
The dictionary is in the format {command_name: app_name}. Key-value
pairs from this dictionary can then be used in calls to
load_command_class(app_name, command_name)
If a specific version of a command must be loaded (e.g., with the
startapp command), the instantiated module can be placed in the
dictionary in place of the application name.
The dictionary is cached on the first call, and reused on subsequent
calls.
"""
global _commands
if _commands is None:
_commands = dict([(name, 'django.core')
for name in find_commands(__path__[0])])
if load_user_commands:
# Get commands from all installed apps
from django.conf import settings
for app_name in settings.INSTALLED_APPS:
try:
path = find_management_module(app_name)
_commands.update(dict([(name, app_name)
for name in find_commands(path)]))
except ImportError:
pass # No management module - ignore this app
if project_directory:
# Remove the "startproject" command from self.commands, because
# that's a django-admin.py command, not a manage.py command.
del _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
_commands['startapp'] = ProjectCommand(project_directory)
return _commands
def call_command(name, *args, **options): def call_command(name, *args, **options):
""" """
@ -25,8 +111,26 @@ def call_command(name, *args, **options):
call_command('shell', plain=True) call_command('shell', plain=True)
call_command('sqlall', 'myapp') call_command('sqlall', 'myapp')
""" """
klass = load_command_class(name) try:
app_name = get_commands()[name]
if isinstance(app_name, BaseCommand):
# If the command is already loaded, use it directly.
klass = app_name
else:
klass = load_command_class(app_name, name)
except KeyError:
raise CommandError, "Unknown command: %r" % name
return klass.execute(*args, **options) return klass.execute(*args, **options)
class LaxOptionParser(OptionParser):
"""
An option parser that doesn't raise any errors on unknown options.
This is needed because the --settings and --pythonpath options affect
the commands (and thus the options) that are available to the user.
"""
def error(self, msg):
pass
class ManagementUtility(object): class ManagementUtility(object):
""" """
@ -38,21 +142,9 @@ class ManagementUtility(object):
def __init__(self, argv=None): def __init__(self, argv=None):
self.argv = argv or sys.argv[:] self.argv = argv or sys.argv[:]
self.prog_name = os.path.basename(self.argv[0]) self.prog_name = os.path.basename(self.argv[0])
self.commands = self.default_commands() self.project_directory = None
self.user_commands = False
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 main_help_text(self): def main_help_text(self):
""" """
Returns the script's main help text, as a string. Returns the script's main help text, as a string.
@ -61,7 +153,7 @@ class ManagementUtility(object):
usage.append('Django command line tool, version %s' % django.get_version()) usage.append('Django command line tool, version %s' % django.get_version())
usage.append("Type '%s help <subcommand>' for help on a specific subcommand." % self.prog_name) usage.append("Type '%s help <subcommand>' for help on a specific subcommand." % self.prog_name)
usage.append('Available subcommands:') usage.append('Available subcommands:')
commands = self.commands.keys() commands = get_commands(self.user_commands, self.project_directory).keys()
commands.sort() commands.sort()
for cmd in commands: for cmd in commands:
usage.append(' %s' % cmd) usage.append(' %s' % cmd)
@ -74,16 +166,33 @@ class ManagementUtility(object):
django-admin.py or manage.py) if it can't be found. django-admin.py or manage.py) if it can't be found.
""" """
try: try:
return self.commands[subcommand] app_name = get_commands(self.user_commands, self.project_directory)[subcommand]
if isinstance(app_name, BaseCommand):
# If the command is already loaded, use it directly.
klass = app_name
else:
klass = load_command_class(app_name, subcommand)
except KeyError: except KeyError:
sys.stderr.write("Unknown command: %r\nType '%s help' for usage.\n" % (subcommand, self.prog_name)) sys.stderr.write("Unknown command: %r\nType '%s help' for usage.\n" % (subcommand, self.prog_name))
sys.exit(1) sys.exit(1)
return klass
def execute(self): def execute(self):
""" """
Given the command-line arguments, this figures out which subcommand is Given the command-line arguments, this figures out which subcommand is
being run, creates a parser appropriate to that command, and runs it. being run, creates a parser appropriate to that command, and runs it.
""" """
# Preprocess options to extract --settings and --pythonpath. These options
# could affect the commands that are available, so they must be processed
# early
parser = LaxOptionParser(version=get_version(),
option_list=BaseCommand.option_list)
try:
options, args = parser.parse_args(self.argv)
handle_default_options(options)
except:
pass # Ignore any option errors at this point.
try: try:
subcommand = self.argv[1] subcommand = self.argv[1]
except IndexError: except IndexError:
@ -91,8 +200,8 @@ class ManagementUtility(object):
sys.exit(1) sys.exit(1)
if subcommand == 'help': if subcommand == 'help':
if len(self.argv) > 2: if len(args) > 2:
self.fetch_command(self.argv[2]).print_help(self.prog_name, self.argv[2]) self.fetch_command(args[2]).print_help(self.prog_name, args[2])
else: else:
sys.stderr.write(self.main_help_text() + '\n') sys.stderr.write(self.main_help_text() + '\n')
sys.exit(1) sys.exit(1)
@ -116,16 +225,9 @@ class ProjectManagementUtility(ManagementUtility):
""" """
def __init__(self, argv, project_directory): def __init__(self, argv, project_directory):
super(ProjectManagementUtility, self).__init__(argv) super(ProjectManagementUtility, self).__init__(argv)
self.project_directory = project_directory
# Remove the "startproject" command from self.commands, because self.user_commands = True
# 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): def setup_environ(settings_mod):
""" """
Configure the runtime environment. This can also be used by external Configure the runtime environment. This can also be used by external
@ -137,7 +239,7 @@ def setup_environ(settings_mod):
project_directory, settings_filename = os.path.split(settings_mod.__file__) project_directory, settings_filename = os.path.split(settings_mod.__file__)
project_name = os.path.basename(project_directory) project_name = os.path.basename(project_directory)
settings_name = os.path.splitext(settings_filename)[0] settings_name = os.path.splitext(settings_filename)[0]
sys.path.append(os.path.join(project_directory, '..')) sys.path.append(os.path.join(project_directory, os.pardir))
project_module = __import__(project_name, {}, {}, ['']) project_module = __import__(project_name, {}, {}, [''])
sys.path.pop() sys.path.pop()

View File

@ -9,6 +9,17 @@ import os
class CommandError(Exception): class CommandError(Exception):
pass pass
def handle_default_options(options):
"""
Include any default options that all commands should accept
here so that ManagementUtility can handle them before searching
for user commands.
"""
if options.settings:
os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
if options.pythonpath:
sys.path.insert(0, options.pythonpath)
class BaseCommand(object): class BaseCommand(object):
# Metadata about this command. # Metadata about this command.
option_list = ( option_list = (
@ -55,10 +66,7 @@ class BaseCommand(object):
def run_from_argv(self, argv): def run_from_argv(self, argv):
parser = self.create_parser(argv[0], argv[1]) parser = self.create_parser(argv[0], argv[1])
options, args = parser.parse_args(argv[2:]) options, args = parser.parse_args(argv[2:])
if options.settings: handle_default_options(options)
os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
if options.pythonpath:
sys.path.insert(0, options.pythonpath)
self.execute(*args, **options.__dict__) self.execute(*args, **options.__dict__)
def execute(self, *args, **options): def execute(self, *args, **options):

View File

@ -16,7 +16,7 @@ class Command(LabelCommand):
directory = os.getcwd() directory = os.getcwd()
# Determine the project_name a bit naively -- by looking at the name of # Determine the project_name a bit naively -- by looking at the name of
# the parent directory. # the parent directory.
project_dir = os.path.normpath(os.path.join(directory, '..')) project_dir = os.path.normpath(os.path.join(directory, os.pardir))
parent_dir = os.path.basename(project_dir) parent_dir = os.path.basename(project_dir)
project_name = os.path.basename(directory) project_name = os.path.basename(directory)
if app_name == project_name: if app_name == project_name:

View File

@ -245,7 +245,7 @@ class Field(object):
if self.default is not NOT_PROVIDED: if self.default is not NOT_PROVIDED:
if callable(self.default): if callable(self.default):
return self.default() return self.default()
return self.default return force_unicode(self.default, strings_only=True)
if not self.empty_strings_allowed or (self.null and settings.DATABASE_ENGINE != 'oracle'): if not self.empty_strings_allowed or (self.null and settings.DATABASE_ENGINE != 'oracle'):
return None return None
return "" return ""

View File

@ -47,8 +47,9 @@ class HttpRequest(object):
def get_host(self): def get_host(self):
"Returns the HTTP host using the environment or request headers." "Returns the HTTP host using the environment or request headers."
# We try three options, in order of decreasing preference. # We try three options, in order of decreasing preference.
host = self.META.get('HTTP_X_FORWARDED_HOST', '') if 'HTTP_X_FORWARDED_HOST' in self.META:
if 'HTTP_HOST' in self.META: host = self.META['HTTP_X_FORWARDED_HOST']
elif 'HTTP_HOST' in self.META:
host = self.META['HTTP_HOST'] host = self.META['HTTP_HOST']
else: else:
# Reconstruct the host using the algorithm from PEP 333. # Reconstruct the host using the algorithm from PEP 333.

View File

@ -54,8 +54,7 @@ class SetRemoteAddrFromForwardedFor(object):
except KeyError: except KeyError:
return None return None
else: else:
# HTTP_X_FORWARDED_FOR can be a comma-separated list of IPs. # HTTP_X_FORWARDED_FOR can be a comma-separated list of IPs. The
# Take just the last one. # client's IP will be the first one.
# See http://bob.pythonmac.org/archives/2005/09/23/apache-x-forwarded-for-caveat/ real_ip = real_ip.split(",")[0].strip()
real_ip = real_ip.split(",")[-1].strip()
request.META['REMOTE_ADDR'] = real_ip request.META['REMOTE_ADDR'] = real_ip

View File

@ -7,7 +7,9 @@ try:
except NameError: except NameError:
from sets import Set as set # Python 2.3 fallback from sets import Set as set # Python 2.3 fallback
import copy
from itertools import chain from itertools import chain
from django.utils.datastructures import MultiValueDict from django.utils.datastructures import MultiValueDict
from django.utils.html import escape from django.utils.html import escape
from django.utils.translation import ugettext from django.utils.translation import ugettext
@ -32,6 +34,12 @@ class Widget(object):
else: else:
self.attrs = {} self.attrs = {}
def __deepcopy__(self, memo):
obj = copy.copy(self)
obj.attrs = self.attrs.copy()
memo[id(self)] = obj
return obj
def render(self, name, value, attrs=None): def render(self, name, value, attrs=None):
""" """
Returns this Widget rendered as HTML, as a Unicode string. Returns this Widget rendered as HTML, as a Unicode string.
@ -88,7 +96,7 @@ class PasswordInput(Input):
input_type = 'password' input_type = 'password'
def __init__(self, attrs=None, render_value=True): def __init__(self, attrs=None, render_value=True):
self.attrs = attrs or {} super(PasswordInput, self).__init__(attrs)
self.render_value = render_value self.render_value = render_value
def render(self, name, value, attrs=None): def render(self, name, value, attrs=None):
@ -105,8 +113,8 @@ class MultipleHiddenInput(HiddenInput):
of values. of values.
""" """
def __init__(self, attrs=None, choices=()): def __init__(self, attrs=None, choices=()):
super(MultipleHiddenInput, self).__init__(attrs)
# choices can be any iterable # choices can be any iterable
self.attrs = attrs or {}
self.choices = choices self.choices = choices
def render(self, name, value, attrs=None, choices=()): def render(self, name, value, attrs=None, choices=()):
@ -145,9 +153,9 @@ class Textarea(Widget):
class CheckboxInput(Widget): class CheckboxInput(Widget):
def __init__(self, attrs=None, check_test=bool): def __init__(self, attrs=None, check_test=bool):
super(CheckboxInput, self).__init__(attrs)
# check_test is a callable that takes a value and returns True # check_test is a callable that takes a value and returns True
# if the checkbox should be checked for that value. # if the checkbox should be checked for that value.
self.attrs = attrs or {}
self.check_test = check_test self.check_test = check_test
def render(self, name, value, attrs=None): def render(self, name, value, attrs=None):
@ -164,7 +172,7 @@ class CheckboxInput(Widget):
class Select(Widget): class Select(Widget):
def __init__(self, attrs=None, choices=()): def __init__(self, attrs=None, choices=()):
self.attrs = attrs or {} super(Select, self).__init__(attrs)
# choices can be any iterable, but we may need to render this widget # choices can be any iterable, but we may need to render this widget
# multiple times. Thus, collapse it into a list so it can be consumed # multiple times. Thus, collapse it into a list so it can be consumed
# more than once. # more than once.
@ -203,8 +211,8 @@ class NullBooleanSelect(Select):
class SelectMultiple(Widget): class SelectMultiple(Widget):
def __init__(self, attrs=None, choices=()): def __init__(self, attrs=None, choices=()):
super(SelectMultiple, self).__init__(attrs)
# choices can be any iterable # choices can be any iterable
self.attrs = attrs or {}
self.choices = choices self.choices = choices
def render(self, name, value, attrs=None, choices=()): def render(self, name, value, attrs=None, choices=()):

View File

@ -500,7 +500,7 @@ class SelectField(FormField):
selected_html = u'' selected_html = u''
if smart_unicode(value) == str_data: if smart_unicode(value) == str_data:
selected_html = u' selected="selected"' selected_html = u' selected="selected"'
output.append(u' <option value="%s"%s>%s</option>' % (escape(value), selected_html, escape(display_name))) output.append(u' <option value="%s"%s>%s</option>' % (escape(value), selected_html, force_unicode(escape(display_name))))
output.append(u' </select>') output.append(u' </select>')
return u'\n'.join(output) return u'\n'.join(output)
@ -612,7 +612,7 @@ class SelectMultipleField(SelectField):
selected_html = u'' selected_html = u''
if smart_unicode(value) in str_data_list: if smart_unicode(value) in str_data_list:
selected_html = u' selected="selected"' selected_html = u' selected="selected"'
output.append(u' <option value="%s"%s>%s</option>' % (escape(value), selected_html, escape(choice))) output.append(u' <option value="%s"%s>%s</option>' % (escape(value), selected_html, force_unicode(escape(choice))))
output.append(u' </select>') output.append(u' </select>')
return u'\n'.join(output) return u'\n'.join(output)

View File

@ -88,8 +88,6 @@ UNKNOWN_SOURCE="&lt;unknown source&gt;"
tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END), tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END),
re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END), re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END),
re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END))) re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END)))
# matches if the string is valid number
number_re = re.compile(r'[-+]?(\d+|\d*\.\d+)$')
# global dictionary of libraries that have been loaded using get_library # global dictionary of libraries that have been loaded using get_library
libraries = {} libraries = {}
@ -564,18 +562,19 @@ class FilterExpression(object):
elif constant_arg is not None: elif constant_arg is not None:
args.append((False, constant_arg.replace(r'\"', '"'))) args.append((False, constant_arg.replace(r'\"', '"')))
elif var_arg: elif var_arg:
args.append((True, var_arg)) args.append((True, Variable(var_arg)))
filter_func = parser.find_filter(filter_name) filter_func = parser.find_filter(filter_name)
self.args_check(filter_name,filter_func, args) self.args_check(filter_name,filter_func, args)
filters.append( (filter_func,args)) filters.append( (filter_func,args))
upto = match.end() upto = match.end()
if upto != len(token): if upto != len(token):
raise TemplateSyntaxError, "Could not parse the remainder: '%s' from '%s'" % (token[upto:], token) raise TemplateSyntaxError, "Could not parse the remainder: '%s' from '%s'" % (token[upto:], token)
self.var, self.filters = var, filters self.filters = filters
self.var = Variable(var)
def resolve(self, context, ignore_failures=False): def resolve(self, context, ignore_failures=False):
try: try:
obj = resolve_variable(self.var, context) obj = self.var.resolve(context)
except VariableDoesNotExist: except VariableDoesNotExist:
if ignore_failures: if ignore_failures:
obj = None obj = None
@ -595,7 +594,7 @@ class FilterExpression(object):
if not lookup: if not lookup:
arg_vals.append(arg) arg_vals.append(arg)
else: else:
arg_vals.append(resolve_variable(arg, context)) arg_vals.append(arg.resolve(context))
obj = func(obj, *arg_vals) obj = func(obj, *arg_vals)
return obj return obj
@ -637,37 +636,98 @@ class FilterExpression(object):
def resolve_variable(path, context): def resolve_variable(path, context):
""" """
Returns the resolved variable, which may contain attribute syntax, within Returns the resolved variable, which may contain attribute syntax, within
the given context. The variable may be a hard-coded string (if it begins the given context.
and ends with single or double quote marks).
Deprecated; use the Variable class instead.
"""
return Variable(path).resolve(context)
>>> c = {'article': {'section':'News'}} class Variable(object):
>>> resolve_variable('article.section', c) """
u'News' A template variable, resolvable against a given context. The variable may be
>>> resolve_variable('article', c) a hard-coded string (if it begins and ends with single or double quote
{'section': 'News'} marks)::
>>> class AClass: pass
>>> c = AClass() >>> c = {'article': {'section':'News'}}
>>> c.article = AClass() >>> Variable('article.section').resolve(c)
>>> c.article.section = 'News' u'News'
>>> resolve_variable('article.section', c) >>> Variable('article').resolve(c)
u'News' {'section': 'News'}
>>> class AClass: pass
>>> c = AClass()
>>> c.article = AClass()
>>> c.article.section = 'News'
>>> Variable('article.section').resolve(c)
u'News'
(The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.') (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.')
""" """
if number_re.match(path):
number_type = '.' in path and float or int def __init__(self, var):
current = number_type(path) self.var = var
elif path[0] in ('"', "'") and path[0] == path[-1]: self.literal = None
current = path[1:-1] self.lookups = None
else:
try:
# First try to treat this variable as a number.
#
# Note that this could cause an OverflowError here that we're not
# catching. Since this should only happen at compile time, that's
# probably OK.
self.literal = float(var)
# So it's a float... is it an int? If the original value contained a
# dot or an "e" then it was a float, not an int.
if '.' not in var and 'e' not in var.lower():
self.literal = int(self.literal)
# "2." is invalid
if var.endswith('.'):
raise ValueError
except ValueError:
# A ValueError means that the variable isn't a number.
# If it's wrapped with quotes (single or double), then
# we're also dealing with a literal.
if var[0] in "\"'" and var[0] == var[-1]:
self.literal = var[1:-1]
else:
# Otherwise we'll set self.lookups so that resolve() knows we're
# dealing with a bonafide variable
self.lookups = tuple(var.split(VARIABLE_ATTRIBUTE_SEPARATOR))
def resolve(self, context):
"""Resolve this variable against a given context."""
if self.lookups is not None:
# We're dealing with a variable that needs to be resolved
return self._resolve_lookup(context)
else:
# We're dealing with a literal, so it's already been "resolved"
return self.literal
def __repr__(self):
return "<%s: %r>" % (self.__class__.__name__, self.var)
def __str__(self):
return self.var
def _resolve_lookup(self, context):
"""
Performs resolution of a real variable (i.e. not a literal) against the
given context.
As indicated by the method's name, this method is an implementation
detail and shouldn't be called by external code. Use Variable.resolve()
instead.
"""
current = context current = context
bits = path.split(VARIABLE_ATTRIBUTE_SEPARATOR) for bit in self.lookups:
while bits:
try: # dictionary lookup try: # dictionary lookup
current = current[bits[0]] current = current[bit]
except (TypeError, AttributeError, KeyError): except (TypeError, AttributeError, KeyError):
try: # attribute lookup try: # attribute lookup
current = getattr(current, bits[0]) current = getattr(current, bit)
if callable(current): if callable(current):
if getattr(current, 'alters_data', False): if getattr(current, 'alters_data', False):
current = settings.TEMPLATE_STRING_IF_INVALID current = settings.TEMPLATE_STRING_IF_INVALID
@ -685,27 +745,27 @@ def resolve_variable(path, context):
raise raise
except (TypeError, AttributeError): except (TypeError, AttributeError):
try: # list-index lookup try: # list-index lookup
current = current[int(bits[0])] current = current[int(bit)]
except (IndexError, # list index out of range except (IndexError, # list index out of range
ValueError, # invalid literal for int() ValueError, # invalid literal for int()
KeyError, # current is a dict without `int(bits[0])` key KeyError, # current is a dict without `int(bit)` key
TypeError, # unsubscriptable object TypeError, # unsubscriptable object
): ):
raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bits[0], current)) # missing attribute raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute
except Exception, e: except Exception, e:
if getattr(e, 'silent_variable_failure', False): if getattr(e, 'silent_variable_failure', False):
current = settings.TEMPLATE_STRING_IF_INVALID current = settings.TEMPLATE_STRING_IF_INVALID
else: else:
raise raise
del bits[0]
if isinstance(current, (basestring, Promise)): if isinstance(current, (basestring, Promise)):
try: try:
current = force_unicode(current) current = force_unicode(current)
except UnicodeDecodeError: except UnicodeDecodeError:
# Failing to convert to unicode can happen sometimes (e.g. debug # Failing to convert to unicode can happen sometimes (e.g. debug
# tracebacks). So we allow it in this particular instance. # tracebacks). So we allow it in this particular instance.
pass pass
return current return current
class Node(object): class Node(object):
def render(self, context): def render(self, context):
@ -861,10 +921,10 @@ class Library(object):
class SimpleNode(Node): class SimpleNode(Node):
def __init__(self, vars_to_resolve): def __init__(self, vars_to_resolve):
self.vars_to_resolve = vars_to_resolve self.vars_to_resolve = map(Variable, vars_to_resolve)
def render(self, context): def render(self, context):
resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve] resolved_vars = [var.resolve(context) for var in self.vars_to_resolve]
return func(*resolved_vars) return func(*resolved_vars)
compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, SimpleNode) compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, SimpleNode)
@ -883,10 +943,10 @@ class Library(object):
class InclusionNode(Node): class InclusionNode(Node):
def __init__(self, vars_to_resolve): def __init__(self, vars_to_resolve):
self.vars_to_resolve = vars_to_resolve self.vars_to_resolve = map(Variable, vars_to_resolve)
def render(self, context): def render(self, context):
resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve] resolved_vars = [var.resolve(context) for var in self.vars_to_resolve]
if takes_context: if takes_context:
args = [context] + resolved_vars args = [context] + resolved_vars
else: else:

View File

@ -1,6 +1,6 @@
"Default variable filters" "Default variable filters"
from django.template import resolve_variable, Library from django.template import Variable, Library
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext, ungettext from django.utils.translation import ugettext, ungettext
from django.utils.encoding import force_unicode, smart_str, iri_to_uri from django.utils.encoding import force_unicode, smart_str, iri_to_uri
@ -297,7 +297,8 @@ def dictsort(value, arg):
Takes a list of dicts, returns that list sorted by the property given in Takes a list of dicts, returns that list sorted by the property given in
the argument. the argument.
""" """
decorated = [(resolve_variable(u'var.' + arg, {u'var' : item}), item) for item in value] var_resolve = Variable(arg).resolve
decorated = [(var_resolve(item), item) for item in value]
decorated.sort() decorated.sort()
return [item[1] for item in decorated] return [item[1] for item in decorated]
@ -306,7 +307,8 @@ def dictsortreversed(value, arg):
Takes a list of dicts, returns that list sorted in reverse order by the Takes a list of dicts, returns that list sorted in reverse order by the
property given in the argument. property given in the argument.
""" """
decorated = [(resolve_variable(u'var.' + arg, {u'var' : item}), item) for item in value] var_resolve = Variable(arg).resolve
decorated = [(var_resolve(item), item) for item in value]
decorated.sort() decorated.sort()
decorated.reverse() decorated.reverse()
return [item[1] for item in decorated] return [item[1] for item in decorated]

View File

@ -1,6 +1,6 @@
"Default tags used by the template system, available to all templates." "Default tags used by the template system, available to all templates."
from django.template import Node, NodeList, Template, Context, resolve_variable from django.template import Node, NodeList, Template, Context, Variable
from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END
from django.template import get_library, Library, InvalidTemplateLibrary from django.template import get_library, Library, InvalidTemplateLibrary
from django.conf import settings from django.conf import settings
@ -30,7 +30,7 @@ class CycleNode(Node):
def render(self, context): def render(self, context):
self.counter += 1 self.counter += 1
value = self.cyclevars[self.counter % self.cyclevars_len] value = self.cyclevars[self.counter % self.cyclevars_len]
value = resolve_variable(value, context) value = Variable(value).resolve(context)
if self.variable_name: if self.variable_name:
context[self.variable_name] = value context[self.variable_name] = value
return value return value
@ -57,12 +57,12 @@ class FilterNode(Node):
class FirstOfNode(Node): class FirstOfNode(Node):
def __init__(self, vars): def __init__(self, vars):
self.vars = vars self.vars = map(Variable, vars)
def render(self, context): def render(self, context):
for var in self.vars: for var in self.vars:
try: try:
value = resolve_variable(var, context) value = var.resolve(context)
except VariableDoesNotExist: except VariableDoesNotExist:
continue continue
if value: if value:
@ -147,7 +147,7 @@ class IfChangedNode(Node):
def __init__(self, nodelist, *varlist): def __init__(self, nodelist, *varlist):
self.nodelist = nodelist self.nodelist = nodelist
self._last_seen = None self._last_seen = None
self._varlist = varlist self._varlist = map(Variable, varlist)
def render(self, context): def render(self, context):
if 'forloop' in context and context['forloop']['first']: if 'forloop' in context and context['forloop']['first']:
@ -156,7 +156,7 @@ class IfChangedNode(Node):
if self._varlist: if self._varlist:
# Consider multiple parameters. # Consider multiple parameters.
# This automatically behaves like a OR evaluation of the multiple variables. # This automatically behaves like a OR evaluation of the multiple variables.
compare_to = [resolve_variable(var, context) for var in self._varlist] compare_to = [var.resolve(context) for var in self._varlist]
else: else:
compare_to = self.nodelist.render(context) compare_to = self.nodelist.render(context)
except VariableDoesNotExist: except VariableDoesNotExist:
@ -175,7 +175,7 @@ class IfChangedNode(Node):
class IfEqualNode(Node): class IfEqualNode(Node):
def __init__(self, var1, var2, nodelist_true, nodelist_false, negate): def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
self.var1, self.var2 = var1, var2 self.var1, self.var2 = Variable(var1), Variable(var2)
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
self.negate = negate self.negate = negate
@ -184,11 +184,11 @@ class IfEqualNode(Node):
def render(self, context): def render(self, context):
try: try:
val1 = resolve_variable(self.var1, context) val1 = self.var1.resolve(context)
except VariableDoesNotExist: except VariableDoesNotExist:
val1 = None val1 = None
try: try:
val2 = resolve_variable(self.var2, context) val2 = self.var2.resolve(context)
except VariableDoesNotExist: except VariableDoesNotExist:
val2 = None val2 = None
if (self.negate and val1 != val2) or (not self.negate and val1 == val2): if (self.negate and val1 != val2) or (not self.negate and val1 == val2):

View File

@ -1,4 +1,4 @@
from django.template import TemplateSyntaxError, TemplateDoesNotExist, resolve_variable from django.template import TemplateSyntaxError, TemplateDoesNotExist, Variable
from django.template import Library, Node from django.template import Library, Node
from django.template.loader import get_template, get_template_from_string, find_template_source from django.template.loader import get_template, get_template_from_string, find_template_source
from django.conf import settings from django.conf import settings
@ -99,11 +99,11 @@ class ConstantIncludeNode(Node):
class IncludeNode(Node): class IncludeNode(Node):
def __init__(self, template_name): def __init__(self, template_name):
self.template_name = template_name self.template_name = Variable(template_name)
def render(self, context): def render(self, context):
try: try:
template_name = resolve_variable(self.template_name, context) template_name = self.template_name.resolve(context)
t = get_template(template_name) t = get_template(template_name)
return t.render(context) return t.render(context)
except TemplateSyntaxError, e: except TemplateSyntaxError, e:

View File

@ -1,4 +1,4 @@
from django.template import Node, resolve_variable from django.template import Node, Variable
from django.template import TemplateSyntaxError, TokenParser, Library from django.template import TemplateSyntaxError, TokenParser, Library
from django.template import TOKEN_TEXT, TOKEN_VAR from django.template import TOKEN_TEXT, TOKEN_VAR
from django.utils import translation from django.utils import translation
@ -32,11 +32,11 @@ class GetCurrentLanguageBidiNode(Node):
class TranslateNode(Node): class TranslateNode(Node):
def __init__(self, value, noop): def __init__(self, value, noop):
self.value = value self.value = Variable(value)
self.noop = noop self.noop = noop
def render(self, context): def render(self, context):
value = resolve_variable(self.value, context) value = self.value.resolve(context)
if self.noop: if self.noop:
return value return value
else: else:

View File

@ -23,7 +23,7 @@ import time
from email.Utils import formatdate from email.Utils import formatdate
from django.conf import settings from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
from django.utils.encoding import smart_str from django.utils.encoding import smart_str, iri_to_uri
cc_delim_re = re.compile(r'\s*,\s*') cc_delim_re = re.compile(r'\s*,\s*')
@ -57,6 +57,13 @@ def patch_cache_control(response, **kwargs):
cc = dict([dictitem(el) for el in cc]) cc = dict([dictitem(el) for el in cc])
else: else:
cc = {} cc = {}
# If there's already a max-age header but we're being asked to set a new
# max-age, use the minumum of the two ages. In practice this happens when
# a decorator and a piece of middleware both operate on a given view.
if 'max-age' in cc and 'max_age' in kwargs:
kwargs['max_age'] = min(cc['max-age'], kwargs['max_age'])
for (k,v) in kwargs.items(): for (k,v) in kwargs.items():
cc[k.replace('_', '-')] = v cc[k.replace('_', '-')] = v
cc = ', '.join([dictvalue(el) for el in cc.items()]) cc = ', '.join([dictvalue(el) for el in cc.items()])
@ -118,7 +125,7 @@ def _generate_cache_key(request, headerlist, key_prefix):
value = request.META.get(header, None) value = request.META.get(header, None)
if value is not None: if value is not None:
ctx.update(value) ctx.update(value)
return 'views.decorators.cache.cache_page.%s.%s.%s' % (key_prefix, request.path, ctx.hexdigest()) return 'views.decorators.cache.cache_page.%s.%s.%s' % (key_prefix, iri_to_uri(request.path), ctx.hexdigest())
def get_cache_key(request, key_prefix=None): def get_cache_key(request, key_prefix=None):
""" """
@ -132,7 +139,7 @@ def get_cache_key(request, key_prefix=None):
""" """
if key_prefix is None: if key_prefix is None:
key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
cache_key = 'views.decorators.cache.cache_header.%s.%s' % (key_prefix, request.path) cache_key = 'views.decorators.cache.cache_header.%s.%s' % (key_prefix, iri_to_uri(request.path))
headerlist = cache.get(cache_key, None) headerlist = cache.get(cache_key, None)
if headerlist is not None: if headerlist is not None:
return _generate_cache_key(request, headerlist, key_prefix) return _generate_cache_key(request, headerlist, key_prefix)
@ -156,7 +163,7 @@ def learn_cache_key(request, response, cache_timeout=None, key_prefix=None):
key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
if cache_timeout is None: if cache_timeout is None:
cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
cache_key = 'views.decorators.cache.cache_header.%s.%s' % (key_prefix, request.path) cache_key = 'views.decorators.cache.cache_header.%s.%s' % (key_prefix, iri_to_uri(request.path))
if response.has_header('Vary'): if response.has_header('Vary'):
headerlist = ['HTTP_'+header.upper().replace('-', '_') for header in vary_delim_re.split(response['Vary'])] headerlist = ['HTTP_'+header.upper().replace('-', '_') for header in vary_delim_re.split(response['Vary'])]
cache.set(cache_key, headerlist, cache_timeout) cache.set(cache_key, headerlist, cache_timeout)

View File

@ -149,7 +149,7 @@ class MultiValueDict(dict):
dict.__init__(self, key_to_list_mapping) dict.__init__(self, key_to_list_mapping)
def __repr__(self): def __repr__(self):
return "<MultiValueDict: %s>" % dict.__repr__(self) return "<%s: %s>" % (self.__class__.__name__, dict.__repr__(self))
def __getitem__(self, key): def __getitem__(self, key):
""" """

View File

@ -1,5 +1,6 @@
import types import types
import urllib import urllib
import datetime
from django.utils.functional import Promise from django.utils.functional import Promise
class StrAndUnicode(object): class StrAndUnicode(object):
@ -30,7 +31,7 @@ def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'):
If strings_only is True, don't convert (some) non-string-like objects. If strings_only is True, don't convert (some) non-string-like objects.
""" """
if strings_only and isinstance(s, (types.NoneType, int, long)): if strings_only and isinstance(s, (types.NoneType, int, long, datetime.datetime, datetime.time, float)):
return s return s
if not isinstance(s, basestring,): if not isinstance(s, basestring,):
if hasattr(s, '__unicode__'): if hasattr(s, '__unicode__'):

View File

@ -2,6 +2,7 @@
Internationalization support. Internationalization support.
""" """
from django.utils.functional import lazy from django.utils.functional import lazy
from django.utils.encoding import force_unicode
__all__ = ['gettext', 'gettext_noop', 'gettext_lazy', 'ngettext', __all__ = ['gettext', 'gettext_noop', 'gettext_lazy', 'ngettext',
'ngettext_lazy', 'string_concat', 'activate', 'deactivate', 'ngettext_lazy', 'string_concat', 'activate', 'deactivate',
@ -39,7 +40,7 @@ def delayed_loader(*args, **kwargs):
g['real_%s' % name] = getattr(trans, name) g['real_%s' % name] = getattr(trans, name)
# Make the originally requested function call on the way out the door. # Make the originally requested function call on the way out the door.
return g[caller](*args, **kwargs) return g['real_%s' % caller](*args, **kwargs)
g = globals() g = globals()
for name in __all__: for name in __all__:
@ -63,14 +64,10 @@ def ugettext(message):
def ungettext(singular, plural, number): def ungettext(singular, plural, number):
return real_ungettext(singular, plural, number) return real_ungettext(singular, plural, number)
def string_concat(*strings):
return real_string_concat(*strings)
ngettext_lazy = lazy(ngettext, str) ngettext_lazy = lazy(ngettext, str)
gettext_lazy = lazy(gettext, str) gettext_lazy = lazy(gettext, str)
ungettext_lazy = lazy(ungettext, unicode) ungettext_lazy = lazy(ungettext, unicode)
ugettext_lazy = lazy(ugettext, unicode) ugettext_lazy = lazy(ugettext, unicode)
string_concat = lazy(string_concat, unicode)
def activate(language): def activate(language):
return real_activate(language) return real_activate(language)
@ -108,3 +105,10 @@ def templatize(src):
def deactivate_all(): def deactivate_all():
return real_deactivate_all() return real_deactivate_all()
def string_concat(*strings):
"""
Lazy variant of string concatenation, needed for translations that are
constructed from multiple parts.
"""
return u''.join([force_unicode(s) for s in strings])
string_concat = lazy(string_concat, unicode)

View File

@ -13,7 +13,6 @@ ngettext_lazy = ngettext
def ungettext(singular, plural, number): def ungettext(singular, plural, number):
return force_unicode(ngettext(singular, plural, number)) return force_unicode(ngettext(singular, plural, number))
string_concat = lambda *strings: u''.join([force_unicode(el) for el in strings])
activate = lambda x: None activate = lambda x: None
deactivate = deactivate_all = install = lambda: None deactivate = deactivate_all = install = lambda: None
get_language = lambda: settings.LANGUAGE_CODE get_language = lambda: settings.LANGUAGE_CODE

View File

@ -516,9 +516,3 @@ def templatize(src):
out.write(blankout(t.contents, 'X')) out.write(blankout(t.contents, 'X'))
return out.getvalue() return out.getvalue()
def string_concat(*strings):
""""
Lazy variant of string concatenation, needed for translations that are
constructed from multiple parts.
"""
return u''.join([force_unicode(s) for s in strings])

View File

@ -29,12 +29,12 @@ def serve(request, path, document_root=None, show_indexes=False):
newpath = '' newpath = ''
for part in path.split('/'): for part in path.split('/'):
if not part: if not part:
# strip empty path components # Strip empty path components.
continue continue
drive, part = os.path.splitdrive(part) drive, part = os.path.splitdrive(part)
head, part = os.path.split(part) head, part = os.path.split(part)
if part in (os.curdir, os.pardir): if part in (os.curdir, os.pardir):
# strip '.' amd '..' in path # Strip '.' and '..' in path.
continue continue
newpath = os.path.join(newpath, part).replace('\\', '/') newpath = os.path.join(newpath, part).replace('\\', '/')
if newpath and path != newpath: if newpath and path != newpath:

View File

@ -163,3 +163,118 @@ storage engine, you have a couple of options.
.. _AlterModelOnSyncDB: http://code.djangoproject.com/wiki/AlterModelOnSyncDB .. _AlterModelOnSyncDB: http://code.djangoproject.com/wiki/AlterModelOnSyncDB
Oracle Notes
============
Django supports `Oracle Database Server`_ versions 9i and higher. Oracle
version 10g or later is required to use Django's ``regex`` and ``iregex`` query
operators. You will also need the `cx_Oracle`_ driver, version 4.3.1 or newer.
.. _`Oracle Database Server`: http://www.oracle.com/
.. _`cx_Oracle`: http://cx-oracle.sourceforge.net/
To run ``python manage.py syncdb``, you'll need to create an Oracle database
user with CREATE TABLE, CREATE SEQUENCE, CREATE PROCEDURE, and CREATE TRIGGER
privileges. To run Django's test suite, the user also needs
CREATE and DROP DATABASE and CREATE and DROP TABLESPACE privileges.
Connecting to the Database
--------------------------
Your Django settings.py file should look something like this for Oracle::
DATABASE_ENGINE = 'oracle'
DATABASE_NAME = 'xe'
DATABASE_USER = 'a_user'
DATABASE_PASSWORD = 'a_password'
DATABASE_HOST = ''
DATABASE_PORT = ''
If you don't use a ``tnsnames.ora`` file or a similar naming method that
recognizes the SID ("xe" in this example), then fill in both ``DATABASE_HOST``
and ``DATABASE_PORT`` like so::
DATABASE_ENGINE = 'oracle'
DATABASE_NAME = 'xe'
DATABASE_USER = 'a_user'
DATABASE_PASSWORD = 'a_password'
DATABASE_HOST = 'dbprod01ned.mycompany.com'
DATABASE_PORT = '1540'
You should supply both ``DATABASE_HOST`` and ``DATABASE_PORT``, or leave both
as empty strings.
Tablespace Options
------------------
A common paradigm for optimizing performance in Oracle-based systems is the
use of `tablespaces`_ to organize disk layout. The Oracle backend supports
this use case by adding ``db_tablespace`` options to the ``Meta`` and
``Field`` classes. (When using a backend that lacks support for tablespaces,
these options are ignored.)
.. _`tablespaces`: http://en.wikipedia.org/wiki/Tablespace
A tablespace can be specified for the table(s) generated by a model by
supplying the ``db_tablespace`` option inside the model's ``Meta`` class.
Additionally, the ``db_tablespace`` option can be passed to a ``Field``
constructor to specify an alternate tablespace for the ``Field``'s column
index. If no index would be created for the column, the ``db_tablespace``
option is ignored.
::
class TablespaceExample(models.Model):
name = models.CharField(maxlength=30, db_index=True, db_tablespace="indexes")
data = models.CharField(maxlength=255, db_index=True)
edges = models.ManyToManyField(to="self", db_tablespace="indexes")
class Meta:
db_tablespace = "tables"
In this example, the tables generated by the ``TablespaceExample`` model
(i.e., the model table and the many-to-many table) would be stored in the
``tables`` tablespace. The index for the name field and the indexes on the
many-to-many table would be stored in the ``indexes`` tablespace. The ``data``
field would also generate an index, but no tablespace for it is specified, so
it would be stored in the model tablespace ``tables`` by default.
Django does not create the tablespaces for you. Please refer to `Oracle's
documentation`_ for details on creating and managing tablespaces.
.. _`Oracle's documentation`: http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_7003.htm#SQLRF01403
Naming Issues
-------------
Oracle imposes a name length limit of 30 characters. To accommodate this, the
backend truncates database identifiers to fit, replacing the final four
characters of the truncated name with a repeatable MD5 hash value.
NULL and Empty Strings
----------------------
Django generally prefers to use the empty string ('') rather than NULL, but
Oracle treats both identically. To get around this, the Oracle backend
coerces the ``null=True`` option on fields that permit the empty string as a
value. When fetching from the database, it is assumed that a NULL value in
one of these fields really means the empty string, and the data is silently
converted to reflect this assumption.
TextField Limitations
---------------------
The Oracle backend stores ``TextFields`` as ``NCLOB`` columns. Oracle imposes
some limitations on the usage of such LOB columns in general:
* LOB columns may not be used as primary keys.
* LOB columns may not be used in indexes.
* LOB columns may not be used in a ``SELECT DISTINCT`` list. This means that
attempting to use the ``QuerySet.distinct`` method on a model that
includes ``TextField`` columns will result in an error when run against
Oracle. A workaround to this is to keep ``TextField`` columns out of any
models that you foresee performing ``.distinct`` queries on, and to
include the ``TextField`` in a related model instead.

View File

@ -952,7 +952,7 @@ Example::
If you pass ``in_bulk()`` an empty list, you'll get an empty dictionary. If you pass ``in_bulk()`` an empty list, you'll get an empty dictionary.
``iterator()`` ``iterator()``
~~~~~~~~~~~~ ~~~~~~~~~~~~~~
Evaluates the ``QuerySet`` (by performing the query) and returns an Evaluates the ``QuerySet`` (by performing the query) and returns an
`iterator`_ over the results. A ``QuerySet`` typically reads all of `iterator`_ over the results. A ``QuerySet`` typically reads all of
@ -1371,11 +1371,6 @@ equivalent::
Entry.objects.filter(blog__id=3) # __exact is implied Entry.objects.filter(blog__id=3) # __exact is implied
Entry.objects.filter(blog__pk=3) # __pk implies __id__exact Entry.objects.filter(blog__pk=3) # __pk implies __id__exact
.. note::
Because of this shortcut, you cannot have a field in your model called
``pk`` that is not the primary key of the model. It will always be
replaced by the name of the model's primary key in queries.
Lookups that span relationships Lookups that span relationships
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -735,3 +735,32 @@ distribution. It enables tab-completion of ``django-admin.py`` and
* Press [TAB] to see all available options. * Press [TAB] to see all available options.
* Type ``sql``, then [TAB], to see all available options whose names start * Type ``sql``, then [TAB], to see all available options whose names start
with ``sql``. with ``sql``.
Customized actions
==================
**New in Django development version**
If you want to add an action of your own to ``manage.py``, you can.
Simply add a ``management/commands`` directory to your application.
Each python module in that directory will be discovered and registered as
a command that can be executed as an action when you run ``manage.py``::
/fancy_blog
__init__.py
models.py
/management
__init__.py
/commands
__init__.py
explode.py
views.py
In this example, ``explode`` command will be made available to any project
that includes the ``fancy_blog`` application in ``settings.INSTALLED_APPS``.
The ``explode.py`` module has only one requirement -- it must define a class
called ``Command`` that extends ``django.core.management.base.BaseCommand``.
For more details on how to define your own commands, look at the code for the
existing ``django-admin.py`` commands, in ``/django/core/management/commands``.

View File

@ -100,31 +100,31 @@ mail_admins()
============= =============
``django.core.mail.mail_admins()`` is a shortcut for sending an e-mail to the ``django.core.mail.mail_admins()`` is a shortcut for sending an e-mail to the
site admins, as defined in the `ADMINS setting`_. Here's the definition:: site admins, as defined in the `ADMINS`_ setting. Here's the definition::
mail_admins(subject, message, fail_silently=False) mail_admins(subject, message, fail_silently=False)
``mail_admins()`` prefixes the subject with the value of the ``mail_admins()`` prefixes the subject with the value of the
`EMAIL_SUBJECT_PREFIX setting`_, which is ``"[Django] "`` by default. `EMAIL_SUBJECT_PREFIX`_ setting, which is ``"[Django] "`` by default.
The "From:" header of the e-mail will be the value of the `SERVER_EMAIL setting`_. The "From:" header of the e-mail will be the value of the `SERVER_EMAIL`_ setting.
This method exists for convenience and readability. This method exists for convenience and readability.
.. _ADMINS setting: ../settings/#admins .. _ADMINS: ../settings/#admins
.. _EMAIL_SUBJECT_PREFIX setting: ../settings/#email-subject-prefix .. _EMAIL_SUBJECT_PREFIX: ../settings/#email-subject-prefix
.. _SERVER_EMAIL setting: ../settings/#server-email .. _SERVER_EMAIL: ../settings/#server-email
mail_managers() function mail_managers() function
======================== ========================
``django.core.mail.mail_managers()`` is just like ``mail_admins()``, except it ``django.core.mail.mail_managers()`` is just like ``mail_admins()``, except it
sends an e-mail to the site managers, as defined in the `MANAGERS setting`_. sends an e-mail to the site managers, as defined in the `MANAGERS`_ setting.
Here's the definition:: Here's the definition::
mail_managers(subject, message, fail_silently=False) mail_managers(subject, message, fail_silently=False)
.. _MANAGERS setting: ../settings/#managers .. _MANAGERS: ../settings/#managers
Examples Examples
======== ========
@ -225,7 +225,7 @@ optional and can be set at any time prior to calling the ``send()`` method.
* ``from_email``: The sender's address. Both ``fred@example.com`` and * ``from_email``: The sender's address. Both ``fred@example.com`` and
``Fred <fred@example.com>`` forms are legal. If omitted, the ``Fred <fred@example.com>`` forms are legal. If omitted, the
``DEFAULT_FROM_EMAIL`` setting is used. `DEFAULT_FROM_EMAIL`_ setting is used.
* ``to``: A list or tuple of recipient addresses. * ``to``: A list or tuple of recipient addresses.
@ -297,6 +297,8 @@ The class has the following methods:
message.attach_file('/images/weather_map.png') message.attach_file('/images/weather_map.png')
.. _DEFAULT_FROM_EMAIL: ../settings/#default-from-email
Sending alternative content types Sending alternative content types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -315,7 +317,7 @@ To send a text and HTML combination, you could write::
subject, from_email, to = 'hello', 'from@example.com', 'to@example.com' subject, from_email, to = 'hello', 'from@example.com', 'to@example.com'
text_content = 'This is an important message.' text_content = 'This is an important message.'
html_content = '<p>This is an <strong>important</strong> message.</p>' html_content = '<p>This is an <strong>important</strong> message.</p>'
msg = EmailMultiAlternatives(subject, text_content, from_email, to) msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.attach_alternative(html_content, "text/html") msg.attach_alternative(html_content, "text/html")
msg.send() msg.send()

View File

@ -800,9 +800,14 @@ specify the page number in the URL in one of two ways:
variable. You can iterate over the list provided by ``page_range`` variable. You can iterate over the list provided by ``page_range``
to create a link to every page of results. to create a link to every page of results.
These values and lists are is 1-based, not 0-based, so the first page would be These values and lists are 1-based, not 0-based, so the first page would be
represented as page ``1``. represented as page ``1``.
An example of the use of pagination can be found in the `object pagination`_
example model.
.. _`object pagination`: ../models/pagination/
**New in Django development version:** **New in Django development version:**
As a special case, you are also permitted to use As a special case, you are also permitted to use

View File

@ -456,10 +456,13 @@ otherwise, they'll be tacked together without whitespace!
.. admonition:: Mind your charset .. admonition:: Mind your charset
When creating a ``.po`` file with your favorite text editor, first edit When creating a PO file with your favorite text editor, first edit
the charset line (search for ``"CHARSET"``) and set it to the charset the charset line (search for ``"CHARSET"``) and set it to the charset
you'll be using to edit the content. Generally, utf-8 should work for most you'll be using to edit the content. Due to the way the ``gettext`` tools
languages, but ``gettext`` should handle any charset you throw at it. work internally and because we want to allow non-ASCII source strings in
Django's core and your applications, you **must** use UTF-8 as the encoding
for your PO file (this means that everybody will be using the same
encoding, which is important when Django processes the PO files).
To reexamine all source code and templates for new translation strings and To reexamine all source code and templates for new translation strings and
update all message files for **all** languages, run this:: update all message files for **all** languages, run this::

View File

@ -66,6 +66,7 @@ installed.
* If you're using SQLite, you'll need pysqlite_. Use version 2.0.3 or higher. * If you're using SQLite, you'll need pysqlite_. Use version 2.0.3 or higher.
* If you're using Oracle, you'll need cx_Oracle_, version 4.3.1 or higher. * If you're using Oracle, you'll need cx_Oracle_, version 4.3.1 or higher.
You will also want to read the database-specific notes for the `Oracle backend`_.
If you plan to use Django's ``manage.py syncdb`` command to If you plan to use Django's ``manage.py syncdb`` command to
automatically create database tables for your models, you'll need to automatically create database tables for your models, you'll need to
@ -88,6 +89,7 @@ to create a temporary test database.
.. _MySQL backend: ../databases/ .. _MySQL backend: ../databases/
.. _cx_Oracle: http://cx-oracle.sourceforge.net/ .. _cx_Oracle: http://cx-oracle.sourceforge.net/
.. _Oracle: http://www.oracle.com/ .. _Oracle: http://www.oracle.com/
.. _Oracle backend: ../databases/#oracle-notes
.. _testing framework: ../testing/ .. _testing framework: ../testing/
Remove any old versions of Django Remove any old versions of Django

View File

@ -1923,11 +1923,22 @@ of the model fields:
.. note:: .. note::
If you specify ``fields`` when creating a form with ``form_for_model()``, If you specify ``fields`` when creating a form with ``form_for_model()``,
make sure that the fields that are *not* specified can provide default then the fields that are *not* specified will not be set by the form's
values, or are allowed to have a value of ``None``. If a field isn't ``save()`` method. Django will prevent any attempt to save an incomplete
specified on a form, the object created from the form can't provide model, so if the model does not allow the missing fields to be empty, and
a value for that attribute, which will prevent the new instance from does not provide a default value for the missing fields, any attempt to
being saved. ``save()`` a ``form_for_model`` with missing fields will fail. To avoid
this failure, you must use ``save(commit=False)`` and manually set any
extra required fields::
instance = form.save(commit=False)
instance.required_field = 'new value'
instance.save()
See the `section on saving forms`_ for more details on using
``save(commit=False)``.
.. _section on saving forms: `The save() method`_
Overriding the default field types Overriding the default field types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -2064,9 +2075,9 @@ More coming soon
================ ================
That's all the documentation for now. For more, see the file That's all the documentation for now. For more, see the file
http://code.djangoproject.com/browser/django/trunk/tests/regressiontests/forms/tests.py http://code.djangoproject.com/browser/django/trunk/tests/regressiontests/forms
-- the unit tests for ``django.newforms``. This can give you a good idea of -- the unit tests for ``django.newforms``. This can give you a good idea of
what's possible. what's possible. (Each submodule there contains separate tests.)
If you're really itching to learn and use this library, please be patient. If you're really itching to learn and use this library, please be patient.
We're working hard on finishing both the code and documentation. We're working hard on finishing both the code and documentation.

View File

@ -190,7 +190,7 @@ necessary because some HTML form elements, notably
That means you can't change attributes of ``request.POST`` and ``request.GET`` That means you can't change attributes of ``request.POST`` and ``request.GET``
directly. directly.
``QueryDict`` implements the all standard dictionary methods, because it's a ``QueryDict`` implements all the standard dictionary methods, because it's a
subclass of dictionary. Exceptions are outlined here: subclass of dictionary. Exceptions are outlined here:
* ``__getitem__(key)`` -- Returns the value for the given key. If the key * ``__getitem__(key)`` -- Returns the value for the given key. If the key

View File

@ -205,7 +205,7 @@ An API is available to manipulate session data outside of a view::
datetime.datetime(2005, 8, 20, 13, 35, 0) datetime.datetime(2005, 8, 20, 13, 35, 0)
>>> s.save() >>> s.save()
If you're using the ``django.contrib.sessions.engine.db`` backend, each If you're using the ``django.contrib.sessions.backends.db`` backend, each
session is just a normal Django model. The ``Session`` model is defined in session is just a normal Django model. The ``Session`` model is defined in
``django/contrib/sessions/models.py``. Because it's a normal model, you can ``django/contrib/sessions/models.py``. Because it's a normal model, you can
access sessions using the normal Django database API:: access sessions using the normal Django database API::

View File

@ -363,7 +363,7 @@ regular expression which will hide from the DEBUG view anything that contains
be able to give backtraces without seeing sensitive (or offensive) settings. be able to give backtraces without seeing sensitive (or offensive) settings.
Still, note that there are always going to be sections of your debug output that Still, note that there are always going to be sections of your debug output that
are inapporpriate for public consumption. File paths, configuration options, and are inappropriate for public consumption. File paths, configuration options, and
the like all give attackers extra information about your server. Never deploy a the like all give attackers extra information about your server. Never deploy a
site with ``DEBUG`` turned on. site with ``DEBUG`` turned on.

View File

@ -316,7 +316,7 @@ optional, third positional argument, ``processors``. In this example, the
}, [ip_address_processor]) }, [ip_address_processor])
return t.render(c) return t.render(c)
Note:: .. note::
If you're using Django's ``render_to_response()`` shortcut to populate a If you're using Django's ``render_to_response()`` shortcut to populate a
template with the contents of a dictionary, your template will be passed a template with the contents of a dictionary, your template will be passed a
``Context`` instance by default (not a ``RequestContext``). To use a ``Context`` instance by default (not a ``RequestContext``). To use a
@ -928,10 +928,36 @@ current context, available in the ``render`` method::
``resolve_variable`` will try to resolve ``blog_entry.date_updated`` and then ``resolve_variable`` will try to resolve ``blog_entry.date_updated`` and then
format it accordingly. format it accordingly.
.. note:: .. admonition:: New in development version:
The ``resolve_variable()`` function will throw a ``VariableDoesNotExist``
exception if it cannot resolve the string passed to it in the current Variable resolution has changed in the development version of Django.
context of the page. ``template.resolve_variable()`` is still available, but has been deprecated
in favor of a new ``template.Variable`` class. Using this class will usually
be more efficient than calling ``template.resolve_variable``
To use the ``Variable`` class, simply instantiate it with the name of the
variable to be resolved, and then call ``variable.resolve(context)``. So,
in the development version, the above example would be more correctly
written as:
.. parsed-literal::
class FormatTimeNode(template.Node):
def __init__(self, date_to_be_formatted, format_string):
self.date_to_be_formatted = **Variable(date_to_be_formatted)**
self.format_string = format_string
def render(self, context):
try:
actual_date = **self.date_to_be_formatted.resolve(context)**
return actual_date.strftime(self.format_string)
except template.VariableDoesNotExist:
return ''
Changes are highlighted in bold.
Variable resolution will throw a ``VariableDoesNotExist`` exception if it cannot
resolve the string passed to it in the current context of the page.
Shortcut for simple tags Shortcut for simple tags
~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -110,19 +110,22 @@ Conversion functions
The ``django.utils.encoding`` module contains a few functions that are handy The ``django.utils.encoding`` module contains a few functions that are handy
for converting back and forth between Unicode and bytestrings. for converting back and forth between Unicode and bytestrings.
* ``smart_unicode(s, encoding='utf-8', errors='strict')`` converts its * ``smart_unicode(s, encoding='utf-8', strings_only=False, errors='strict')``
input to a Unicode string. The ``encoding`` parameter specifies the input converts its input to a Unicode string. The ``encoding`` parameter
encoding. (For example, Django uses this internally when processing form specifies the input encoding. (For example, Django uses this internally
input data, which might not be UTF-8 encoded.) The ``errors`` parameter when processing form input data, which might not be UTF-8 encoded.) The
takes any of the values that are accepted by Python's ``unicode()`` ``strings_only`` parameter, if set to True, will result in Python
function for its error handling. numbers, booleans and ``None`` not being converted to a string (they keep
their original types). The ``errors`` parameter takes any of the values
that are accepted by Python's ``unicode()`` function for its error
handling.
If you pass ``smart_unicode()`` an object that has a ``__unicode__`` If you pass ``smart_unicode()`` an object that has a ``__unicode__``
method, it will use that method to do the conversion. method, it will use that method to do the conversion.
* ``force_unicode(s, encoding='utf-8', errors='strict')`` is identical to * ``force_unicode(s, encoding='utf-8', strings_only=False, errors='strict')``
``smart_unicode()`` in almost all cases. The difference is when the is identical to ``smart_unicode()`` in almost all cases. The difference
first argument is a `lazy translation`_ instance. While is when the first argument is a `lazy translation`_ instance. While
``smart_unicode()`` preserves lazy translations, ``force_unicode()`` ``smart_unicode()`` preserves lazy translations, ``force_unicode()``
forces those objects to a Unicode string (causing the translation to forces those objects to a Unicode string (causing the translation to
occur). Normally, you'll want to use ``smart_unicode()``. However, occur). Normally, you'll want to use ``smart_unicode()``. However,
@ -132,11 +135,10 @@ for converting back and forth between Unicode and bytestrings.
* ``smart_str(s, encoding='utf-8', strings_only=False, errors='strict')`` * ``smart_str(s, encoding='utf-8', strings_only=False, errors='strict')``
is essentially the opposite of ``smart_unicode()``. It forces the first is essentially the opposite of ``smart_unicode()``. It forces the first
argument to a bytestring. The ``strings_only`` parameter, if set to True, argument to a bytestring. The ``strings_only`` parameter has the same
will result in Python integers, booleans and ``None`` not being behaviour as for ``smart_unicode()`` and ``force_unicode()``. This is
converted to a string (they keep their original types). This is slightly slightly different semantics from Python's builtin ``str()`` function,
different semantics from Python's builtin ``str()`` function, but the but the difference is needed in a few places within Django's internals.
difference is needed in a few places within Django's internals.
Normally, you'll only need to use ``smart_unicode()``. Call it as early as Normally, you'll only need to use ``smart_unicode()``. Call it as early as
possible on any input data that might be either Unicode or a bytestring, and possible on any input data that might be either Unicode or a bytestring, and

View File

@ -152,7 +152,7 @@ TypeError: 'foo' is an invalid keyword argument for this function
>>> a6 = Article(pub_date=datetime(2005, 7, 31)) >>> a6 = Article(pub_date=datetime(2005, 7, 31))
>>> a6.save() >>> a6.save()
>>> a6.headline >>> a6.headline
'Default headline' u'Default headline'
# For DateTimeFields, Django saves as much precision (in seconds) as you # For DateTimeFields, Django saves as much precision (in seconds) as you
# give it. # give it.

View File

@ -42,7 +42,7 @@ __test__ = {'API_TESTS':"""
# Access database columns via Python attributes. # Access database columns via Python attributes.
>>> a.headline >>> a.headline
'Default headline' u'Default headline'
# make sure the two dates are sufficiently close # make sure the two dates are sufficiently close
>>> d = now - a.pub_date >>> d = now - a.pub_date

View File

@ -63,6 +63,9 @@ class Movie(models.Model):
def __unicode__(self): def __unicode__(self):
return self.title return self.title
class Score(models.Model):
score = models.FloatField()
__test__ = {'API_TESTS':""" __test__ = {'API_TESTS':"""
# Create some data: # Create some data:
@ -83,7 +86,7 @@ __test__ = {'API_TESTS':"""
>>> a2 = Article( >>> a2 = Article(
... author = joe, ... author = joe,
... headline = "Time to reform copyright", ... headline = "Time to reform copyright",
... pub_date = datetime(2006, 6, 16, 13, 00)) ... pub_date = datetime(2006, 6, 16, 13, 00, 11, 345))
>>> a1.save(); a2.save() >>> a1.save(); a2.save()
>>> a1.categories = [sports, op_ed] >>> a1.categories = [sports, op_ed]
>>> a2.categories = [music, op_ed] >>> a2.categories = [music, op_ed]
@ -181,7 +184,7 @@ __test__ = {'API_TESTS':"""
# Serializer output can be restricted to a subset of fields # Serializer output can be restricted to a subset of fields
>>> print serializers.serialize("json", Article.objects.all(), fields=('headline','pub_date')) >>> print serializers.serialize("json", Article.objects.all(), fields=('headline','pub_date'))
[{"pk": 1, "model": "serializers.article", "fields": {"headline": "Just kidding; I love TV poker", "pub_date": "2006-06-16 11:00:00"}}, {"pk": 2, "model": "serializers.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 3, "model": "serializers.article", "fields": {"headline": "Forward references pose no problem", "pub_date": "2006-06-16 15:00:00"}}] [{"pk": 1, "model": "serializers.article", "fields": {"headline": "Just kidding; I love TV poker", "pub_date": "2006-06-16 11:00:00"}}, {"pk": 2, "model": "serializers.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:11"}}, {"pk": 3, "model": "serializers.article", "fields": {"headline": "Forward references pose no problem", "pub_date": "2006-06-16 15:00:00"}}]
# Every string is serialized as a unicode object, also primary key # Every string is serialized as a unicode object, also primary key
# which is 'varchar' # which is 'varchar'
@ -207,4 +210,11 @@ u'G\u0119\u015bl\u0105 ja\u017a\u0144'
>>> print list(serializers.deserialize('json', serializers.serialize('json', [mv2])))[0].object.id >>> print list(serializers.deserialize('json', serializers.serialize('json', [mv2])))[0].object.id
None None
# Serialization and deserialization of floats:
>>> sc = Score(score=3.4)
>>> print serializers.serialize("json", [sc])
[{"pk": null, "model": "serializers.score", "fields": {"score": 3.4}}]
>>> print list(serializers.deserialize('json', serializers.serialize('json', [sc])))[0].object.score
3.4
"""} """}

View File

@ -54,7 +54,7 @@ Is updated
pre_delete signal, Tom Smith pre_delete signal, Tom Smith
instance.id is not None: True instance.id is not None: True
post_delete signal, Tom Smith post_delete signal, Tom Smith
instance.id is None: True instance.id is None: False
>>> p2 = Person(first_name='James', last_name='Jones') >>> p2 = Person(first_name='James', last_name='Jones')
>>> p2.id = 99999 >>> p2.id = 99999
@ -73,7 +73,7 @@ Is created
pre_delete signal, James Jones pre_delete signal, James Jones
instance.id is not None: True instance.id is not None: True
post_delete signal, James Jones post_delete signal, James Jones
instance.id is None: True instance.id is None: False
>>> Person.objects.all() >>> Person.objects.all()
[<Person: James Jones>] [<Person: James Jones>]

View File

@ -0,0 +1,9 @@
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = "Dance around like a madman."
args = ''
requires_model_validation = True
def handle(self, *args, **options):
print "I don't feel like dancing."

View File

@ -0,0 +1,30 @@
"""
37. User-registered management commands
The manage.py utility provides a number of useful commands for managing a
Django project. If you want to add a utility command of your own, you can.
The user-defined command 'dance' is defined in the management/commands
subdirectory of this test application. It is a simple command that responds
with a printed message when invoked.
For more details on how to define your own manage.py commands, look at the
django.core.management.commands directory. This directory contains the
definitions for the base Django manage.py commands.
"""
__test__ = {'API_TESTS': """
>>> from django.core import management
# Invoke a simple user-defined command
>>> management.call_command('dance')
I don't feel like dancing.
# Invoke a command that doesn't exist
>>> management.call_command('explode')
Traceback (most recent call last):
...
CommandError: Unknown command: 'explode'
"""}

View File

@ -8,7 +8,7 @@
>>> q['foo'] >>> q['foo']
Traceback (most recent call last): Traceback (most recent call last):
... ...
MultiValueDictKeyError: "Key 'foo' not found in <MultiValueDict: {}>" MultiValueDictKeyError: "Key 'foo' not found in <QueryDict: {}>"
>>> q['something'] = 'bar' >>> q['something'] = 'bar'
Traceback (most recent call last): Traceback (most recent call last):
@ -89,7 +89,7 @@ AttributeError: This QueryDict instance is immutable
>>> q['foo'] >>> q['foo']
Traceback (most recent call last): Traceback (most recent call last):
... ...
MultiValueDictKeyError: "Key 'foo' not found in <MultiValueDict: {}>" MultiValueDictKeyError: "Key 'foo' not found in <QueryDict: {}>"
>>> q['name'] = 'john' >>> q['name'] = 'john'
@ -201,7 +201,7 @@ u'bar'
>>> q['bar'] >>> q['bar']
Traceback (most recent call last): Traceback (most recent call last):
... ...
MultiValueDictKeyError: "Key 'bar' not found in <MultiValueDict: {u'foo': [u'bar']}>" MultiValueDictKeyError: "Key 'bar' not found in <QueryDict: {u'foo': [u'bar']}>"
>>> q['something'] = 'bar' >>> q['something'] = 'bar'
Traceback (most recent call last): Traceback (most recent call last):

View File

@ -0,0 +1,12 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
class TestModel(models.Model):
text = models.CharField(max_length=10, default=_('Anything'))
__test__ = {'API_TESTS': '''
>>> tm = TestModel()
>>> tm.save()
'''
}

View File

@ -30,4 +30,12 @@ True
>>> s4 = ugettext_lazy('Some other string') >>> s4 = ugettext_lazy('Some other string')
>>> s == s4 >>> s == s4
False False
unicode(string_concat(...)) should not raise a TypeError - #4796
>>> import django.utils.translation
>>> reload(django.utils.translation)
<module 'django.utils.translation' from ...>
>>> unicode(django.utils.translation.string_concat("dja", "ngo"))
u'django'
""" """

View File

@ -43,9 +43,9 @@ class MonthArchiveTest(TestCase):
author.save() author.save()
# 2004 was a leap year, so it should be weird enough to not cheat # 2004 was a leap year, so it should be weird enough to not cheat
first_second_of_feb = datetime(2004, 2, 1, 0, 0, 0) first_second_of_feb = datetime(2004, 2, 1, 0, 0, 1)
first_second_of_mar = datetime(2004, 3, 1, 0, 0, 0) first_second_of_mar = datetime(2004, 3, 1, 0, 0, 1)
one_microsecond = timedelta(0, 0, 1) two_seconds = timedelta(0, 2, 0)
article = Article(title="example", author=author) article = Article(title="example", author=author)
article.date_created = first_second_of_feb article.date_created = first_second_of_feb
@ -53,12 +53,12 @@ class MonthArchiveTest(TestCase):
response = self.client.get('/views/date_based/archive_month/2004/02/') response = self.client.get('/views/date_based/archive_month/2004/02/')
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
article.date_created = first_second_of_feb-one_microsecond article.date_created = first_second_of_feb-two_seconds
article.save() article.save()
response = self.client.get('/views/date_based/archive_month/2004/02/') response = self.client.get('/views/date_based/archive_month/2004/02/')
self.assertEqual(response.status_code, 404) self.assertEqual(response.status_code, 404)
article.date_created = first_second_of_mar-one_microsecond article.date_created = first_second_of_mar-two_seconds
article.save() article.save()
response = self.client.get('/views/date_based/archive_month/2004/02/') response = self.client.get('/views/date_based/archive_month/2004/02/')
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)