diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index 7f2445f116..d08d903f3f 100644 --- a/django/conf/global_settings.py +++ b/django/conf/global_settings.py @@ -100,6 +100,15 @@ TEMPLATE_LOADERS = ( # 'django.core.template.loaders.eggs.load_template_source', ) +# List of processors used by DjangoContext to populate the context. +# Each one should be a callable that takes the request object as its +# only parameter and returns a dictionary to add to the context. +TEMPLATE_CONTEXT_PROCESSORS = ( + 'django.core.context_processors.auth', + 'django.core.context_processors.debug', + 'django.core.context_processors.i18n', +) + # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a # trailing slash. # Examples: "http://foo.com/media/", "/media/". diff --git a/django/conf/locale/cs/LC_MESSAGES/djangojs.mo b/django/conf/locale/cs/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000000..e5c6a134e0 Binary files /dev/null and b/django/conf/locale/cs/LC_MESSAGES/djangojs.mo differ diff --git a/django/conf/locale/cs/LC_MESSAGES/djangojs.po b/django/conf/locale/cs/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000000..7206e3321d --- /dev/null +++ b/django/conf/locale/cs/LC_MESSAGES/djangojs.po @@ -0,0 +1,112 @@ +# Translation of djangojs.po to Czech +# Copyright (C) 2005 THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the DJANGO package. +# Radek Svarz , 2005. +# +msgid "" +msgstr "" +"Project-Id-Version: Django JavaScript Czech translation\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2005-12-17 22:26+0100\n" +"PO-Revision-Date: 2005-12-21 14:03+0100\n" +"Last-Translator: Radek Švarz \n" +"Language-Team: Czech\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Poedit-Language: Czech\n" +"X-Poedit-Country: CZECH REPUBLIC\n" + +#: contrib/admin/media/js/SelectFilter2.js:33 +#, perl-format +msgid "Available %s" +msgstr "K dispozici %s" + +#: contrib/admin/media/js/SelectFilter2.js:41 +msgid "Choose all" +msgstr "Vybrat vše" + +#: contrib/admin/media/js/SelectFilter2.js:46 +msgid "Add" +msgstr "Přidat" + +#: contrib/admin/media/js/SelectFilter2.js:48 +msgid "Remove" +msgstr "Odebrat" + +#: contrib/admin/media/js/SelectFilter2.js:53 +#, perl-format +msgid "Chosen %s" +msgstr "Vybraný %s" + +#: contrib/admin/media/js/SelectFilter2.js:54 +msgid "Select your choice(s) and click " +msgstr "Vyberte si a klikněte" + +#: contrib/admin/media/js/SelectFilter2.js:59 +msgid "Clear all" +msgstr "Vše vymazat" + +#: 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 "Leden Únor Březen Duben Květen Červen Červenec Srpen Září Říjen Listopad Prosinec" + +#: contrib/admin/media/js/dateparse.js:27 +#, fuzzy +msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday" +msgstr "Neděle Pondělí Úterý Středa Čtvrtek Pátek Sobota Neděle" + +#: contrib/admin/media/js/calendar.js:25 +#, fuzzy +msgid "S M T W T F S" +msgstr "N P U S C P S" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45 +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80 +msgid "Now" +msgstr "Nyní" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48 +msgid "Clock" +msgstr "Hodiny" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77 +msgid "Choose a time" +msgstr "Vyberte čas" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81 +msgid "Midnight" +msgstr "Půlnoc" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82 +msgid "6 a.m." +msgstr "6 ráno" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83 +msgid "Noon" +msgstr "Poledne" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87 +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168 +msgid "Cancel" +msgstr "Storno" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111 +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162 +msgid "Today" +msgstr "Dnes" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114 +msgid "Calendar" +msgstr "Kalendář" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160 +msgid "Yesterday" +msgstr "Včera" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164 +msgid "Tomorrow" +msgstr "Zítra" + diff --git a/django/core/context_processors.py b/django/core/context_processors.py new file mode 100644 index 0000000000..30af6bc1f3 --- /dev/null +++ b/django/core/context_processors.py @@ -0,0 +1,58 @@ +""" +A set of request processors that return dictionaries to be merged into a +template context. Each function takes the request object as its only parameter +and returns a dictionary to add to the context. + +These are referenced from the setting TEMPLATE_CONTEXT_PROCESSORS and used by +DjangoContext. +""" + +from django.conf.settings import DEBUG, INTERNAL_IPS, LANGUAGES, LANGUAGE_CODE + +def auth(request): + """ + Returns context variables required by apps that use Django's authentication + system. + """ + return { + 'user': request.user, + 'messages': request.user.get_and_delete_messages(), + 'perms': PermWrapper(request.user), + } + +def debug(request): + "Returns context variables helpful for debugging." + context_extras = {} + if DEBUG and request.META.get('REMOTE_ADDR') in INTERNAL_IPS: + context_extras['debug'] = True + from django.db import connection + context_extras['sql_queries'] = connection.queries + return context_extras + +def i18n(request): + context_extras = {} + context_extras['LANGUAGES'] = LANGUAGES + if hasattr(request, 'LANGUAGE_CODE'): + context_extras['LANGUAGE_CODE'] = request.LANGUAGE_CODE + else: + context_extras['LANGUAGE_CODE'] = LANGUAGE_CODE + return context_extras + +# PermWrapper and PermLookupDict proxy the permissions system into objects that +# the template system can understand. + +class PermLookupDict: + def __init__(self, user, module_name): + self.user, self.module_name = user, module_name + def __repr__(self): + return str(self.user.get_permission_list()) + def __getitem__(self, perm_name): + return self.user.has_perm("%s.%s" % (self.module_name, perm_name)) + def __nonzero__(self): + return self.user.has_module_perms(self.module_name) + +class PermWrapper: + def __init__(self, user): + self.user = user + def __getitem__(self, module_name): + return PermLookupDict(self.user, module_name) diff --git a/django/core/extensions.py b/django/core/extensions.py index e00ecd4159..9fef65fd58 100644 --- a/django/core/extensions.py +++ b/django/core/extensions.py @@ -2,11 +2,34 @@ # of MVC. In other words, these functions/classes introduce controlled coupling # for convenience's sake. -from django.core.exceptions import Http404 +from django.core.exceptions import Http404, ImproperlyConfigured from django.core.template import Context, loader -from django.conf.settings import DEBUG, INTERNAL_IPS +from django.conf.settings import TEMPLATE_CONTEXT_PROCESSORS from django.utils.httpwrappers import HttpResponse +_standard_context_processors = None + +# This is a function rather than module-level procedural code because we only +# want it to execute if somebody uses DjangoContext. +def get_standard_processors(): + global _standard_context_processors + if _standard_context_processors is None: + processors = [] + for path in TEMPLATE_CONTEXT_PROCESSORS: + i = path.rfind('.') + module, attr = path[:i], path[i+1:] + try: + mod = __import__(module, '', '', [attr]) + except ImportError, e: + raise ImproperlyConfigured, 'Error importing request processor module %s: "%s"' % (module, e) + try: + func = getattr(mod, attr) + except AttributeError: + raise ImproperlyConfigured, 'Module "%s" does not define a "%s" callable request processor' % (module, attr) + processors.append(func) + _standard_context_processors = tuple(processors) + return _standard_context_processors + def render_to_response(*args, **kwargs): return HttpResponse(loader.render_to_string(*args, **kwargs)) load_and_render = render_to_response # For backwards compatibility. @@ -25,24 +48,19 @@ def get_list_or_404(klass, **kwargs): class DjangoContext(Context): """ - This subclass of template.Context automatically populates 'user' and - 'messages' in the context. + This subclass of template.Context automatically populates itself using + the processors defined in TEMPLATE_CONTEXT_PROCESSORS. + Additional processors can be specified as a list of callables + using the "processors" keyword argument. """ - def __init__(self, request, dict=None): + def __init__(self, request, dict=None, processors=None): Context.__init__(self, dict) - self['user'] = request.user - self['messages'] = request.user.get_and_delete_messages() - self['perms'] = PermWrapper(request.user) - from django.conf import settings - self['LANGUAGES'] = settings.LANGUAGES - if hasattr(request, 'LANGUAGE_CODE'): - self['LANGUAGE_CODE'] = request.LANGUAGE_CODE + if processors is None: + processors = () else: - self['LANGUAGE_CODE'] = settings.LANGUAGE_CODE - if DEBUG and request.META.get('REMOTE_ADDR') in INTERNAL_IPS: - self['debug'] = True - from django.db import connection - self['sql_queries'] = connection.queries + processors = tuple(processors) + for processor in get_standard_processors() + processors: + self.update(processor(request)) # PermWrapper and PermLookupDict proxy the permissions system into objects that # the template system can understand. diff --git a/django/views/generic/create_update.py b/django/views/generic/create_update.py index da15bd1a43..7ddde87650 100644 --- a/django/views/generic/create_update.py +++ b/django/views/generic/create_update.py @@ -3,14 +3,14 @@ from django.core.xheaders import populate_xheaders from django.core.template import loader from django.core import formfields, meta from django.views.auth.login import redirect_to_login -from django.core.extensions import DjangoContext as Context +from django.core.extensions import DjangoContext from django.core.paginator import ObjectPaginator, InvalidPage from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect from django.core.exceptions import Http404, ObjectDoesNotExist, ImproperlyConfigured def create_object(request, app_label, module_name, template_name=None, - template_loader=loader, extra_context={}, - post_save_redirect=None, login_required=False, follow=None): + template_loader=loader, extra_context={}, post_save_redirect=None, + login_required=False, follow=None, context_processors=None): """ Generic object-creation function. @@ -60,9 +60,9 @@ def create_object(request, app_label, module_name, template_name=None, if not template_name: template_name = "%s/%s_form" % (app_label, module_name) t = template_loader.get_template(template_name) - c = Context(request, { - 'form' : form, - }) + c = DjangoContext(request, { + 'form': form, + }, context_processors) for key, value in extra_context.items(): if callable(value): c[key] = value() @@ -71,9 +71,9 @@ def create_object(request, app_label, module_name, template_name=None, return HttpResponse(t.render(c)) def update_object(request, app_label, module_name, object_id=None, slug=None, - slug_field=None, template_name=None, template_loader=loader, - extra_lookup_kwargs={}, extra_context={}, post_save_redirect=None, - login_required=False, follow=None): + slug_field=None, template_name=None, template_loader=loader, + extra_lookup_kwargs={}, extra_context={}, post_save_redirect=None, + login_required=False, follow=None, context_processors=None): """ Generic object-update function. @@ -131,10 +131,10 @@ def update_object(request, app_label, module_name, object_id=None, slug=None, if not template_name: template_name = "%s/%s_form" % (app_label, module_name) t = template_loader.get_template(template_name) - c = Context(request, { - 'form' : form, - 'object' : object, - }) + c = DjangoContext(request, { + 'form': form, + 'object': object, + }, context_processors) for key, value in extra_context.items(): if callable(value): c[key] = value() @@ -145,9 +145,9 @@ def update_object(request, app_label, module_name, object_id=None, slug=None, return response def delete_object(request, app_label, module_name, post_delete_redirect, - object_id=None, slug=None, slug_field=None, template_name=None, - template_loader=loader, extra_lookup_kwargs={}, - extra_context={}, login_required=False): + object_id=None, slug=None, slug_field=None, template_name=None, + template_loader=loader, extra_lookup_kwargs={}, extra_context={}, + login_required=False, context_processors=None): """ Generic object-delete function. @@ -188,9 +188,9 @@ def delete_object(request, app_label, module_name, post_delete_redirect, if not template_name: template_name = "%s/%s_confirm_delete" % (app_label, module_name) t = template_loader.get_template(template_name) - c = Context(request, { - 'object' : object, - }) + c = DjangoContext(request, { + 'object': object, + }, context_processors) for key, value in extra_context.items(): if callable(value): c[key] = value() @@ -199,4 +199,3 @@ def delete_object(request, app_label, module_name, post_delete_redirect, response = HttpResponse(t.render(c)) populate_xheaders(request, response, app_label, module_name, getattr(object, object._meta.pk.name)) return response - diff --git a/django/views/generic/date_based.py b/django/views/generic/date_based.py index eb7386daf3..1b9e8e9587 100644 --- a/django/views/generic/date_based.py +++ b/django/views/generic/date_based.py @@ -1,14 +1,14 @@ from django.core.template import loader from django.core.exceptions import Http404, ObjectDoesNotExist -from django.core.extensions import DjangoContext as Context +from django.core.extensions import DjangoContext from django.core.xheaders import populate_xheaders from django.models import get_module from django.utils.httpwrappers import HttpResponse import datetime, time def archive_index(request, app_label, module_name, date_field, num_latest=15, - template_name=None, template_loader=loader, - extra_lookup_kwargs={}, extra_context={}, allow_empty=False): + template_name=None, template_loader=loader, extra_lookup_kwargs={}, + extra_context={}, allow_empty=False, context_processors=None): """ Generic top-level archive of date-based objects. @@ -38,10 +38,10 @@ def archive_index(request, app_label, module_name, date_field, num_latest=15, if not template_name: template_name = "%s/%s_archive" % (app_label, module_name) t = template_loader.get_template(template_name) - c = Context(request, { + c = DjangoContext(request, { 'date_list' : date_list, 'latest' : latest, - }) + }, context_processors) for key, value in extra_context.items(): if callable(value): c[key] = value() @@ -50,8 +50,8 @@ def archive_index(request, app_label, module_name, date_field, num_latest=15, return HttpResponse(t.render(c)) def archive_year(request, year, app_label, module_name, date_field, - template_name=None, template_loader=loader, - extra_lookup_kwargs={}, extra_context={}): + template_name=None, template_loader=loader, extra_lookup_kwargs={}, + extra_context={}, context_processors=None): """ Generic yearly archive view. @@ -75,10 +75,10 @@ def archive_year(request, year, app_label, module_name, date_field, if not template_name: template_name = "%s/%s_archive_year" % (app_label, module_name) t = template_loader.get_template(template_name) - c = Context(request, { + c = DjangoContext(request, { 'date_list': date_list, 'year': year, - }) + }, context_processors) for key, value in extra_context.items(): if callable(value): c[key] = value() @@ -87,8 +87,8 @@ def archive_year(request, year, app_label, module_name, date_field, return HttpResponse(t.render(c)) def archive_month(request, year, month, app_label, module_name, date_field, - month_format='%b', template_name=None, template_loader=loader, - extra_lookup_kwargs={}, extra_context={}): + month_format='%b', template_name=None, template_loader=loader, + extra_lookup_kwargs={}, extra_context={}, context_processors=None): """ Generic monthly archive view. @@ -123,10 +123,10 @@ def archive_month(request, year, month, app_label, module_name, date_field, if not template_name: template_name = "%s/%s_archive_month" % (app_label, module_name) t = template_loader.get_template(template_name) - c = Context(request, { + c = DjangoContext(request, { 'object_list': object_list, 'month': date, - }) + }, context_processors) for key, value in extra_context.items(): if callable(value): c[key] = value() @@ -135,9 +135,9 @@ def archive_month(request, year, month, app_label, module_name, date_field, return HttpResponse(t.render(c)) def archive_day(request, year, month, day, app_label, module_name, date_field, - month_format='%b', day_format='%d', template_name=None, - template_loader=loader, extra_lookup_kwargs={}, - extra_context={}, allow_empty=False): + month_format='%b', day_format='%d', template_name=None, + template_loader=loader, extra_lookup_kwargs={}, extra_context={}, + allow_empty=False, context_processors=None): """ Generic daily archive view. @@ -172,12 +172,12 @@ def archive_day(request, year, month, day, app_label, module_name, date_field, if not template_name: template_name = "%s/%s_archive_day" % (app_label, module_name) t = template_loader.get_template(template_name) - c = Context(request, { + c = DjangoContext(request, { 'object_list': object_list, 'day': date, 'previous_day': date - datetime.timedelta(days=1), 'next_day': (date < datetime.date.today()) and (date + datetime.timedelta(days=1)) or None, - }) + }, context_processors) for key, value in extra_context.items(): if callable(value): c[key] = value() @@ -198,10 +198,10 @@ def archive_today(request, **kwargs): return archive_day(request, **kwargs) def object_detail(request, year, month, day, app_label, module_name, date_field, - month_format='%b', day_format='%d', object_id=None, slug=None, - slug_field=None, template_name=None, template_name_field=None, - template_loader=loader, extra_lookup_kwargs={}, - extra_context={}): + month_format='%b', day_format='%d', object_id=None, slug=None, + slug_field=None, template_name=None, template_name_field=None, + template_loader=loader, extra_lookup_kwargs={}, extra_context={}, + context_processors=None): """ Generic detail view from year/month/day/slug or year/month/day/id structure. @@ -241,9 +241,9 @@ def object_detail(request, year, month, day, app_label, module_name, date_field, t = template_loader.select_template(template_name_list) else: t = template_loader.get_template(template_name) - c = Context(request, { + c = DjangoContext(request, { 'object': object, - }) + }, context_processors) for key, value in extra_context.items(): if callable(value): c[key] = value() diff --git a/django/views/generic/list_detail.py b/django/views/generic/list_detail.py index c4c3e85945..d81d46f52b 100644 --- a/django/views/generic/list_detail.py +++ b/django/views/generic/list_detail.py @@ -2,13 +2,13 @@ from django import models from django.core.template import loader from django.utils.httpwrappers import HttpResponse from django.core.xheaders import populate_xheaders -from django.core.extensions import DjangoContext as Context +from django.core.extensions import DjangoContext from django.core.paginator import ObjectPaginator, InvalidPage from django.core.exceptions import Http404, ObjectDoesNotExist def object_list(request, app_label, module_name, paginate_by=None, allow_empty=False, - template_name=None, template_loader=loader, - extra_lookup_kwargs={}, extra_context={}): + template_name=None, template_loader=loader, extra_lookup_kwargs={}, + extra_context={}, context_processors=None): """ Generic list of objects. @@ -48,7 +48,7 @@ def object_list(request, app_label, module_name, paginate_by=None, allow_empty=F else: raise Http404 page = int(page) - c = Context(request, { + c = DjangoContext(request, { 'object_list': object_list, 'is_paginated': paginator.pages > 1, 'results_per_page': paginate_by, @@ -59,13 +59,13 @@ def object_list(request, app_label, module_name, paginate_by=None, allow_empty=F 'previous': page - 1, 'pages': paginator.pages, 'hits' : paginator.hits, - }) + }, context_processors) else: object_list = mod.get_list(**lookup_kwargs) - c = Context(request, { + c = DjangoContext(request, { 'object_list': object_list, 'is_paginated': False - }) + }, context_processors) if len(object_list) == 0 and not allow_empty: raise Http404 for key, value in extra_context.items(): @@ -79,9 +79,9 @@ def object_list(request, app_label, module_name, paginate_by=None, allow_empty=F return HttpResponse(t.render(c)) def object_detail(request, app_label, module_name, object_id=None, slug=None, - slug_field=None, template_name=None, template_name_field=None, - template_loader=loader, extra_lookup_kwargs={}, - extra_context={}): + slug_field=None, template_name=None, template_name_field=None, + template_loader=loader, extra_lookup_kwargs={}, extra_context={}, + context_processors=None): """ Generic list of objects. @@ -110,9 +110,9 @@ def object_detail(request, app_label, module_name, object_id=None, slug=None, t = template_loader.select_template(template_name_list) else: t = template_loader.get_template(template_name) - c = Context(request, { + c = DjangoContext(request, { 'object': object, - }) + }, context_processors) for key, value in extra_context.items(): if callable(value): c[key] = value() diff --git a/docs/authentication.txt b/docs/authentication.txt index c5d9ceda7e..634366096a 100644 --- a/docs/authentication.txt +++ b/docs/authentication.txt @@ -438,6 +438,15 @@ Authentication data in templates The currently logged-in user and his/her permissions are made available in the `template context`_ when you use ``DjangoContext``. +.. admonition:: Technicality + + Technically, these variables are only made available in the template context + if you use ``DjangoContext`` *and* your ``TEMPLATE_CONTEXT_PROCESSORS`` + setting contains ``"django.core.context_processors.auth"``, which is default. + For more, see the `DjangoContext docs`_. + + .. _DjangoContext docs: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-djangocontext + Users ----- @@ -454,7 +463,7 @@ Permissions ----------- The currently logged-in user's permissions are stored in the template variable -``{{ perms }}``. This is an instance of ``django.core.extensions.PermWrapper``, +``{{ perms }}``. This is an instance of ``django.core.context_processors.PermWrapper``, which is a template-friendly proxy of permissions. In the ``{{ perms }}`` object, single-attribute lookup is a proxy to diff --git a/docs/contributing.txt b/docs/contributing.txt index 1470b7a1f6..42592fb336 100644 --- a/docs/contributing.txt +++ b/docs/contributing.txt @@ -120,6 +120,24 @@ Patch style it obvious that the ticket includes a patch, and it will add the ticket to the `list of tickets with patches`_. +Submitting and maintaining translations +======================================= + +Various parts of Django, such as the admin site and validator error messages, +are internationalized. This means they display different text depending on a +user's language setting. + +These translations are contributed by Django users worldwide. If you find an +incorrect translation, or if you'd like to add a language that isn't yet +translated, here's what to do: + + * Join the `Django i18n mailing list`_ and introduce yourself. + * Create and submit translations using the methods described in the + `i18n documentation`_. + +.. _Django i18n mailing list: http://groups.google.com/group/django-i18n/ +.. _i18n documentation: http://www.djangoproject.com/documentation/i18n/ + Coding style ============ @@ -205,15 +223,22 @@ trunk more than once. Using branches -------------- -To test a given branch, you can simply check out the entire branch. Or, if -you've got a working directory you'd like to switch to use a branch, you can -use:: +To test a given branch, you can simply check out the entire branch, like so:: + + svn co http://code.djangoproject.com/svn/django/branches// + +Or, if you've got a working directory you'd like to switch to use a branch, +you can use:: svn switch http://code.djangoproject.com/svn/django/branches// ...in the root of your Django sandbox (the directory that contains ``django``, ``docs``, and ``tests``). +The advantage of using ``svn switch`` instead of ``svn co`` is that the +``switch`` command retains any changes you might have made to your local copy +of the code. It attempts to merge those changes into the "switched" code. + Official releases ================= diff --git a/docs/db-api.txt b/docs/db-api.txt index 3cee4d6c6e..a83b7dad6a 100644 --- a/docs/db-api.txt +++ b/docs/db-api.txt @@ -243,7 +243,7 @@ The ``|`` symbol signifies an "OR", so this (roughly) translates into:: You can use ``&`` and ``|`` operators together, and use parenthetical grouping. Example:: - polls.get_object(complex=(Q(question__startswith='Who') & (Q(pub_date__exact=date(2005, 5, 2)) | pub_date__exact=date(2005, 5, 6))) + polls.get_object(complex=(Q(question__startswith='Who') & (Q(pub_date__exact=date(2005, 5, 2)) | Q(pub_date__exact=date(2005, 5, 6)))) This roughly translates into:: diff --git a/docs/generic_views.txt b/docs/generic_views.txt index d196d2cf96..cfca09d5b1 100644 --- a/docs/generic_views.txt +++ b/docs/generic_views.txt @@ -128,9 +128,14 @@ arguments: ``extra_context`` A dictionary of extra data to put into the template's context. + + ``processors`` **New in Django development version.** A tuple of + processors to apply to the ``DjangoContext`` of + this view's template. See the `DjangoContext docs`_ ======================= ================================================== -.. _`database API docs`: http://www.djangoproject.com/documentation/db_api/ +.. _database API docs: http://www.djangoproject.com/documentation/db_api/ +.. _DjangoContext docs: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-djangocontext The date-based generic functions are: @@ -247,7 +252,7 @@ The list-detail generic-view framework (in the except the former simply has two views: a list of objects and an individual object page. -All these views take the same three optional arguments as the date-based ones +All these views take the same four optional arguments as the date-based ones -- and, clearly, they don't accept the ``date_field`` argument. Individual views are: @@ -371,4 +376,3 @@ The create/update/delete views are: object The object about to be deleted - diff --git a/docs/i18n.txt b/docs/i18n.txt index acfefef042..f1b1d950ca 100644 --- a/docs/i18n.txt +++ b/docs/i18n.txt @@ -361,8 +361,10 @@ That's it. Your translations are ready for use. .. admonition:: A note to translators If you've created a translation in a language Django doesn't yet support, - please let us know! We'll add it to the global list of available languages - in the global Django settings (``settings.LANGUAGES``). + please let us know! See `Submitting and maintaining translations`_ for + the steps to take. + + .. _Submitting and maintaining translations: http://www.djangoproject.com/documentation/contributing/ How Django discovers language preference ======================================== diff --git a/docs/settings.txt b/docs/settings.txt index 6913113c09..40ae452275 100644 --- a/docs/settings.txt +++ b/docs/settings.txt @@ -547,6 +547,21 @@ The ID, as an integer, of the current site in the ``sites`` database. This is used so that application data can hook into specific site(s) and a single database can manage content for multiple sites. +TEMPLATE_CONTEXT_PROCESSORS +--------------------------- + +Default:: + + ("django.core.context_processors.auth", + "django.core.context_processors.debug", + "django.core.context_processors.i18n") + +**Only available in Django development version.** + +A tuple of callables that are used to populate the context in ``DjangoContext``. +These callables take a request object as their argument and return a dictionary +of items to be merged into the context. + TEMPLATE_DEBUG -------------- diff --git a/docs/templates_python.txt b/docs/templates_python.txt index 3bedf67caa..9058208feb 100644 --- a/docs/templates_python.txt +++ b/docs/templates_python.txt @@ -246,21 +246,77 @@ Subclassing Context: DjangoContext Django comes with a special ``Context`` class, ``django.core.extensions.DjangoContext``, that acts slightly differently than -the normal ``django.core.template.Context``. It takes an ``HttpRequest`` object -as its first argument, and it automatically populates the context with a few -variables: +the normal ``django.core.template.Context``. The first difference is that takes +an `HttpRequest object`_ as its first argument. For example:: + + c = DjangoContext(request, { + 'foo': 'bar', + } + +The second difference is that it automatically populates the context with a few +variables, according to your `TEMPLATE_CONTEXT_PROCESSORS setting`_. + +The ``TEMPLATE_CONTEXT_PROCESSORS`` setting is a tuple of callables that take a +request object as their argument and return a dictionary of items to be merged +into the context. By default, ``TEMPLATE_CONTEXT_PROCESSORS`` is set to:: + + ("django.core.context_processors.auth", + "django.core.context_processors.debug", + "django.core.context_processors.i18n") + +Each processor is applied in order. That means, if one processor adds a +variable to the context and a second processor adds a variable with the same +name, the second will override the first. The default processors are explained +below. + +Also, you can give ``DjangoContext`` a list of additional processors, using the +optional, third positional argument, ``processors``. In this example, the +``DjangoContext`` instance gets a ``ip_address`` variable:: + + def ip_address_processor(request): + return {'ip_address': request.META['REMOTE_ADDR']} + + def some_view(request): + # ... + return DjangoContext({ + 'foo': 'bar', + }, [ip_address_processor]) + +Note: The concept of template-context processors is new in the Django +development version. In Django 0.90, ``DjangoContext`` automatically populates +the context with all of the values explained below, but it's not possible to +add and remove processors. + +Here's what each of the default processors does: + +.. _HttpRequest object: http://www.djangoproject.com/documentation/request_response/#httprequest-objects +.. _TEMPLATE_CONTEXT_PROCESSORS setting: http://www.djangoproject.com/documentation/settings/#template-context_processors + +django.core.context_processors.auth +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every +``DjangoContext`` will contain these three variables: * ``user`` -- An ``auth.User`` instance representing the currently logged-in user (or an ``AnonymousUser`` instance, if the client isn't logged in). See the `user authentication docs`. * ``messages`` -- A list of ``auth.Message`` objects for the currently logged-in user. - * ``perms`` -- An instance of ``django.core.extensions.PermWrapper``, + * ``perms`` -- An instance of ``django.core.context_processors.PermWrapper``, representing the permissions that the currently logged-in user has. See the `permissions docs`_. -Also, if your ``DEBUG`` setting is set to ``True``, every ``DjangoContext`` -instance has the following two extra variables: +.. _user authentication docs: http://www.djangoproject.com/documentation/models/authentication/#users +.. _permissions docs: http://www.djangoproject.com/documentation/models/authentication/#permissions + +django.core.context_processors.debug +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every +``DjangoContext`` will contain these two variables -- but only if your +``DEBUG`` setting is set to ``True`` and the request's IP address +(``request.META['REMOTE_ADDR']``) is in the ``INTERNAL_IPS`` setting: * ``debug`` -- ``True``. You can use this in templates to test whether you're in ``DEBUG`` mode. @@ -268,6 +324,25 @@ instance has the following two extra variables: representing every SQL query that has happened so far during the request and how long it took. The list is in order by query. +django.core.context_processors.i18n +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every +``DjangoContext`` will contain these two variables: + + * ``LANGUAGES`` -- The value of the `LANGUAGES setting`_. + * ``LANGUAGE_CODE`` -- ``request.LANGUAGE_CODE``, if it exists. Otherwise, + the value of the `LANGUAGE_CODE setting`_. + +See the `internationalization docs`_ for more. + +.. _LANGUAGES setting: http://www.djangoproject.com/documentation/settings/#languages +.. _LANGUAGE_CODE setting: http://www.djangoproject.com/documentation/settings/#language-code +.. _internationalization docs: http://www.djangoproject.com/documentation/i18n/ + +Subclassing Context: Custom subclasses +-------------------------------------- + Feel free to subclass ``Context`` yourself if you find yourself wanting to give each template something "automatically." For instance, if you want to give every template automatic access to the current time, use something like this:: @@ -287,9 +362,6 @@ This technique has two caveats: * You'll have to be careful not to set the variable ``current_time`` when you populate this context. If you do, you'll override the other one. -.. _user authentication docs: http://www.djangoproject.com/documentation/models/authentication/#users -.. _permissions docs: http://www.djangoproject.com/documentation/models/authentication/#permissions - Loading templates -----------------