1
0
mirror of https://github.com/django/django.git synced 2025-07-05 10:19:20 +00:00

[multi-db] Merge trunk to [3354]

git-svn-id: http://code.djangoproject.com/svn/django/branches/multiple-db-support@3355 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jason Pellerin 2006-07-16 23:11:33 +00:00
parent 49ce784805
commit 541ac3b990
47 changed files with 2403 additions and 191 deletions

View File

@ -72,6 +72,7 @@ answer newbie questions, and generally made Django that much better:
junzhang.jn@gmail.com junzhang.jn@gmail.com
Russell Keith-Magee <freakboy@iinet.net.au> Russell Keith-Magee <freakboy@iinet.net.au>
Garth Kidd <http://www.deadlybloodyserious.com/> Garth Kidd <http://www.deadlybloodyserious.com/>
kilian <kilian.cavalotti@lip6.fr>
Sune Kirkeby <http://ibofobi.dk/> Sune Kirkeby <http://ibofobi.dk/>
Cameron Knight (ckknight) Cameron Knight (ckknight)
Bruce Kroeze <http://coderseye.com/> Bruce Kroeze <http://coderseye.com/>

View File

@ -36,6 +36,7 @@ LANGUAGE_CODE = 'en-us'
# Languages we provide translations for, out of the box. The language name # Languages we provide translations for, out of the box. The language name
# should be the utf-8 encoded local name for the language. # should be the utf-8 encoded local name for the language.
LANGUAGES = ( LANGUAGES = (
('ar', gettext_noop('Arabic')),
('bn', gettext_noop('Bengali')), ('bn', gettext_noop('Bengali')),
('cs', gettext_noop('Czech')), ('cs', gettext_noop('Czech')),
('cy', gettext_noop('Welsh')), ('cy', gettext_noop('Welsh')),
@ -67,7 +68,7 @@ LANGUAGES = (
) )
# Languages using BiDi (right-to-left) layout # Languages using BiDi (right-to-left) layout
LANGUAGES_BIDI = ("he",) LANGUAGES_BIDI = ("he", "ar")
# If you set this to False, Django will make some optimizations so as not # If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery. # to load the internationalization machinery.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,110 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Django SVN\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2005-12-09 11:51+0100\n"
"PO-Revision-Date: 2006-07-06 23:50+0300\n"
"Last-Translator: Ahmad Alhashemi <ahmad@ahmadh.com>\n"
"Language-Team: Ahmad Alhashemi <trans@ahmadh.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-Language: Arabic\n"
"X-Poedit-Country: Kuwait\n"
"X-Poedit-SourceCharset: utf-8\n"
#: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format
msgid "Available %s"
msgstr "%s متوفرة"
#: contrib/admin/media/js/SelectFilter2.js:41
msgid "Choose all"
msgstr "اختيار الكل"
#: contrib/admin/media/js/SelectFilter2.js:46
msgid "Add"
msgstr "إضافة"
#: contrib/admin/media/js/SelectFilter2.js:48
msgid "Remove"
msgstr "حذف"
#: contrib/admin/media/js/SelectFilter2.js:53
#, perl-format
msgid "Chosen %s"
msgstr "%s اختيرت"
#: contrib/admin/media/js/SelectFilter2.js:54
msgid "Select your choice(s) and click "
msgstr "حدد خيارك أو خياراتك واضغط"
#: contrib/admin/media/js/SelectFilter2.js:59
msgid "Clear all"
msgstr "مسح الكل"
#: contrib/admin/media/js/dateparse.js:26
#: contrib/admin/media/js/calendar.js:24
msgid "January February March April May June July August September October November December"
msgstr "يناير فبراير مارس إبريل مايو يونيو يوليو أغسطس سبتمبر أكتوبر نوفمبر ديسمبر"
#: contrib/admin/media/js/dateparse.js:27
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr "الأحد الأثنين الثلاثاء الأربعاء الخميس الجمعة السبت"
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
msgstr "أ أ ث أ خ ج س"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
msgid "Now"
msgstr "الآن"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
msgid "Clock"
msgstr "الساعة"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
msgid "Choose a time"
msgstr "اختر وقتا ما"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Midnight"
msgstr "منتصف الليل"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "6 a.m."
msgstr "6 ص."
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "Noon"
msgstr "الظهر"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
msgid "Cancel"
msgstr "الغاء"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
msgid "Today"
msgstr "اليوم"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
msgid "Calendar"
msgstr "التقويم"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
msgid "Yesterday"
msgstr "يوم أمس"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
msgid "Tomorrow"
msgstr "الغد"

Binary file not shown.

View File

@ -26,7 +26,7 @@
{% block nav-global %}{% endblock %} {% block nav-global %}{% endblock %}
</div> </div>
<!-- END Header --> <!-- END Header -->
{% block breadcrumbs %}<div class="breadcrumbs"><a href="/">{% trans 'Home' %}</a>{% if title %} &rsaquo; {{ title }}{% endif %}</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="/">{% trans 'Home' %}</a>{% if title %} &rsaquo; {{ title|escape }}{% endif %}</div>{% endblock %}
{% endif %} {% endif %}
{% if messages %} {% if messages %}
@ -36,7 +36,7 @@
<!-- Content --> <!-- Content -->
<div id="content" class="{% block coltype %}colM{% endblock %}"> <div id="content" class="{% block coltype %}colM{% endblock %}">
{% block pretitle %}{% endblock %} {% block pretitle %}{% endblock %}
{% block content_title %}{% if title %}<h1>{{ title }}</h1>{% endif %}{% endblock %} {% block content_title %}{% if title %}<h1>{{ title|escape }}</h1>{% endif %}{% endblock %}
{% block content %}{{ content }}{% endblock %} {% block content %}{{ content }}{% endblock %}
{% block sidebar %}{% endblock %} {% block sidebar %}{% endblock %}
<br class="clear" /> <br class="clear" />

View File

@ -1,7 +1,7 @@
{% extends "admin/base.html" %} {% extends "admin/base.html" %}
{% load i18n %} {% load i18n %}
{% block title %}{{ title }} | {% trans 'Django site admin' %}{% endblock %} {% block title %}{{ title|escape }} | {% trans 'Django site admin' %}{% endblock %}
{% block branding %} {% block branding %}
<h1 id="site-name">{% trans 'Django administration' %}</h1> <h1 id="site-name">{% trans 'Django administration' %}</h1>

View File

@ -11,8 +11,8 @@
{% 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;
<a href="../">{{ opts.verbose_name_plural|capfirst }}</a> &rsaquo; <a href="../">{{ opts.verbose_name_plural|capfirst|escape }}</a> &rsaquo;
{% if add %}{% trans "Add" %} {{ opts.verbose_name }}{% else %}{{ original|truncatewords:"18"|escape }}{% endif %} {% if add %}{% trans "Add" %} {{ opts.verbose_name|escape }}{% else %}{{ original|truncatewords:"18"|escape }}{% endif %}
</div> </div>
{% endif %}{% endblock %} {% endif %}{% endblock %}
{% block content %}<div id="content-main"> {% block content %}<div id="content-main">

View File

@ -3,12 +3,12 @@
{% 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 %} {% 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 }}</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 %}
<div id="content-main"> <div id="content-main">
{% if has_add_permission %} {% if has_add_permission %}
<ul class="object-tools"><li><a href="add/{% if is_popup %}?_popup=1{% endif %}" class="addlink">{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}</a></li></ul> <ul class="object-tools"><li><a href="add/{% if is_popup %}?_popup=1{% endif %}" class="addlink">{% blocktrans with cl.opts.verbose_name|escape as name %}Add {{ name }}{% endblocktrans %}</a></li></ul>
{% endif %} {% endif %}
<div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist"> <div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
{% block search %}{% search_form cl %}{% endblock %} {% block search %}{% search_form cl %}{% endblock %}

View File

@ -1,9 +1,9 @@
{% if show %} {% if show %}
<div class="xfull"> <div class="xfull">
<ul class="toplinks"> <ul class="toplinks">
{% if back %}<li class="date-back"><a href="{{ back.link }}">&lsaquo; {{ back.title }}</a></li>{% endif %} {% if back %}<li class="date-back"><a href="{{ back.link }}">&lsaquo; {{ back.title|escape }}</a></li>{% endif %}
{% for choice in choices %} {% for choice in choices %}
<li> {% if choice.link %}<a href="{{ choice.link }}">{% endif %}{{ choice.title }}{% if choice.link %}</a>{% endif %}</li> <li> {% if choice.link %}<a href="{{ choice.link }}">{% endif %}{{ choice.title|escape }}{% if choice.link %}</a>{% endif %}</li>
{% endfor %} {% endfor %}
</ul><br class="clear" /> </ul><br class="clear" />
</div> </div>

View File

@ -4,21 +4,21 @@
{% block breadcrumbs %} {% block breadcrumbs %}
<div class="breadcrumbs"> <div class="breadcrumbs">
<a href="../../../../">{% trans "Home" %}</a> &rsaquo; <a href="../../../../">{% trans "Home" %}</a> &rsaquo;
<a href="../../">{{ opts.verbose_name_plural|capfirst }}</a> &rsaquo; <a href="../../">{{ opts.verbose_name_plural|capfirst|escape }}</a> &rsaquo;
<a href="../">{{ object|striptags|truncatewords:"18" }}</a> &rsaquo; <a href="../">{{ object|escape|truncatewords:"18" }}</a> &rsaquo;
{% trans 'Delete' %} {% trans 'Delete' %}
</div> </div>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% if perms_lacking %} {% if perms_lacking %}
<p>{% blocktrans %}Deleting the {{ object_name }} '{{ object }}' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:{% endblocktrans %}</p> <p>{% blocktrans with object|escape as escaped_object %}Deleting the {{ object_name }} '{{ escaped_object }}' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:{% endblocktrans %}</p>
<ul> <ul>
{% for obj in perms_lacking %} {% for obj in perms_lacking %}
<li>{{ obj }}</li> <li>{{ obj|escape }}</li>
{% endfor %} {% endfor %}
</ul> </ul>
{% else %} {% else %}
<p>{% blocktrans %}Are you sure you want to delete the {{ object_name }} "{{ object }}"? All of the following related items will be deleted:{% endblocktrans %}</p> <p>{% blocktrans with object|escape as escaped_object %}Are you sure you want to delete the {{ object_name }} "{{ escaped_object }}"? All of the following related items will be deleted:{% endblocktrans %}</p>
<ul>{{ deleted_objects|unordered_list }}</ul> <ul>{{ deleted_objects|unordered_list }}</ul>
<form action="" method="post"> <form action="" method="post">
<div> <div>

View File

@ -1,7 +1,7 @@
{% load admin_modify %} {% load admin_modify %}
<fieldset class="module aligned"> <fieldset class="module aligned">
{% for fcw in bound_related_object.form_field_collection_wrappers %} {% for fcw in bound_related_object.form_field_collection_wrappers %}
<h2>{{ bound_related_object.relation.opts.verbose_name|capfirst }}&nbsp;#{{ forloop.counter }}</h2> <h2>{{ bound_related_object.relation.opts.verbose_name|capfirst|escape }}&nbsp;#{{ forloop.counter }}</h2>
{% if bound_related_object.show_url %}{% if fcw.obj.original %} {% if bound_related_object.show_url %}{% if fcw.obj.original %}
<p><a href="/r/{{ fcw.obj.original.content_type_id }}/{{ fcw.obj.original.id }}/">View on site</a></p> <p><a href="/r/{{ fcw.obj.original.content_type_id }}/{{ fcw.obj.original.id }}/">View on site</a></p>
{% endif %}{% endif %} {% endif %}{% endif %}

View File

@ -1,10 +1,10 @@
{% load admin_modify %} {% load admin_modify %}
<fieldset class="module"> <fieldset class="module">
<h2>{{ bound_related_object.relation.opts.verbose_name_plural|capfirst }}</h2><table> <h2>{{ bound_related_object.relation.opts.verbose_name_plural|capfirst|escape }}</h2><table>
<thead><tr> <thead><tr>
{% for fw in bound_related_object.field_wrapper_list %} {% for fw in bound_related_object.field_wrapper_list %}
{% if fw.needs_header %} {% if fw.needs_header %}
<th{{ fw.header_class_attribute }}>{{ fw.field.verbose_name|capfirst }}</th> <th{{ fw.header_class_attribute }}>{{ fw.field.verbose_name|capfirst|escape }}</th>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% for fcw in bound_related_object.form_field_collection_wrappers %} {% for fcw in bound_related_object.form_field_collection_wrappers %}

View File

@ -1,5 +1,5 @@
{% load i18n %} {% load i18n %}
<h3>{% blocktrans %} By {{ title }} {% endblocktrans %}</h3> <h3>{% blocktrans with title|escape as filter_title %} By {{ filter_title }} {% endblocktrans %}</h3>
<ul> <ul>
{% for choice in choices %} {% for choice in choices %}
<li{% if choice.selected %} class="selected"{% endif %}> <li{% if choice.selected %} class="selected"{% endif %}>

View File

@ -19,9 +19,9 @@
{% for model in app.models %} {% for model in app.models %}
<tr> <tr>
{% if model.perms.change %} {% if model.perms.change %}
<th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th> <th scope="row"><a href="{{ model.admin_url }}">{{ model.name|escape }}</a></th>
{% else %} {% else %}
<th scope="row">{{ model.name }}</th> <th scope="row">{{ model.name|escape }}</th>
{% endif %} {% endif %}
{% if model.perms.add %} {% if model.perms.add %}
@ -58,7 +58,7 @@
{% else %} {% else %}
<ul class="actionlist"> <ul class="actionlist">
{% for entry in admin_log %} {% for entry in admin_log %}
<li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">{% if not entry.is_deletion %}<a href="{{ entry.get_admin_url }}">{% endif %}{{ entry.object_repr|escape }}{% if not entry.is_deletion %}</a>{% endif %}<br /><span class="mini quiet">{{ entry.content_type.name|capfirst }}</span></li> <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">{% if not entry.is_deletion %}<a href="{{ entry.get_admin_url }}">{% endif %}{{ entry.object_repr|escape }}{% if not entry.is_deletion %}</a>{% endif %}<br /><span class="mini quiet">{{ entry.content_type.name|capfirst|escape }}</span></li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}

View File

@ -1,7 +1,7 @@
{% extends "admin/base_site.html" %} {% extends "admin/base_site.html" %}
{% load i18n %} {% load i18n %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> &rsaquo; {{ title }}</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> &rsaquo; {{ title|escape }}</div>{% endblock %}
{% block content %} {% block content %}

View File

@ -2,7 +2,7 @@
{% 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 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 }}</a> &rsaquo; <a href="../">{{ object|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 %}
{% block content %} {% block content %}

View File

@ -6,6 +6,6 @@
{% paginator_number cl i %} {% paginator_number cl i %}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name }}{% else %}{{ cl.opts.verbose_name_plural }}{% endifequal %} {{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name|escape }}{% else %}{{ cl.opts.verbose_name_plural|escape }}{% endifequal %}
{% if show_all_url %}&nbsp;&nbsp;<a href="{{ show_all_url }}" class="showall">{% trans 'Show all' %}</a>{% endif %} {% if show_all_url %}&nbsp;&nbsp;<a href="{{ show_all_url }}" class="showall">{% trans 'Show all' %}</a>{% endif %}
</p> </p>

View File

@ -9,13 +9,13 @@
</style> </style>
{% endblock %} {% endblock %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> &rsaquo; <a href="../../">Documentation</a> &rsaquo; <a href="../">Models</a> &rsaquo; {{ name }}</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> &rsaquo; <a href="../../">Documentation</a> &rsaquo; <a href="../">Models</a> &rsaquo; {{ name|escape }}</div>{% endblock %}
{% block title %}Model: {{ name }}{% endblock %} {% block title %}Model: {{ name|escape }}{% endblock %}
{% block content %} {% block content %}
<div id="content-main"> <div id="content-main">
<h1>{{ summary }}</h1> <h1>{{ summary|escape }}</h1>
{% if description %} {% if description %}
<p>{% filter escape|linebreaksbr %}{% trans description %}{% endfilter %}</p> <p>{% filter escape|linebreaksbr %}{% trans description %}{% endfilter %}</p>
@ -35,7 +35,7 @@
<tr> <tr>
<td>{{ field.name }}</td> <td>{{ field.name }}</td>
<td>{{ field.data_type }}</td> <td>{{ field.data_type }}</td>
<td>{% if field.verbose %}{{ field.verbose }}{% endif %}{% if field.help_text %} - {{ field.help_text }}{% endif %}</td> <td>{% if field.verbose %}{{ field.verbose|escape }}{% endif %}{% if field.help_text %} - {{ field.help_text|escape }}{% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View File

@ -1,19 +1,19 @@
{% 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 }}</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 userlinks %}<a href="../../../password_change/">{% trans 'Change password' %}</a> / <a href="../../../logout/">{% trans 'Log out' %}</a>{% endblock %}
{% block title %}Template: {{ name }}{% endblock %} {% block title %}Template: {{ name|escape }}{% endblock %}
{% block content %} {% block content %}
<h1>Template: "{{ name }}"</h1> <h1>Template: "{{ name|escape }}"</h1>
{% regroup templates|dictsort:"site_id" by site as templates_by_site %} {% regroup templates|dictsort:"site_id" by site as templates_by_site %}
{% for group in templates_by_site %} {% for group in templates_by_site %}
<h2>Search path for template "{{ name }}" on {{ group.grouper }}:</h2> <h2>Search path for template "{{ name|escape }}" on {{ group.grouper }}:</h2>
<ol> <ol>
{% for template in group.list|dictsort:"order" %} {% for template in group.list|dictsort:"order" %}
<li><code>{{ template.file }}</code>{% if not template.exists %} <em>(does not exist)</em>{% endif %}</li> <li><code>{{ template.file|escape }}</code>{% if not template.exists %} <em>(does not exist)</em>{% endif %}</li>
{% endfor %} {% endfor %}
</ol> </ol>
{% endfor %} {% endfor %}

View File

@ -8,7 +8,7 @@
<h1>{{ name }}</h1> <h1>{{ name }}</h1>
<h2 class="subhead">{{ summary }}</h2> <h2 class="subhead">{{ summary|escape }}</h2>
<p>{{ body }}</p> <p>{{ body }}</p>

View File

@ -1,4 +1,4 @@
{% load admin_modify i18n %}{% if bound_field.original_value %} {% load admin_modify i18n %}{% if bound_field.original_value %}
{% trans "Currently:" %} <a href="{{ bound_field.original_url }}" > {{ bound_field.original_value }} </a><br /> {% trans "Currently:" %} <a href="{{ bound_field.original_url }}" > {{ bound_field.original_value|escape }} </a><br />
{% trans "Change:" %}{% output_all bound_field.form_fields %} {% trans "Change:" %}{% output_all bound_field.form_fields %}
{% else %} {% output_all bound_field.form_fields %} {% endif %} {% else %} {% output_all bound_field.form_fields %} {% endif %}

View File

@ -15,6 +15,6 @@
{{ bound_field.original_value }} {{ bound_field.original_value }}
{% endif %} {% endif %}
{% if bound_field.raw_id_admin %} {% if bound_field.raw_id_admin %}
{% if bound_field.existing_display %}&nbsp;<strong>{{ bound_field.existing_display|truncatewords:"14" }}</strong>{% endif %} {% if bound_field.existing_display %}&nbsp;<strong>{{ bound_field.existing_display|truncatewords:"14"|escape }}</strong>{% endif %}
{% endif %} {% endif %}
{% endif %} {% endif %}

View File

@ -1,2 +1,2 @@
{% if add %}{% include "widget/foreign.html" %}{% endif %} {% if add %}{% include "widget/foreign.html" %}{% endif %}
{% if change %}{% if bound_field.existing_display %}&nbsp;<strong>{{ bound_field.existing_display|truncatewords:"14" }}</strong>{% endif %}{% endif %} {% if change %}{% if bound_field.existing_display %}&nbsp;<strong>{{ bound_field.existing_display|truncatewords:"14"|escape }}</strong>{% endif %}{% endif %}

View File

@ -165,12 +165,14 @@ def items_for_result(cl, result):
result_repr = escape(str(field_val)) result_repr = escape(str(field_val))
if result_repr == '': if result_repr == '':
result_repr = '&nbsp;' result_repr = '&nbsp;'
if first: # First column is a special case # If list_display_links not defined, add the link tag to the first field
if (first and not cl.lookup_opts.admin.list_display_links) or field_name in cl.lookup_opts.admin.list_display_links:
table_tag = {True:'th', False:'td'}[first]
first = False first = False
url = cl.url_for_result(result) url = cl.url_for_result(result)
result_id = str(getattr(result, pk)) # str() is needed in case of 23L (long ints) result_id = str(getattr(result, pk)) # str() is needed in case of 23L (long ints)
yield ('<th%s><a href="%s"%s>%s</a></th>' % \ yield ('<%s%s><a href="%s"%s>%s</a></%s>' % \
(row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %r); return false;"' % result_id or ''), result_repr)) (table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %r); return false;"' % result_id or ''), result_repr, table_tag))
else: else:
yield ('<td%s>%s</td>' % (row_class, result_repr)) yield ('<td%s>%s</td>' % (row_class, result_repr))

View File

@ -38,7 +38,7 @@ def authenticate(**credentials):
if user is None: if user is None:
continue continue
# Annotate the user object with the path of the backend. # Annotate the user object with the path of the backend.
user.backend = str(backend.__class__) user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__)
return user return user
def login(request, user): def login(request, user):

View File

@ -239,7 +239,7 @@ class User(models.Model):
app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.') app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.')
model = models.get_model(app_label, model_name) model = models.get_model(app_label, model_name)
self._profile_cache = model._default_manager.get(user__id__exact=self.id) self._profile_cache = model._default_manager.get(user__id__exact=self.id)
except ImportError, ImproperlyConfigured: except (ImportError, ImproperlyConfigured):
raise SiteProfileNotAvailable raise SiteProfileNotAvailable
return self._profile_cache return self._profile_cache

View File

@ -10,7 +10,7 @@ class FlatPage(models.Model):
content = models.TextField(_('content')) content = models.TextField(_('content'))
enable_comments = models.BooleanField(_('enable comments')) enable_comments = models.BooleanField(_('enable comments'))
template_name = models.CharField(_('template name'), maxlength=70, blank=True, template_name = models.CharField(_('template name'), maxlength=70, blank=True,
help_text=_("Example: 'flatpages/contact_page'. If this isn't provided, the system will use 'flatpages/default'.")) help_text=_("Example: 'flatpages/contact_page.html'. If this isn't provided, the system will use 'flatpages/default.html'."))
registration_required = models.BooleanField(_('registration required'), help_text=_("If this is checked, only logged-in users will be able to view the page.")) registration_required = models.BooleanField(_('registration required'), help_text=_("If this is checked, only logged-in users will be able to view the page."))
sites = models.ManyToManyField(Site) sites = models.ManyToManyField(Site)
class Meta: class Meta:

View File

@ -45,8 +45,8 @@ def disable_termcolors():
global style global style
style = dummy() style = dummy()
# Disable terminal coloring on Windows or if somebody's piping the output. # Disable terminal coloring on Windows, Pocket PC, or if somebody's piping the output.
if sys.platform == 'win32' or not sys.stdout.isatty(): if sys.platform == 'win32' or sys.platform == 'Pocket PC' or not sys.stdout.isatty():
disable_termcolors() disable_termcolors()
# singleton representing the default connection # singleton representing the default connection
@ -847,6 +847,19 @@ def get_validation_errors(outfile, app=None):
else: else:
if isinstance(f, models.ManyToManyField): if isinstance(f, models.ManyToManyField):
e.add(opts, '"admin.list_display" doesn\'t support ManyToManyFields (%r).' % fn) e.add(opts, '"admin.list_display" doesn\'t support ManyToManyFields (%r).' % fn)
# list_display_links
if opts.admin.list_display_links and not opts.admin.list_display:
e.add(opts, '"admin.list_display" must be defined for "admin.list_display_links" to be used.')
if not isinstance(opts.admin.list_display_links, (list, tuple)):
e.add(opts, '"admin.list_display_links", if given, must be set to a list or tuple.')
else:
for fn in opts.admin.list_display_links:
try:
f = opts.get_field(fn)
except models.FieldDoesNotExist:
e.add(opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn)
if fn not in opts.admin.list_display:
e.add(opts, '"admin.list_display_links" refers to %r, which is not defined in "admin.list_display".' % fn)
# list_filter # list_filter
if not isinstance(opts.admin.list_filter, (list, tuple)): if not isinstance(opts.admin.list_filter, (list, tuple)):
e.add(opts, '"admin.list_filter", if given, must be set to a list or tuple.') e.add(opts, '"admin.list_filter", if given, must be set to a list or tuple.')
@ -922,7 +935,7 @@ def _check_for_validation_errors(app=None):
sys.stderr.write(s.read()) sys.stderr.write(s.read())
sys.exit(1) sys.exit(1)
def runserver(addr, port): def runserver(addr, port, use_reloader=True):
"Starts a lightweight Web server for development." "Starts a lightweight Web server for development."
from django.core.servers.basehttp import run, AdminMediaHandler, WSGIServerException from django.core.servers.basehttp import run, AdminMediaHandler, WSGIServerException
from django.core.handlers.wsgi import WSGIHandler from django.core.handlers.wsgi import WSGIHandler
@ -956,9 +969,12 @@ def runserver(addr, port):
sys.exit(1) sys.exit(1)
except KeyboardInterrupt: except KeyboardInterrupt:
sys.exit(0) sys.exit(0)
from django.utils import autoreload if use_reloader:
autoreload.main(inner_run) from django.utils import autoreload
runserver.args = '[optional port number, or ipaddr:port]' autoreload.main(inner_run)
else:
inner_run()
runserver.args = '[--noreload] [optional port number, or ipaddr:port]'
def createcachetable(tablename): def createcachetable(tablename):
"Creates the table needed to use the SQL cache backend" "Creates the table needed to use the SQL cache backend"
@ -1107,6 +1123,8 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
help='Lets you manually add a directory the Python path, e.g. "/home/djangoprojects/myproject".') help='Lets you manually add a directory the Python path, e.g. "/home/djangoprojects/myproject".')
parser.add_option('--plain', action='store_true', dest='plain', parser.add_option('--plain', action='store_true', dest='plain',
help='Tells Django to use plain Python, not IPython, for "shell" command.') help='Tells Django to use plain Python, not IPython, for "shell" command.')
parser.add_option('--noreload', action='store_false', dest='use_reloader', default=True,
help='Tells Django to NOT use the auto-reloader when running the development server.')
options, args = parser.parse_args(argv[1:]) options, args = parser.parse_args(argv[1:])
# Take care of options. # Take care of options.
@ -1162,7 +1180,7 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
addr, port = args[1].split(':') addr, port = args[1].split(':')
except ValueError: except ValueError:
addr, port = '', args[1] addr, port = '', args[1]
action_mapping[action](addr, port) action_mapping[action](addr, port, options.use_reloader)
elif action == 'runfcgi': elif action == 'runfcgi':
action_mapping[action](args[1:]) action_mapping[action](args[1:])
else: else:

View File

@ -23,7 +23,7 @@ ansi_datetime_re = re.compile('^%s %s$' % (_datere, _timere))
email_re = re.compile( email_re = re.compile(
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}$', re.IGNORECASE) # domain r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain
integer_re = re.compile(r'^-?\d+$') integer_re = re.compile(r'^-?\d+$')
ip4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$') ip4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE) phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE)

View File

@ -46,7 +46,7 @@ def manipulator_valid_rel_key(f, self, field_data, all_data):
"Validates that the value is a valid foreign key" "Validates that the value is a valid foreign key"
klass = f.rel.to klass = f.rel.to
try: try:
klass._default_manager.get(pk=field_data) klass._default_manager.get(**{f.rel.field_name: field_data})
except klass.DoesNotExist: except klass.DoesNotExist:
raise validators.ValidationError, _("Please enter a valid %s.") % f.verbose_name raise validators.ValidationError, _("Please enter a valid %s.") % f.verbose_name

View File

@ -212,12 +212,13 @@ class Options(object):
return self._field_types[field_type] return self._field_types[field_type]
class AdminOptions(object): class AdminOptions(object):
def __init__(self, fields=None, js=None, list_display=None, list_filter=None, def __init__(self, fields=None, js=None, list_display=None, list_display_links=None, list_filter=None,
date_hierarchy=None, save_as=False, ordering=None, search_fields=None, date_hierarchy=None, save_as=False, ordering=None, search_fields=None,
save_on_top=False, list_select_related=False, manager=None, list_per_page=100): save_on_top=False, list_select_related=False, manager=None, list_per_page=100):
self.fields = fields self.fields = fields
self.js = js or [] self.js = js or []
self.list_display = list_display or ['__str__'] self.list_display = list_display or ['__str__']
self.list_display_links = list_display_links or []
self.list_filter = list_filter or [] self.list_filter = list_filter or []
self.date_hierarchy = date_hierarchy self.date_hierarchy = date_hierarchy
self.save_as, self.ordering = save_as, ordering self.save_as, self.ordering = save_as, ordering

View File

@ -85,8 +85,8 @@ class QuerySet(object):
self._where = [] # List of extra WHERE clauses to use. self._where = [] # List of extra WHERE clauses to use.
self._params = [] # List of params to use for extra WHERE clauses. self._params = [] # List of params to use for extra WHERE clauses.
self._tables = [] # List of extra tables to use. self._tables = [] # List of extra tables to use.
self._offset = None # OFFSET clause self._offset = None # OFFSET clause.
self._limit = None # LIMIT clause self._limit = None # LIMIT clause.
self._result_cache = None self._result_cache = None
######################## ########################
@ -444,8 +444,7 @@ class QuerySet(object):
params = self._params[:] params = self._params[:]
# Convert self._filters into SQL. # Convert self._filters into SQL.
tables2, joins2, where2, params2 = self._filters.get_sql(opts) joins2, where2, params2 = self._filters.get_sql(opts)
tables.extend(tables2)
joins.update(joins2) joins.update(joins2)
where.extend(where2) where.extend(where2)
params.extend(params2) params.extend(params2)
@ -580,16 +579,15 @@ class QOperator(object):
self.args = args self.args = args
def get_sql(self, opts): def get_sql(self, opts):
tables, joins, where, params = [], SortedDict(), [], [] joins, where, params = SortedDict(), [], []
for val in self.args: for val in self.args:
tables2, joins2, where2, params2 = val.get_sql(opts) joins2, where2, params2 = val.get_sql(opts)
tables.extend(tables2)
joins.update(joins2) joins.update(joins2)
where.extend(where2) where.extend(where2)
params.extend(params2) params.extend(params2)
if where: if where:
return tables, joins, ['(%s)' % self.operator.join(where)], params return joins, ['(%s)' % self.operator.join(where)], params
return tables, joins, [], params return joins, [], params
class QAnd(QOperator): class QAnd(QOperator):
"Encapsulates a combined query that uses 'AND'." "Encapsulates a combined query that uses 'AND'."
@ -640,9 +638,9 @@ class QNot(Q):
self.q = q self.q = q
def get_sql(self, opts): def get_sql(self, opts):
tables, joins, where, params = self.q.get_sql(opts) joins, where, params = self.q.get_sql(opts)
where2 = ['(NOT (%s))' % " AND ".join(where)] where2 = ['(NOT (%s))' % " AND ".join(where)]
return tables, joins, where2, params return joins, where2, params
def get_where_clause(opts, lookup_type, table_prefix, field_name, value): def get_where_clause(opts, lookup_type, table_prefix, field_name, value):
backend = opts.connection_info.backend backend = opts.connection_info.backend
@ -682,20 +680,20 @@ def fill_table_cache(opts, select, tables, where, old_prefix, cache_tables_seen)
place) for select_related queries. place) for select_related queries.
""" """
backend = opts.connection_info.backend backend = opts.connection_info.backend
qn = backend.quote_name
for f in opts.fields: for f in opts.fields:
if f.rel and not f.null: if f.rel and not f.null:
db_table = f.rel.to._meta.db_table db_table = f.rel.to._meta.db_table
if db_table not in cache_tables_seen: if db_table not in cache_tables_seen:
tables.append(backend.quote_name(db_table)) tables.append(qn(db_table))
else: # The table was already seen, so give it a table alias. else: # The table was already seen, so give it a table alias.
new_prefix = '%s%s' % (db_table, len(cache_tables_seen)) new_prefix = '%s%s' % (db_table, len(cache_tables_seen))
tables.append('%s %s' % (backend.quote_name(db_table), backend.quote_name(new_prefix))) tables.append('%s %s' % (qn(db_table), qn(new_prefix)))
db_table = new_prefix db_table = new_prefix
cache_tables_seen.append(db_table) cache_tables_seen.append(db_table)
where.append('%s.%s = %s.%s' % \ where.append('%s.%s = %s.%s' % \
(backend.quote_name(old_prefix), backend.quote_name(f.column), (qn(old_prefix), qn(f.column), qn(db_table), qn(f.rel.get_related_field().column)))
backend.quote_name(db_table), backend.quote_name(f.rel.get_related_field().column))) select.extend(['%s.%s' % (qn(db_table), qn(f2.column)) for f2 in f.rel.to._meta.fields])
select.extend(['%s.%s' % (backend.quote_name(db_table), backend.quote_name(f2.column)) for f2 in f.rel.to._meta.fields])
fill_table_cache(f.rel.to._meta, select, tables, where, db_table, cache_tables_seen) fill_table_cache(f.rel.to._meta, select, tables, where, db_table, cache_tables_seen)
def parse_lookup(kwarg_items, opts): def parse_lookup(kwarg_items, opts):
@ -719,39 +717,38 @@ def parse_lookup(kwarg_items, opts):
# At present, this method only every returns INNER JOINs; the option is # At present, this method only every returns INNER JOINs; the option is
# there for others to implement custom Q()s, etc that return other join # there for others to implement custom Q()s, etc that return other join
# types. # types.
tables, joins, where, params = [], SortedDict(), [], [] joins, where, params = SortedDict(), [], []
for kwarg, value in kwarg_items: for kwarg, value in kwarg_items:
if value is not None: if value is not None:
path = kwarg.split(LOOKUP_SEPARATOR) path = kwarg.split(LOOKUP_SEPARATOR)
# Extract the last elements of the kwarg. # Extract the last elements of the kwarg.
# The very-last is the clause (equals, like, etc). # The very-last is the lookup_type (equals, like, etc).
# The second-last is the table column on which the clause is # The second-last is the table column on which the lookup_type is
# to be performed. # to be performed.
# The exceptions to this are: # The exceptions to this are:
# 1) "pk", which is an implicit id__exact; # 1) "pk", which is an implicit id__exact;
# if we find "pk", make the clause "exact', and insert # if we find "pk", make the lookup_type "exact', and insert
# a dummy name of None, which we will replace when # a dummy name of None, which we will replace when
# we know which table column to grab as the primary key. # we know which table column to grab as the primary key.
# 2) If there is only one part, or the last part is not a query # 2) If there is only one part, or the last part is not a query
# term, assume that the query is an __exact # term, assume that the query is an __exact
clause = path.pop() lookup_type = path.pop()
if clause == 'pk': if lookup_type == 'pk':
clause = 'exact' lookup_type = 'exact'
path.append(None) path.append(None)
elif len(path) == 0 or clause not in QUERY_TERMS: elif len(path) == 0 or lookup_type not in QUERY_TERMS:
path.append(clause) path.append(lookup_type)
clause = 'exact' lookup_type = 'exact'
if len(path) < 1: if len(path) < 1:
raise TypeError, "Cannot parse keyword query %r" % kwarg raise TypeError, "Cannot parse keyword query %r" % kwarg
tables2, joins2, where2, params2 = lookup_inner(path, clause, value, opts, opts.db_table, None) joins2, where2, params2 = lookup_inner(path, lookup_type, value, opts, opts.db_table, None)
tables.extend(tables2)
joins.update(joins2) joins.update(joins2)
where.extend(where2) where.extend(where2)
params.extend(params2) params.extend(params2)
return tables, joins, where, params return joins, where, params
class FieldFound(Exception): class FieldFound(Exception):
"Exception used to short circuit field-finding operations." "Exception used to short circuit field-finding operations."
@ -770,8 +767,8 @@ def find_field(name, field_list, related_query):
return None return None
return matches[0] return matches[0]
def lookup_inner(path, clause, value, opts, table, column): def lookup_inner(path, lookup_type, value, opts, table, column):
tables, joins, where, params = [], SortedDict(), [], [] joins, where, params = SortedDict(), [], []
current_opts = opts current_opts = opts
current_table = table current_table = table
current_column = column current_column = column
@ -780,6 +777,7 @@ def lookup_inner(path, clause, value, opts, table, column):
info = current_opts.connection_info info = current_opts.connection_info
backend = info.backend backend = info.backend
connection = info.connection connection = info.connection
qn = backend.quote_name
name = path.pop(0) name = path.pop(0)
# Has the primary key been requested? If so, expand it out # Has the primary key been requested? If so, expand it out
@ -792,7 +790,7 @@ def lookup_inner(path, clause, value, opts, table, column):
# Does the name belong to a defined many-to-many field? # Does the name belong to a defined many-to-many field?
field = find_field(name, current_opts.many_to_many, False) field = find_field(name, current_opts.many_to_many, False)
if field: if field:
new_table = current_table + LOOKUP_SEPARATOR + name new_table = current_table + '__' + name
new_opts = field.rel.to._meta new_opts = field.rel.to._meta
new_column = new_opts.pk.column new_column = new_opts.pk.column
@ -809,7 +807,7 @@ def lookup_inner(path, clause, value, opts, table, column):
# Does the name belong to a reverse defined many-to-many field? # Does the name belong to a reverse defined many-to-many field?
field = find_field(name, current_opts.get_all_related_many_to_many_objects(), True) field = find_field(name, current_opts.get_all_related_many_to_many_objects(), True)
if field: if field:
new_table = current_table + LOOKUP_SEPARATOR + name new_table = current_table + '__' + name
new_opts = field.opts new_opts = field.opts
new_column = new_opts.pk.column new_column = new_opts.pk.column
@ -826,7 +824,7 @@ def lookup_inner(path, clause, value, opts, table, column):
# Does the name belong to a one-to-many field? # Does the name belong to a one-to-many field?
field = find_field(name, current_opts.get_all_related_objects(), True) field = find_field(name, current_opts.get_all_related_objects(), True)
if field: if field:
new_table = table + LOOKUP_SEPARATOR + name new_table = table + '__' + name
new_opts = field.opts new_opts = field.opts
new_column = field.field.column new_column = field.field.column
join_column = opts.pk.column join_column = opts.pk.column
@ -840,7 +838,7 @@ def lookup_inner(path, clause, value, opts, table, column):
field = find_field(name, current_opts.fields, False) field = find_field(name, current_opts.fields, False)
if field: if field:
if field.rel: # One-to-One/Many-to-one field if field.rel: # One-to-One/Many-to-one field
new_table = current_table + LOOKUP_SEPARATOR + name new_table = current_table + '__' + name
new_opts = field.rel.to._meta new_opts = field.rel.to._meta
new_column = new_opts.pk.column new_column = new_opts.pk.column
join_column = field.column join_column = field.column
@ -849,54 +847,41 @@ def lookup_inner(path, clause, value, opts, table, column):
except FieldFound: # Match found, loop has been shortcut. except FieldFound: # Match found, loop has been shortcut.
pass pass
except: # Any other exception; rethrow
raise
else: # No match found. else: # No match found.
raise TypeError, "Cannot resolve keyword '%s' into field" % name raise TypeError, "Cannot resolve keyword '%s' into field" % name
# Check to see if an intermediate join is required between current_table # Check whether an intermediate join is required between current_table
# and new_table. # and new_table.
if intermediate_table: if intermediate_table:
joins[backend.quote_name(current_table)] = ( joins[qn(current_table)] = (
backend.quote_name(intermediate_table), qn(intermediate_table), "LEFT OUTER JOIN",
"LEFT OUTER JOIN", "%s.%s = %s.%s" % (qn(table), qn(current_opts.pk.column), qn(current_table), qn(intermediate_column))
"%s.%s = %s.%s" % \
(backend.quote_name(table),
backend.quote_name(current_opts.pk.column),
backend.quote_name(current_table),
backend.quote_name(intermediate_column))
) )
if path: if path:
# There are elements left in the path. More joins are required. # There are elements left in the path. More joins are required.
if len(path) == 1 and path[0] in (new_opts.pk.name, None) \ if len(path) == 1 and path[0] in (new_opts.pk.name, None) \
and clause in ('exact', 'isnull') and not join_required: and lookup_type in ('exact', 'isnull') and not join_required:
# If the next and final name query is for a primary key, # If the next and final name query is for a primary key,
# and the search is for isnull/exact, then the current # and the search is for isnull/exact, then the current
# (for N-1) or intermediate (for N-N) table can be used # (for N-1) or intermediate (for N-N) table can be used
# for the search - no need to join an extra table just # for the search. No need to join an extra table just
# to check the primary key. # to check the primary key.
new_table = current_table new_table = current_table
else: else:
# There are 1 or more name queries pending, and we have ruled out # There are 1 or more name queries pending, and we have ruled out
# any shortcuts; therefore, a join is required. # any shortcuts; therefore, a join is required.
joins[backend.quote_name(new_table)] = ( joins[qn(new_table)] = (
backend.quote_name(new_opts.db_table), qn(new_opts.db_table), "INNER JOIN",
"INNER JOIN", "%s.%s = %s.%s" % (qn(current_table), qn(join_column), qn(new_table), qn(new_column))
"%s.%s = %s.%s" %
(backend.quote_name(current_table),
backend.quote_name(join_column),
backend.quote_name(new_table),
backend.quote_name(new_column))
) )
# If we have made the join, we don't need to tell subsequent # If we have made the join, we don't need to tell subsequent
# recursive calls about the column name we joined on. # recursive calls about the column name we joined on.
join_column = None join_column = None
# There are name queries remaining. Recurse deeper. # There are name queries remaining. Recurse deeper.
tables2, joins2, where2, params2 = lookup_inner(path, clause, value, new_opts, new_table, join_column) joins2, where2, params2 = lookup_inner(path, lookup_type, value, new_opts, new_table, join_column)
tables.extend(tables2)
joins.update(joins2) joins.update(joins2)
where.extend(where2) where.extend(where2)
params.extend(params2) params.extend(params2)
@ -910,14 +895,9 @@ def lookup_inner(path, clause, value, opts, table, column):
# RelatedObject is from a 1-N relation. # RelatedObject is from a 1-N relation.
# Join is required; query operates on joined table. # Join is required; query operates on joined table.
column = new_opts.pk.name column = new_opts.pk.name
joins[backend.quote_name(new_table)] = ( joins[qn(new_table)] = (
backend.quote_name(new_opts.db_table), qn(new_opts.db_table), "INNER JOIN",
"INNER JOIN", "%s.%s = %s.%s" % (qn(current_table), qn(join_column), qn(new_table), qn(new_column))
"%s.%s = %s.%s" %
(backend.quote_name(current_table),
backend.quote_name(join_column),
backend.quote_name(new_table),
backend.quote_name(new_column))
) )
current_table = new_table current_table = new_table
else: else:
@ -929,7 +909,7 @@ def lookup_inner(path, clause, value, opts, table, column):
# Last query term is a related object from an N-N relation. # Last query term is a related object from an N-N relation.
# Join from intermediate table is sufficient. # Join from intermediate table is sufficient.
column = join_column column = join_column
elif name == current_opts.pk.name and clause in ('exact', 'isnull') and current_column: elif name == current_opts.pk.name and lookup_type in ('exact', 'isnull') and current_column:
# Last query term is for a primary key. If previous iterations # Last query term is for a primary key. If previous iterations
# introduced a current/intermediate table that can be used to # introduced a current/intermediate table that can be used to
# optimize the query, then use that table and column name. # optimize the query, then use that table and column name.
@ -938,10 +918,10 @@ def lookup_inner(path, clause, value, opts, table, column):
# Last query term was a normal field. # Last query term was a normal field.
column = field.column column = field.column
where.append(get_where_clause(current_opts, clause, current_table + '.', column, value)) where.append(get_where_clause(current_opts, lookup_type, current_table + '.', column, value))
params.extend(field.get_db_prep_lookup(clause, value)) params.extend(field.get_db_prep_lookup(lookup_type, value))
return tables, joins, where, params return joins, where, params
def delete_objects(seen_objs): def delete_objects(seen_objs):
"Iterate through a list of seen classes, and remove any instances that are referred to" "Iterate through a list of seen classes, and remove any instances that are referred to"
@ -953,6 +933,7 @@ def delete_objects(seen_objs):
backend = info.backend backend = info.backend
connection = info.connection connection = info.connection
cursor = connection.cursor() cursor = connection.cursor()
qn = backend.quote_name
seen_objs[cls] = seen_objs[cls].items() seen_objs[cls] = seen_objs[cls].items()
seen_objs[cls].sort() seen_objs[cls].sort()
@ -965,24 +946,21 @@ def delete_objects(seen_objs):
for related in cls._meta.get_all_related_many_to_many_objects(): for related in cls._meta.get_all_related_many_to_many_objects():
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE): for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
cursor.execute("DELETE FROM %s WHERE %s IN (%s)" % \ cursor.execute("DELETE FROM %s WHERE %s IN (%s)" % \
(backend.quote_name(related.field.m2m_db_table()), (qn(related.field.m2m_db_table()),
backend.quote_name(related.field.m2m_reverse_name()), qn(related.field.m2m_reverse_name()),
','.join(['%s' for pk in pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]])), ','.join(['%s' for pk in pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]])),
pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]) pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE])
for f in cls._meta.many_to_many: for f in cls._meta.many_to_many:
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE): for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
cursor.execute("DELETE FROM %s WHERE %s IN (%s)" % \ cursor.execute("DELETE FROM %s WHERE %s IN (%s)" % \
(backend.quote_name(f.m2m_db_table()), (qn(f.m2m_db_table()), qn(f.m2m_column_name()),
backend.quote_name(f.m2m_column_name()), ','.join(['%s' for pk in pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]])),
','.join(['%s' for pk in pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]])),
pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]) pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE])
for field in cls._meta.fields: for field in cls._meta.fields:
if field.rel and field.null and field.rel.to in seen_objs: if field.rel and field.null and field.rel.to in seen_objs:
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE): for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
cursor.execute("UPDATE %s SET %s=NULL WHERE %s IN (%s)" % \ cursor.execute("UPDATE %s SET %s=NULL WHERE %s IN (%s)" % \
(backend.quote_name(cls._meta.db_table), (qn(cls._meta.db_table), qn(field.column), qn(cls._meta.pk.column),
backend.quote_name(field.column),
backend.quote_name(cls._meta.pk.column),
','.join(['%s' for pk in pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]])), ','.join(['%s' for pk in pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]])),
pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]) pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE])
@ -993,6 +971,7 @@ def delete_objects(seen_objs):
info = cls._meta.connection_info info = cls._meta.connection_info
backend = info.backend backend = info.backend
connection = info.connection connection = info.connection
qn = backend.quote_name
cursor = connection.cursor() cursor = connection.cursor()
if connection not in dirty_conns: if connection not in dirty_conns:
dirty_conns.append(connection) dirty_conns.append(connection)
@ -1001,9 +980,8 @@ def delete_objects(seen_objs):
pk_list = [pk for pk,instance in seen_objs[cls]] pk_list = [pk for pk,instance in seen_objs[cls]]
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE): for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
cursor.execute("DELETE FROM %s WHERE %s IN (%s)" % \ cursor.execute("DELETE FROM %s WHERE %s IN (%s)" % \
(backend.quote_name(cls._meta.db_table), (qn(cls._meta.db_table), qn(cls._meta.pk.column),
backend.quote_name(cls._meta.pk.column), ','.join(['%s' for pk in pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]])),
','.join(['%s' for pk in pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]])),
pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]) pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE])
# Last cleanup; set NULLs where there once was a reference to the object, # Last cleanup; set NULLs where there once was a reference to the object,

View File

@ -171,7 +171,7 @@ class Token(object):
self.contents[:20].replace('\n', '')) self.contents[:20].replace('\n', ''))
def split_contents(self): def split_contents(self):
return smart_split(self.contents) return list(smart_split(self.contents))
class Lexer(object): class Lexer(object):
def __init__(self, template_string, origin): def __init__(self, template_string, origin):
@ -758,7 +758,7 @@ class DebugVariableNode(VariableNode):
def generic_tag_compiler(params, defaults, name, node_class, parser, token): def generic_tag_compiler(params, defaults, name, node_class, parser, token):
"Returns a template.Node subclass." "Returns a template.Node subclass."
bits = token.contents.split()[1:] bits = token.split_contents()[1:]
bmax = len(params) bmax = len(params)
def_len = defaults and len(defaults) or 0 def_len = defaults and len(defaults) or 0
bmin = bmax - def_len bmin = bmax - def_len

View File

@ -133,7 +133,7 @@ def wordwrap(value, arg):
""" """
Wraps words at specified line length Wraps words at specified line length
Argument: number of words to wrap the text at. Argument: number of characters to wrap the text at.
""" """
from django.utils.text import wrap from django.utils.text import wrap
return wrap(str(value), int(arg)) return wrap(str(value), int(arg))

View File

@ -14,5 +14,14 @@ string_concat = lambda *strings: ''.join([str(el) for el in strings])
activate = lambda x: None activate = lambda x: None
deactivate = install = lambda: None deactivate = install = lambda: None
get_language = lambda: settings.LANGUAGE_CODE get_language = lambda: settings.LANGUAGE_CODE
get_date_formats = lambda: settings.DATE_FORMAT, settings.DATETIME_FORMAT, settings.TIME_FORMAT get_language_bidi = lambda: settings.LANGUAGE_CODE in settings.LANGUAGES_BIDI
get_partial_date_formats = lambda: settings.YEAR_MONTH_FORMAT, settings.MONTH_DAY_FORMAT get_date_formats = lambda: (settings.DATE_FORMAT, settings.DATETIME_FORMAT, settings.TIME_FORMAT)
get_partial_date_formats = lambda: (settings.YEAR_MONTH_FORMAT, settings.MONTH_DAY_FORMAT)
check_for_language = lambda x: True
def to_locale(language):
p = language.find('-')
if p >= 0:
return language[:p].lower()+'_'+language[p+1:].upper()
else:
return language.lower()

View File

@ -224,6 +224,13 @@ block::
This will have {{ myvar }} inside. This will have {{ myvar }} inside.
{% endblocktrans %} {% endblocktrans %}
If you need to bind more than one expression inside a ``blocktrans`` tag,
separate the pieces with ``and``::
{% blocktrans with book|title as book_t and author|title as author_t %}
This is {{ book_t }} by {{ author_t }}
{% endblocktrans %}
To pluralize, specify both the singular and plural forms with the To pluralize, specify both the singular and plural forms with the
``{% plural %}`` tag, which appears within ``{% blocktrans %}`` and ``{% plural %}`` tag, which appears within ``{% blocktrans %}`` and
``{% endblocktrans %}``. Example:: ``{% endblocktrans %}``. Example::
@ -306,7 +313,7 @@ marked for translation. It creates (or updates) a message file in the directory
``conf/locale``. In the ``de`` example, the file will be ``conf/locale``. In the ``de`` example, the file will be
``conf/locale/de/LC_MESSAGES/django.po``. ``conf/locale/de/LC_MESSAGES/django.po``.
If run over your project source tree or your appliation source tree, it will If run over your project source tree or your application source tree, it will
do the same, but the location of the locale directory is ``locale/LANG/LC_MESSAGES`` do the same, but the location of the locale directory is ``locale/LANG/LC_MESSAGES``
(note the missing ``conf`` prefix). (note the missing ``conf`` prefix).
@ -349,7 +356,7 @@ A quick explanation:
Long messages are a special case. There, the first string directly after the Long messages are a special case. There, the first string directly after the
``msgstr`` (or ``msgid``) is an empty string. Then the content itself will be ``msgstr`` (or ``msgid``) is an empty string. Then the content itself will be
written over the next few lines as one string per line. Those strings are written over the next few lines as one string per line. Those strings are
directlyconcatenated. Don't forget trailing spaces within the strings; directly concatenated. Don't forget trailing spaces within the strings;
otherwise, they'll be tacked together without whitespace! otherwise, they'll be tacked together without whitespace!
.. admonition:: Mind your charset .. admonition:: Mind your charset
@ -452,7 +459,7 @@ Notes:
``de``. ``de``.
* Only languages listed in the `LANGUAGES setting`_ can be selected. If * Only languages listed in the `LANGUAGES setting`_ can be selected. If
you want to restrict the language selection to a subset of provided you want to restrict the language selection to a subset of provided
languages (because your appliaction doesn't provide all those languages), languages (because your application doesn't provide all those languages),
set ``LANGUAGES`` to a list of languages. For example:: set ``LANGUAGES`` to a list of languages. For example::
LANGUAGES = ( LANGUAGES = (
@ -465,6 +472,30 @@ Notes:
en-us). en-us).
.. _LANGUAGES setting: http://www.djangoproject.com/documentation/settings/#languages .. _LANGUAGES setting: http://www.djangoproject.com/documentation/settings/#languages
* If you define a custom ``LANGUAGES`` setting, as explained in the
previous bullet, it's OK to mark the languages as translation strings
-- but use a "dummy" ``gettext()`` function, not the one in
``django.utils.translation``. You should *never* import
``django.utils.translation`` from within your settings file, because that
module in itself depends on the settings, and that would cause a circular
import.
The solution is to use a "dummy" ``gettext()`` function. Here's a sample
settings file::
gettext = lambda s: s
LANGUAGES = (
('de', gettext('German')),
('en', gettext('English')),
)
With this arrangement, ``make-messages.py`` will still find and mark
these strings for translation, but the translation won't happen at
runtime -- so you'll have to remember to wrap the languages in the *real*
``gettext()`` in any code that uses ``LANGUAGES`` at runtime.
* The ``LocaleMiddleware`` can only select languages for which there is a * The ``LocaleMiddleware`` can only select languages for which there is a
Django-provided base translation. If you want to provide translations Django-provided base translation. If you want to provide translations
for your application that aren't already in the set of translations for your application that aren't already in the set of translations
@ -623,7 +654,7 @@ The ``javascript_catalog`` view
------------------------------- -------------------------------
The main solution to these problems is the ``javascript_catalog`` view, which The main solution to these problems is the ``javascript_catalog`` view, which
sends out a JavaScript code library with functions that mimick the ``gettext`` sends out a JavaScript code library with functions that mimic the ``gettext``
interface, plus an array of translation strings. Those translation strings are interface, plus an array of translation strings. Those translation strings are
taken from the application, project or Django core, according to what you taken from the application, project or Django core, according to what you
specify in either the {{{info_dict}}} or the URL. specify in either the {{{info_dict}}} or the URL.
@ -641,7 +672,7 @@ You hook it up like this::
Each string in ``packages`` should be in Python dotted-package syntax (the Each string in ``packages`` should be in Python dotted-package syntax (the
same format as the strings in ``INSTALLED_APPS``) and should refer to a package same format as the strings in ``INSTALLED_APPS``) and should refer to a package
that contains a ``locale`` directory. If you specify multiple packages, all that contains a ``locale`` directory. If you specify multiple packages, all
those catalogs aremerged into one catalog. This is useful if you have those catalogs are merged into one catalog. This is useful if you have
JavaScript that uses strings from different applications. JavaScript that uses strings from different applications.
You can make the view dynamic by putting the packages into the URL pattern:: You can make the view dynamic by putting the packages into the URL pattern::

View File

@ -1225,6 +1225,33 @@ A few special cases to note about ``list_display``:
return self.birthday.strftime('%Y')[:3] + "0's" return self.birthday.strftime('%Y')[:3] + "0's"
decade_born_in.short_description = 'Birth decade' decade_born_in.short_description = 'Birth decade'
``list_display_links``
----------------------
Set ``list_display_links`` to control which fields in ``list_display`` should
be linked to the "change" page for an object.
By default, the change list page will link the first column -- the first field
specified in ``list_display`` -- to the change page for each item. But
``list_display_links`` lets you change which columns are linked. Set
``list_display_links`` to a list or tuple of field names (in the same format as
``list_display``) to link.
``list_display_links`` can specify one or many field names. As long as the
field names appear in ``list_display``, Django doesn't care how many (or how
few) fields are linked. The only requirement is: If you want to use
``list_display_links``, you must define ``list_display``.
In this example, the ``first_name`` and ``last_name`` fields will be linked on
the change list page::
class Admin:
list_display = ('first_name', 'last_name', 'birthday')
list_display_links = ('first_name', 'last_name')
Finally, note that in order to use ``list_display_links``, you must define
``list_display``, too.
``list_filter`` ``list_filter``
--------------- ---------------

View File

@ -501,6 +501,28 @@ specifies which languages are available for language selection. See the
Generally, the default value should suffice. Only set this setting if you want Generally, the default value should suffice. Only set this setting if you want
to restrict language selection to a subset of the Django-provided languages. to restrict language selection to a subset of the Django-provided languages.
If you define a custom ``LANGUAGES`` setting, it's OK to mark the languages as
translation strings (as in the default value displayed above) -- but use a
"dummy" ``gettext()`` function, not the one in ``django.utils.translation``.
You should *never* import ``django.utils.translation`` from within your
settings file, because that module in itself depends on the settings, and that
would cause a circular import.
The solution is to use a "dummy" ``gettext()`` function. Here's a sample
settings file::
gettext = lambda s: s
LANGUAGES = (
('de', gettext('German')),
('en', gettext('English')),
)
With this arrangement, ``make-messages.py`` will still find and mark these
strings for translation, but the translation won't happen at runtime -- so
you'll have to remember to wrap the languages in the *real* ``gettext()`` in
any code that uses ``LANGUAGES`` at runtime.
MANAGERS MANAGERS
-------- --------
@ -738,6 +760,13 @@ Note that this is the time zone to which Django will convert all dates/times --
not necessarily the timezone of the server. For example, one server may serve not necessarily the timezone of the server. For example, one server may serve
multiple Django-powered sites, each with a separate time-zone setting. multiple Django-powered sites, each with a separate time-zone setting.
Normally, Django sets the ``os.environ['TZ']`` variable to the time zone you
specify in the ``TIME_ZONE`` setting. Thus, all your views and models will
automatically operate in the correct time zone. However, if you're using the
manual configuration option (see below), Django will *not* touch the ``TZ``
environment variable, and it'll be up to you to ensure your processes are
running in the correct environment.
USE_ETAGS USE_ETAGS
--------- ---------
@ -815,6 +844,15 @@ uppercase, with the same name as the settings described above. If a particular
setting is not passed to ``configure()`` and is needed at some later point, setting is not passed to ``configure()`` and is needed at some later point,
Django will use the default setting value. Django will use the default setting value.
Configuring Django in this fashion is mostly necessary -- and, indeed,
recommended -- when you're using a piece of the framework inside a larger
application.
Consequently, when configured via ``settings.configure()``, Django will not
make any modifications to the process environment variables. (See the
explanation of ``TIME_ZONE``, above, for why this would normally occur.) It's
assumed that you're already in full control of your environment in these cases.
Custom default settings Custom default settings
----------------------- -----------------------

View File

@ -47,7 +47,7 @@ explained later in this document.::
JavaScript and CSV. You can use the template language for any text-based JavaScript and CSV. You can use the template language for any text-based
format. format.
Oh, and one more thing: Making humans edit XML is masochistic! Oh, and one more thing: Making humans edit XML is sadistic!
Variables Variables
========= =========

View File

@ -643,7 +643,7 @@ the current date/time, formatted according to a parameter given in the tag, in
`strftime syntax`_. It's a good idea to decide the tag syntax before anything `strftime syntax`_. It's a good idea to decide the tag syntax before anything
else. In our case, let's say the tag should be used like this:: else. In our case, let's say the tag should be used like this::
<p>The time is {% current_time "%Y-%M-%d %I:%M %p" %}.</p> <p>The time is {% current_time "%Y-%m-%d %I:%M %p" %}.</p>
.. _`strftime syntax`: http://www.python.org/doc/current/lib/module-time.html#l2h-1941 .. _`strftime syntax`: http://www.python.org/doc/current/lib/module-time.html#l2h-1941
@ -653,10 +653,10 @@ object::
from django import template from django import template
def do_current_time(parser, token): def do_current_time(parser, token):
try: try:
# Splitting by None == splitting by spaces. # split_contents() knows not to split quoted strings.
tag_name, format_string = token.contents.split(None, 1) tag_name, format_string = token.split_contents()
except ValueError: except ValueError:
raise template.TemplateSyntaxError, "%r tag requires an argument" % token.contents[0] raise template.TemplateSyntaxError, "%r tag requires a single argument" % token.contents[0]
if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")): if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
return CurrentTimeNode(format_string[1:-1]) return CurrentTimeNode(format_string[1:-1])
@ -667,7 +667,13 @@ Notes:
example. example.
* ``token.contents`` is a string of the raw contents of the tag. In our * ``token.contents`` is a string of the raw contents of the tag. In our
example, it's ``'current_time "%Y-%M-%d %I:%M %p"'``. example, it's ``'current_time "%Y-%m-%d %I:%M %p"'``.
* The ``token.split_contents()`` method separates the arguments on spaces
while keeping quoted strings together. The more straightforward
``token.contents.split()`` wouldn't be as robust, as it would naively
split on *all* spaces, including those within quoted strings. It's a good
idea to always use ``token.split_contents()``.
* This function is responsible for raising * This function is responsible for raising
``django.template.TemplateSyntaxError``, with helpful messages, for ``django.template.TemplateSyntaxError``, with helpful messages, for
@ -681,7 +687,7 @@ Notes:
* The function returns a ``CurrentTimeNode`` with everything the node needs * The function returns a ``CurrentTimeNode`` with everything the node needs
to know about this tag. In this case, it just passes the argument -- to know about this tag. In this case, it just passes the argument --
``"%Y-%M-%d %I:%M %p"``. The leading and trailing quotes from the ``"%Y-%m-%d %I:%M %p"``. The leading and trailing quotes from the
template tag are removed in ``format_string[1:-1]``. template tag are removed in ``format_string[1:-1]``.
* The parsing is very low-level. The Django developers have experimented * The parsing is very low-level. The Django developers have experimented
@ -766,27 +772,24 @@ registers it with the template system.
Our earlier ``current_time`` function could thus be written like this:: Our earlier ``current_time`` function could thus be written like this::
# This version of do_current_time takes only a single argument and returns def current_time(format_string):
# a string. return datetime.datetime.now().strftime(format_string)
def do_current_time(token): register.simple_tag(current_time)
try:
# Splitting by None == splitting by spaces.
tag_name, format_string = token.contents.split(None, 1)
except ValueError:
raise template.TemplateSyntaxError, "%r tag requires an argument" % token.contents[0]
if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
return datetime.datetime.now().strftime(self.format_string[1:-1])
register.simple_tag(do_current_time)
In Python 2.4, the decorator syntax also works:: In Python 2.4, the decorator syntax also works::
@register.simple_tag @register.simple_tag
def do_current_time(token): def current_time(token):
... ...
A couple of things to note about the ``simple_tag`` helper function:
* Only the (single) argument is passed into our function.
* Checking for the required number of arguments, etc, has already been
done by the time our function is called, so we don't need to do that.
* The quotes around the argument (if any) have already been stripped away,
so we just receive a plain string.
Inclusion tags Inclusion tags
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~

View File

@ -14,7 +14,8 @@ setup(
packages = find_packages(exclude=['examples', 'examples.*']), packages = find_packages(exclude=['examples', 'examples.*']),
package_data = { package_data = {
'': ['*.TXT'], '': ['*.TXT'],
'django.conf': ['locale/bn/LC_MESSAGES/*', 'django.conf': ['locale/ar/LC_MESSAGES/*',
'locale/bn/LC_MESSAGES/*',
'locale/cs/LC_MESSAGES/*', 'locale/cs/LC_MESSAGES/*',
'locale/cy/LC_MESSAGES/*', 'locale/cy/LC_MESSAGES/*',
'locale/da/LC_MESSAGES/*', 'locale/da/LC_MESSAGES/*',

View File

@ -28,24 +28,23 @@ API_TESTS = """
>>> r.save() >>> r.save()
>>> g = User(username='gustav') >>> g = User(username='gustav')
>>> g.save() >>> g.save()
>>> i = Issue(num=1) >>> i = Issue(num=1)
>>> i.client = r >>> i.client = r
>>> i.validate()
{}
>>> i.save() >>> i.save()
>>> i2 = Issue(num=2) >>> i2 = Issue(num=2)
>>> i2.client = r >>> i2.client = r
>>> i2.validate()
{}
>>> i2.save() >>> i2.save()
>>> i2.cc.add(r) >>> i2.cc.add(r)
>>> i3 = Issue(num=3) >>> i3 = Issue(num=3)
>>> i3.client = g >>> i3.client = g
>>> i3.validate()
{}
>>> i3.save() >>> i3.save()
>>> i3.cc.add(r) >>> i3.cc.add(r)
>>> from django.db.models.query import Q >>> from django.db.models.query import Q
>>> Issue.objects.filter(client=r.id) >>> Issue.objects.filter(client=r.id)
[<Issue: 1>, <Issue: 2>] [<Issue: 1>, <Issue: 2>]
>>> Issue.objects.filter(client=g.id) >>> Issue.objects.filter(client=g.id)
@ -55,8 +54,8 @@ API_TESTS = """
>>> Issue.objects.filter(cc__id__exact=r.id) >>> Issue.objects.filter(cc__id__exact=r.id)
[<Issue: 2>, <Issue: 3>] [<Issue: 2>, <Issue: 3>]
# Queries that combine results from the m2m and the m2o relationship. # These queries combine results from the m2m and the m2o relationships.
# 3 ways of saying the same thing: # They're three ways of saying the same thing.
>>> Issue.objects.filter(Q(cc__id__exact=r.id) | Q(client=r.id)) >>> Issue.objects.filter(Q(cc__id__exact=r.id) | Q(client=r.id))
[<Issue: 1>, <Issue: 2>, <Issue: 3>] [<Issue: 1>, <Issue: 2>, <Issue: 3>]
>>> Issue.objects.filter(cc__id__exact=r.id) | Issue.objects.filter(client=r.id) >>> Issue.objects.filter(cc__id__exact=r.id) | Issue.objects.filter(client=r.id)

View File

@ -1,5 +1,9 @@
from django.conf import settings from django.conf import settings
if __name__ == '__main__':
# When running this file in isolation, we need to set up the configuration
# before importing 'template'.
settings.configure()
from django import template from django import template
from django.template import loader from django.template import loader
@ -538,10 +542,10 @@ TEMPLATE_TESTS = {
### TIMESINCE TAG ################################################## ### TIMESINCE TAG ##################################################
# Default compare with datetime.now() # Default compare with datetime.now()
'timesince01' : ('{{ a|timesince }}', {'a':datetime.now() + timedelta(minutes=-1)}, '1 minute'), 'timesince01' : ('{{ a|timesince }}', {'a':datetime.now() + timedelta(minutes=-1, seconds = -10)}, '1 minute'),
'timesince02' : ('{{ a|timesince }}', {'a':(datetime.now() - timedelta(days=1))}, '1 day'), 'timesince02' : ('{{ a|timesince }}', {'a':(datetime.now() - timedelta(days=1, minutes = 1))}, '1 day'),
'timesince03' : ('{{ a|timesince }}', {'a':(datetime.now() - 'timesince03' : ('{{ a|timesince }}', {'a':(datetime.now() -
timedelta(hours=1, minutes=25))}, '1 hour, 25 minutes'), timedelta(hours=1, minutes=25, seconds = 10))}, '1 hour, 25 minutes'),
# Compare to a given parameter # Compare to a given parameter
'timesince04' : ('{{ a|timesince:b }}', {'a':NOW + timedelta(days=2), 'b':NOW + timedelta(days=1)}, '1 day'), 'timesince04' : ('{{ a|timesince:b }}', {'a':NOW + timedelta(days=2), 'b':NOW + timedelta(days=1)}, '1 day'),
@ -552,9 +556,9 @@ TEMPLATE_TESTS = {
### TIMEUNTIL TAG ################################################## ### TIMEUNTIL TAG ##################################################
# Default compare with datetime.now() # Default compare with datetime.now()
'timeuntil01' : ('{{ a|timeuntil }}', {'a':datetime.now() + timedelta(minutes=2)}, '2 minutes'), 'timeuntil01' : ('{{ a|timeuntil }}', {'a':datetime.now() + timedelta(minutes=2, seconds = 10)}, '2 minutes'),
'timeuntil02' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(days=1))}, '1 day'), 'timeuntil02' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(days=1, seconds = 10))}, '1 day'),
'timeuntil03' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(hours=8, minutes=10))}, '8 hours, 10 minutes'), 'timeuntil03' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(hours=8, minutes=10, seconds = 10))}, '8 hours, 10 minutes'),
# Compare to a given parameter # Compare to a given parameter
'timeuntil04' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=1), 'b':NOW - timedelta(days=2)}, '1 day'), 'timeuntil04' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=1), 'b':NOW - timedelta(days=2)}, '1 day'),
@ -621,5 +625,4 @@ def run_tests(verbosity=0, standalone=False):
raise Exception, msg raise Exception, msg
if __name__ == "__main__": if __name__ == "__main__":
settings.configure()
run_tests(1, True) run_tests(1, True)

View File

@ -154,8 +154,9 @@ class TestRunner:
# Manually set INSTALLED_APPS to point to the test models. # Manually set INSTALLED_APPS to point to the test models.
settings.INSTALLED_APPS = ALWAYS_INSTALLED_APPS + ['.'.join(a) for a in get_test_models()] settings.INSTALLED_APPS = ALWAYS_INSTALLED_APPS + ['.'.join(a) for a in get_test_models()]
# Manually set DEBUG = False. # Manually set DEBUG and USE_I18N.
settings.DEBUG = False settings.DEBUG = False
settings.USE_I18N = True
self.output(0, "Running tests with database %r" % settings.DATABASE_ENGINE) self.output(0, "Running tests with database %r" % settings.DATABASE_ENGINE)