Django

Code

Changeset 1773

Show
Ignore:
Timestamp:
12/23/05 22:39:59 (3 years ago)
Author:
adrian
Message:

Fixed #925 -- Added TEMPLATE_CONTEXT_PROCESSORS, which lets you specify processesors for DjangoContext?. Thanks, Luke Plant

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/conf/global_settings.py

    r1584 r1773  
    101101) 
    102102 
     103# List of processors used by DjangoContext to populate the context. 
     104# Each one should be a callable that takes the request object as its 
     105# only parameter and returns a dictionary to add to the context. 
     106TEMPLATE_CONTEXT_PROCESSORS = ( 
     107    'django.core.context_processors.auth', 
     108    'django.core.context_processors.debug', 
     109    'django.core.context_processors.i18n', 
     110) 
     111 
    103112# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a 
    104113# trailing slash. 
  • django/trunk/django/core/extensions.py

    r1068 r1773  
    33# for convenience's sake. 
    44 
    5 from django.core.exceptions import Http404, ObjectDoesNotExist 
     5from django.core.exceptions import Http404, ImproperlyConfigured, ObjectDoesNotExist 
    66from django.core.template import Context, loader 
    7 from django.conf.settings import DEBUG, INTERNAL_IP
     7from django.conf.settings import TEMPLATE_CONTEXT_PROCESSOR
    88from django.utils.httpwrappers import HttpResponse 
     9 
     10_standard_context_processors = None 
     11 
     12# This is a function rather than module-level procedural code because we only 
     13# want it to execute if somebody uses DjangoContext. 
     14def get_standard_processors(): 
     15    global _standard_context_processors 
     16    if _standard_context_processors is None: 
     17        processors = [] 
     18        for path in TEMPLATE_CONTEXT_PROCESSORS: 
     19            i = path.rfind('.') 
     20            module, attr = path[:i], path[i+1:] 
     21            try: 
     22                mod = __import__(module, '', '', [attr]) 
     23            except ImportError, e: 
     24                raise ImproperlyConfigured, 'Error importing request processor module %s: "%s"' % (module, e) 
     25            try: 
     26                func = getattr(mod, attr) 
     27            except AttributeError: 
     28                raise ImproperlyConfigured, 'Module "%s" does not define a "%s" callable request processor' % (module, attr) 
     29            processors.append(func) 
     30        _standard_context_processors = tuple(processors) 
     31    return _standard_context_processors 
    932 
    1033def render_to_response(*args, **kwargs): 
     
    2649class DjangoContext(Context): 
    2750    """ 
    28     This subclass of template.Context automatically populates 'user' and 
    29     'messages' in the context. 
     51    This subclass of template.Context automatically populates itself using 
     52    the processors defined in TEMPLATE_CONTEXT_PROCESSORS. 
     53    Additional processors can be specified as a list of callables 
     54    using the "processors" keyword argument. 
    3055    """ 
    31     def __init__(self, request, dict=None): 
     56    def __init__(self, request, dict=None, processors=None): 
    3257        Context.__init__(self, dict) 
    33         self['user'] = request.user 
    34         self['messages'] = request.user.get_and_delete_messages() 
    35         self['perms'] = PermWrapper(request.user) 
    36         from django.conf import settings 
    37         self['LANGUAGES'] = settings.LANGUAGES 
    38         if hasattr(request, 'LANGUAGE_CODE'): 
    39             self['LANGUAGE_CODE'] = request.LANGUAGE_CODE 
     58        if processors is None: 
     59            processors = () 
    4060        else: 
    41             self['LANGUAGE_CODE'] = settings.LANGUAGE_CODE 
    42         if DEBUG and request.META.get('REMOTE_ADDR') in INTERNAL_IPS: 
    43             self['debug'] = True 
    44             from django.core import db 
    45             self['sql_queries'] = db.db.queries 
     61            processors = tuple(processors) 
     62        for processor in get_standard_processors() + processors: 
     63            self.update(processor(request)) 
    4664 
    4765# PermWrapper and PermLookupDict proxy the permissions system into objects that 
  • django/trunk/django/views/generic/create_update.py

    r1684 r1773  
    44from django.core import formfields, meta 
    55from django.views.auth.login import redirect_to_login 
    6 from django.core.extensions import DjangoContext as Context 
     6from django.core.extensions import DjangoContext 
    77from django.core.paginator import ObjectPaginator, InvalidPage 
    88from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect 
     
    1010 
    1111def create_object(request, app_label, module_name, template_name=None, 
    12                  template_loader=loader, extra_context={}
    13                  post_save_redirect=None, login_required=False, follow=None): 
     12        template_loader=loader, extra_context={}, post_save_redirect=None
     13        login_required=False, follow=None, context_processors=None): 
    1414    """ 
    1515    Generic object-creation function. 
     
    6161        template_name = "%s/%s_form" % (app_label, module_name) 
    6262    t = template_loader.get_template(template_name) 
    63     c = Context(request, { 
    64         'form' : form, 
    65     }
     63    c = DjangoContext(request, { 
     64        'form': form, 
     65    }, context_processors
    6666    for key, value in extra_context.items(): 
    6767        if callable(value): 
     
    7272 
    7373def update_object(request, app_label, module_name, object_id=None, slug=None, 
    74                   slug_field=None, template_name=None, template_loader=loader, 
    75                   extra_lookup_kwargs={}, extra_context={}, post_save_redirect=None, 
    76                   login_required=False, follow=None): 
     74        slug_field=None, template_name=None, template_loader=loader, 
     75        extra_lookup_kwargs={}, extra_context={}, post_save_redirect=None, 
     76        login_required=False, follow=None, context_processors=None): 
    7777    """ 
    7878    Generic object-update function. 
     
    132132        template_name = "%s/%s_form" % (app_label, module_name) 
    133133    t = template_loader.get_template(template_name) 
    134     c = Context(request, { 
    135         'form' : form, 
    136         'object' : object, 
    137     }
     134    c = DjangoContext(request, { 
     135        'form': form, 
     136        'object': object, 
     137    }, context_processors
    138138    for key, value in extra_context.items(): 
    139139        if callable(value): 
     
    146146 
    147147def delete_object(request, app_label, module_name, post_delete_redirect, 
    148                   object_id=None, slug=None, slug_field=None, template_name=None, 
    149                   template_loader=loader, extra_lookup_kwargs={}, 
    150                   extra_context={}, login_required=False): 
     148        object_id=None, slug=None, slug_field=None, template_name=None, 
     149        template_loader=loader, extra_lookup_kwargs={}, extra_context={}, 
     150        login_required=False, context_processors=None): 
    151151    """ 
    152152    Generic object-delete function. 
     
    189189            template_name = "%s/%s_confirm_delete" % (app_label, module_name) 
    190190        t = template_loader.get_template(template_name) 
    191         c = Context(request, { 
    192             'object' : object, 
    193         }
     191        c = DjangoContext(request, { 
     192            'object': object, 
     193        }, context_processors
    194194        for key, value in extra_context.items(): 
    195195            if callable(value): 
     
    200200        populate_xheaders(request, response, app_label, module_name, getattr(object, object._meta.pk.name)) 
    201201        return response 
    202  
  • django/trunk/django/views/generic/date_based.py

    r1684 r1773  
    11from django.core.template import loader 
    22from django.core.exceptions import Http404, ObjectDoesNotExist 
    3 from django.core.extensions import DjangoContext as Context 
     3from django.core.extensions import DjangoContext 
    44from django.core.xheaders import populate_xheaders 
    55from django.models import get_module 
     
    88 
    99def archive_index(request, app_label, module_name, date_field, num_latest=15, 
    10                   template_name=None, template_loader=loader
    11                   extra_lookup_kwargs={}, extra_context={}, allow_empty=False): 
     10        template_name=None, template_loader=loader, extra_lookup_kwargs={}
     11        extra_context={}, allow_empty=False, context_processors=None): 
    1212    """ 
    1313    Generic top-level archive of date-based objects. 
     
    3939        template_name = "%s/%s_archive" % (app_label, module_name) 
    4040    t = template_loader.get_template(template_name) 
    41     c = Context(request, { 
     41    c = DjangoContext(request, { 
    4242        'date_list' : date_list, 
    4343        'latest' : latest, 
    44     }
     44    }, context_processors
    4545    for key, value in extra_context.items(): 
    4646        if callable(value): 
     
    5151 
    5252def archive_year(request, year, app_label, module_name, date_field, 
    53                  template_name=None, template_loader=loader
    54                  extra_lookup_kwargs={}, extra_context={}): 
     53        template_name=None, template_loader=loader, extra_lookup_kwargs={}
     54        extra_context={}, context_processors=None): 
    5555    """ 
    5656    Generic yearly archive view. 
     
    7676        template_name = "%s/%s_archive_year" % (app_label, module_name) 
    7777    t = template_loader.get_template(template_name) 
    78     c = Context(request, { 
     78    c = DjangoContext(request, { 
    7979        'date_list': date_list, 
    8080        'year': year, 
    81     }
     81    }, context_processors
    8282    for key, value in extra_context.items(): 
    8383        if callable(value): 
     
    8888 
    8989def archive_month(request, year, month, app_label, module_name, date_field, 
    90                   month_format='%b', template_name=None, template_loader=loader, 
    91                   extra_lookup_kwargs={}, extra_context={}): 
     90        month_format='%b', template_name=None, template_loader=loader, 
     91        extra_lookup_kwargs={}, extra_context={}, context_processors=None): 
    9292    """ 
    9393    Generic monthly archive view. 
     
    124124        template_name = "%s/%s_archive_month" % (app_label, module_name) 
    125125    t = template_loader.get_template(template_name) 
    126     c = Context(request, { 
     126    c = DjangoContext(request, { 
    127127        'object_list': object_list, 
    128128        'month': date, 
    129     }
     129    }, context_processors
    130130    for key, value in extra_context.items(): 
    131131        if callable(value): 
     
    136136 
    137137def archive_day(request, year, month, day, app_label, module_name, date_field, 
    138                 month_format='%b', day_format='%d', template_name=None, 
    139                 template_loader=loader, extra_lookup_kwargs={}, 
    140                 extra_context={}, allow_empty=False): 
     138        month_format='%b', day_format='%d', template_name=None, 
     139        template_loader=loader, extra_lookup_kwargs={}, extra_context={}, 
     140        allow_empty=False, context_processors=None): 
    141141    """ 
    142142    Generic daily archive view. 
     
    173173        template_name = "%s/%s_archive_day" % (app_label, module_name) 
    174174    t = template_loader.get_template(template_name) 
    175     c = Context(request, { 
     175    c = DjangoContext(request, { 
    176176        'object_list': object_list, 
    177177        'day': date, 
    178178        'previous_day': date - datetime.timedelta(days=1), 
    179179        'next_day': (date < datetime.date.today()) and (date + datetime.timedelta(days=1)) or None, 
    180     }
     180    }, context_processors
    181181    for key, value in extra_context.items(): 
    182182        if callable(value): 
     
    199199 
    200200def object_detail(request, year, month, day, app_label, module_name, date_field, 
    201                   month_format='%b', day_format='%d', object_id=None, slug=None, 
    202                   slug_field=None, template_name=None, template_name_field=None, 
    203                   template_loader=loader, extra_lookup_kwargs={}, 
    204                   extra_context={}): 
     201        month_format='%b', day_format='%d', object_id=None, slug=None, 
     202        slug_field=None, template_name=None, template_name_field=None, 
     203        template_loader=loader, extra_lookup_kwargs={}, extra_context={}, 
     204        context_processors=None): 
    205205    """ 
    206206    Generic detail view from year/month/day/slug or year/month/day/id structure. 
     
    242242    else: 
    243243        t = template_loader.get_template(template_name) 
    244     c = Context(request, { 
     244    c = DjangoContext(request, { 
    245245        'object': object, 
    246     }
     246    }, context_processors
    247247    for key, value in extra_context.items(): 
    248248        if callable(value): 
  • django/trunk/django/views/generic/list_detail.py

    r1684 r1773  
    33from django.utils.httpwrappers import HttpResponse 
    44from django.core.xheaders import populate_xheaders 
    5 from django.core.extensions import DjangoContext as Context 
     5from django.core.extensions import DjangoContext 
    66from django.core.paginator import ObjectPaginator, InvalidPage 
    77from django.core.exceptions import Http404, ObjectDoesNotExist 
    88 
    99def object_list(request, app_label, module_name, paginate_by=None, allow_empty=False, 
    10                 template_name=None, template_loader=loader
    11                 extra_lookup_kwargs={}, extra_context={}): 
     10        template_name=None, template_loader=loader, extra_lookup_kwargs={}
     11        extra_context={}, context_processors=None): 
    1212    """ 
    1313    Generic list of objects. 
     
    4949                raise Http404 
    5050        page = int(page) 
    51         c = Context(request, { 
     51        c = DjangoContext(request, { 
    5252            'object_list': object_list, 
    5353            'is_paginated': paginator.pages > 1, 
     
    6060            'pages': paginator.pages, 
    6161            'hits' : paginator.hits, 
    62         }
     62        }, context_processors
    6363    else: 
    6464        object_list = mod.get_list(**lookup_kwargs) 
    65         c = Context(request, { 
     65        c = DjangoContext(request, { 
    6666            'object_list': object_list, 
    6767            'is_paginated': False 
    68         }
     68        }, context_processors
    6969        if len(object_list) == 0 and not allow_empty: 
    7070            raise Http404 
     
    8080 
    8181def object_detail(request, app_label, module_name, object_id=None, slug=None, 
    82                   slug_field=None, template_name=None, template_name_field=None, 
    83                   template_loader=loader, extra_lookup_kwargs={}, 
    84                   extra_context={}): 
     82        slug_field=None, template_name=None, template_name_field=None, 
     83        template_loader=loader, extra_lookup_kwargs={}, extra_context={}, 
     84        context_processors=None): 
    8585    """ 
    8686    Generic list of objects. 
     
    111111    else: 
    112112        t = template_loader.get_template(template_name) 
    113     c = Context(request, { 
     113    c = DjangoContext(request, { 
    114114        'object': object, 
    115     }
     115    }, context_processors
    116116    for key, value in extra_context.items(): 
    117117        if callable(value): 
  • django/trunk/docs/authentication.txt

    r1440 r1773  
    439439`template context`_ when you use ``DjangoContext``. 
    440440 
     441.. admonition:: Technicality 
     442 
     443   Technically, these variables are only made available in the template context 
     444   if you use ``DjangoContext`` *and* your ``TEMPLATE_CONTEXT_PROCESSORS`` 
     445   setting contains ``"django.core.context_processors.auth"``, which is default. 
     446   For more, see the `DjangoContext docs`_. 
     447 
     448   .. _DjangoContext docs: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-djangocontext 
     449 
    441450Users 
    442451----- 
     
    455464 
    456465The currently logged-in user's permissions are stored in the template variable 
    457 ``{{ perms }}``. This is an instance of ``django.core.extensions.PermWrapper``, 
     466``{{ perms }}``. This is an instance of ``django.core.context_processors.PermWrapper``, 
    458467which is a template-friendly proxy of permissions. 
    459468 
  • django/trunk/docs/generic_views.txt

    r1510 r1773  
    129129    ``extra_context``        A dictionary of extra data to put into the 
    130130                             template's context. 
     131 
     132    ``processors``           **New in Django development version.** A tuple of 
     133                             processors to apply to the ``DjangoContext`` of 
     134                             this view's template. See the `DjangoContext docs`_ 
    131135    =======================  ================================================== 
    132136 
    133 .. _`database API docs`: http://www.djangoproject.com/documentation/db_api/ 
     137.. _database API docs: http://www.djangoproject.com/documentation/db_api/ 
     138.. _DjangoContext docs: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-djangocontext 
    134139 
    135140The date-based generic functions are: 
     
    248253object page. 
    249254 
    250 All these views take the same three optional arguments as the date-based ones 
     255All these views take the same four optional arguments as the date-based ones 
    251256-- and, clearly, they don't accept the ``date_field`` argument. 
    252257 
     
    372377        object 
    373378            The object about to be deleted 
    374  
  • django/trunk/docs/settings.txt

    r1585 r1773  
    548548database can manage content for multiple sites. 
    549549 
     550TEMPLATE_CONTEXT_PROCESSORS 
     551--------------------------- 
     552 
     553Default:: 
     554 
     555    ("django.core.context_processors.auth", 
     556    "django.core.context_processors.debug", 
     557    "django.core.context_processors.i18n") 
     558 
     559**Only available in Django development version.** 
     560 
     561A tuple of callables that are used to populate the context in ``DjangoContext``. 
     562These callables take a request object as their argument and return a dictionary 
     563of items to be merged into the context. 
     564 
    550565TEMPLATE_DEBUG 
    551566-------------- 
  • django/trunk/docs/templates_python.txt

    r1461 r1773  
    241241Django comes with a special ``Context`` class, 
    242242``django.core.extensions.DjangoContext``, that acts slightly differently than 
    243 the normal ``django.core.template.Context``. It takes an ``HttpRequest`` object 
    244 as its first argument, and it automatically populates the context with a few 
    245 variables: 
     243the normal ``django.core.template.Context``. The first difference is that takes 
     244an `HttpRequest object`_ as its first argument. For example:: 
     245 
     246    c = DjangoContext(request, { 
     247        'foo': 'bar', 
     248    } 
     249 
     250The second difference is that it automatically populates the context with a few 
     251variables, according to your `TEMPLATE_CONTEXT_PROCESSORS setting`_. 
     252 
     253The ``TEMPLATE_CONTEXT_PROCESSORS`` setting is a tuple of callables that take a 
     254request object as their argument and return a dictionary of items to be merged 
     255into the context. By default, ``TEMPLATE_CONTEXT_PROCESSORS`` is set to:: 
     256 
     257    ("django.core.context_processors.auth", 
     258    "django.core.context_processors.debug", 
     259    "django.core.context_processors.i18n") 
     260 
     261Each processor is applied in order. That means, if one processor adds a 
     262variable to the context and a second processor adds a variable with the same 
     263name, the second will override the first. The default processors are explained 
     264below. 
     265 
     266Also, you can give ``DjangoContext`` a list of additional processors, using the 
     267optional, third positional argument, ``processors``. In this example, the 
     268``DjangoContext`` instance gets a ``ip_address`` variable:: 
     269 
     270    def ip_address_processor(request): 
     271        return {'ip_address': request.META['REMOTE_ADDR']} 
     272 
     273    def some_view(request): 
     274        # ... 
     275        return DjangoContext({ 
     276            'foo': 'bar', 
     277        }, [ip_address_processor]) 
     278 
     279Note: The concept of template-context processors is new in the Django 
     280development version. In Django 0.90, ``DjangoContext`` automatically populates 
     281the context with all of the values explained below, but it's not possible to 
     282add and remove processors. 
     283 
     284Here's what each of the default processors does: 
     285 
     286.. _HttpRequest object: http://www.djangoproject.com/documentation/request_response/#httprequest-objects 
     287.. _TEMPLATE_CONTEXT_PROCESSORS setting: http://www.djangoproject.com/documentation/settings/#template-context_processors 
     288 
     289django.core.context_processors.auth 
     290~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     291 
     292If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every 
     293``DjangoContext`` will contain these three variables: 
    246294 
    247295    * ``user`` -- An ``auth.User`` instance representing the currently 
     
    250298    * ``messages`` -- A list of ``auth.Message`` objects for the currently 
    251299      logged-in user. 
    252     * ``perms`` -- An instance of ``django.core.extensions.PermWrapper``, 
     300    * ``perms`` -- An instance of ``django.core.context_processors.PermWrapper``, 
    253301      representing the permissions that the currently logged-in user has. See 
    254302      the `permissions docs`_. 
    255303 
    256 Also, if your ``DEBUG`` setting is set to ``True``, every ``DjangoContext`` 
    257 instance has the following two extra variables: 
     304.. _user authentication docs: http://www.djangoproject.com/documentation/models/authentication/#users 
     305.. _permissions docs: http://www.djangoproject.com/documentation/models/authentication/#permissions 
     306 
     307django.core.context_processors.debug 
     308~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     309 
     310If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every 
     311``DjangoContext`` will contain these two variables -- but only if your 
     312``DEBUG`` setting is set to ``True`` and the request's IP address 
     313(``request.META['REMOTE_ADDR']``) is in the ``INTERNAL_IPS`` setting: 
    258314 
    259315    * ``debug`` -- ``True``. You can use this in templates to test whether 
     
    262318      representing every SQL query that has happened so far during the request 
    263319      and how long it took. The list is in order by query. 
     320 
     321django.core.context_processors.i18n 
     322~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     323 
     324If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every 
     325``DjangoContext`` will contain these two variables: 
     326 
     327    * ``LANGUAGES`` -- The value of the `LANGUAGES setting`_. 
     328    * ``LANGUAGE_CODE`` -- ``request.LANGUAGE_CODE``, if it exists. Otherwise, 
     329      the value of the `LANGUAGE_CODE setting`_. 
     330 
     331See the `internationalization docs`_ for more. 
     332 
     333.. _LANGUAGES setting: http://www.djangoproject.com/documentation/settings/#languages 
     334.. _LANGUAGE_CODE setting: http://www.djangoproject.com/documentation/settings/#language-code 
     335.. _internationalization docs: http://www.djangoproject.com/documentation/i18n/ 
     336 
     337Subclassing Context: Custom subclasses 
     338-------------------------------------- 
    264339 
    265340Feel free to subclass ``Context`` yourself if you find yourself wanting to give 
     
    281356    * You'll have to be careful not to set the variable ``current_time`` when 
    282357      you populate this context. If you do, you'll override the other one. 
    283  
    284 .. _user authentication docs: http://www.djangoproject.com/documentation/models/authentication/#users 
    285 .. _permissions docs: http://www.djangoproject.com/documentation/models/authentication/#permissions 
    286358 
    287359Loading templates