Changeset 6442
- Timestamp:
- 09/30/07 22:58:05 (1 year ago)
- Files:
-
- django/branches/gis (modified) (1 prop)
- django/branches/gis/AUTHORS (modified) (4 diffs)
- django/branches/gis/django/contrib/admin/templatetags/admin_modify.py (modified) (3 diffs)
- django/branches/gis/django/contrib/auth/backends.py (modified) (1 diff)
- django/branches/gis/django/contrib/comments/templatetags/comments.py (modified) (6 diffs)
- django/branches/gis/django/contrib/sessions/models.py (modified) (1 diff)
- django/branches/gis/django/core/handlers/wsgi.py (modified) (3 diffs)
- django/branches/gis/django/core/management/base.py (modified) (2 diffs)
- django/branches/gis/django/core/management/__init__.py (modified) (8 diffs)
- django/branches/gis/django/db/models/query.py (modified) (1 diff)
- django/branches/gis/django/middleware/http.py (modified) (1 diff)
- django/branches/gis/django/template/defaultfilters.py (modified) (3 diffs)
- django/branches/gis/django/template/defaulttags.py (modified) (7 diffs)
- django/branches/gis/django/template/__init__.py (modified) (9 diffs)
- django/branches/gis/django/template/loader_tags.py (modified) (2 diffs)
- django/branches/gis/django/templatetags/i18n.py (modified) (2 diffs)
- django/branches/gis/django/utils/cache.py (modified) (5 diffs)
- django/branches/gis/django/utils/encoding.py (modified) (2 diffs)
- django/branches/gis/docs/databases.txt (modified) (1 diff)
- django/branches/gis/docs/db-api.txt (modified) (1 diff)
- django/branches/gis/docs/django-admin.txt (modified) (1 diff)
- django/branches/gis/docs/email.txt (modified) (1 diff)
- django/branches/gis/docs/generic_views.txt (modified) (1 diff)
- django/branches/gis/docs/install.txt (modified) (2 diffs)
- django/branches/gis/docs/newforms.txt (modified) (1 diff)
- django/branches/gis/docs/settings.txt (modified) (1 diff)
- django/branches/gis/docs/templates_python.txt (modified) (1 diff)
- django/branches/gis/tests/modeltests/serializers/models.py (modified) (4 diffs)
- django/branches/gis/tests/modeltests/signals/models.py (modified) (2 diffs)
- django/branches/gis/tests/modeltests/user_commands (copied) (copied from django/trunk/tests/modeltests/user_commands)
- django/branches/gis/tests/modeltests/user_commands/__init__.py (copied) (copied from django/trunk/tests/modeltests/user_commands/__init__.py)
- django/branches/gis/tests/modeltests/user_commands/management (copied) (copied from django/trunk/tests/modeltests/user_commands/management)
- django/branches/gis/tests/modeltests/user_commands/management/commands (copied) (copied from django/trunk/tests/modeltests/user_commands/management/commands)
- django/branches/gis/tests/modeltests/user_commands/management/commands/dance.py (copied) (copied from django/trunk/tests/modeltests/user_commands/management/commands/dance.py)
- django/branches/gis/tests/modeltests/user_commands/management/commands/__init__.py (copied) (copied from django/trunk/tests/modeltests/user_commands/management/commands/__init__.py)
- django/branches/gis/tests/modeltests/user_commands/management/__init__.py (copied) (copied from django/trunk/tests/modeltests/user_commands/management/__init__.py)
- django/branches/gis/tests/modeltests/user_commands/models.py (copied) (copied from django/trunk/tests/modeltests/user_commands/models.py)
- django/branches/gis/tests/regressiontests/httpwrappers/tests.py (modified) (3 diffs)
- django/branches/gis/tests/regressiontests/views/tests/generic/date_based.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/gis
- Property svnmerge-integrated changed from /django/trunk:1-6393 to /django/trunk:1-6441
django/branches/gis/AUTHORS
r6394 r6442 115 115 A. Murat Eren <meren@pardus.org.tr> 116 116 Ludvig Ericson <ludvig.ericson@gmail.com> 117 eriks@win.tue.nl 117 118 Dirk Eschler <dirk.eschler@gmx.net> 118 119 Marc Fargas <telenieko@telenieko.com> … … 235 236 pavithran s <pavithran.s@gmail.com> 236 237 Barry Pederson <bp@barryp.org> 238 permonik@mesias.brnonet.cz 237 239 petr.marhoun@gmail.com 238 240 pgross@thoughtworks.com … … 241 243 phil.h.smith@gmail.com 242 244 Gustavo Picon 243 pigletto244 245 Luke Plant <http://lukeplant.me.uk/> 245 246 plisk … … 322 323 Gary Wilson <gary.wilson@gmail.com> 323 324 Jakub Wiśniowski <restless.being@gmail.com> 325 Maciej Wiśniowski <pigletto@gmail.com> 324 326 wojtek 325 327 ye7cakf02@sneakemail.com django/branches/gis/django/contrib/admin/templatetags/admin_modify.py
r6018 r6442 73 73 74 74 def __init__(self, bound_field_var): 75 self.bound_field_var = bound_field_var75 self.bound_field_var = template.Variable(bound_field_var) 76 76 77 77 def get_nodelist(cls, klass): … … 97 97 98 98 def render(self, context): 99 bound_field = template.resolve_variable(self.bound_field_var,context)99 bound_field = self.bound_field_var.resolve(context) 100 100 101 101 context.push() … … 157 157 class EditInlineNode(template.Node): 158 158 def __init__(self, rel_var): 159 self.rel_var = rel_var159 self.rel_var = template.Variable(rel_var) 160 160 161 161 def render(self, context): 162 relation = template.resolve_variable(self.rel_var,context)162 relation = self.rel_var.resolve(context) 163 163 context.push() 164 164 if relation.field.rel.edit_inline == models.TABULAR: django/branches/gis/django/contrib/auth/backends.py
r6394 r6442 2 2 from django.contrib.auth.models import User 3 3 4 try: 5 set 6 except NameError: 7 from sets import Set as set # Python 2.3 fallback 8 4 9 class ModelBackend: 5 10 """ django/branches/gis/django/contrib/comments/templatetags/comments.py
r6018 r6442 20 20 is_public=True): 21 21 self.content_type = content_type 22 if obj_id_lookup_var is not None: 23 obj_id_lookup_var = template.Variable(obj_id_lookup_var) 22 24 self.obj_id_lookup_var, self.obj_id, self.free = obj_id_lookup_var, obj_id, free 23 25 self.photos_optional, self.photos_required = photos_optional, photos_required … … 33 35 if self.obj_id_lookup_var is not None: 34 36 try: 35 self.obj_id = template.resolve_variable(self.obj_id_lookup_var,context)37 self.obj_id = self.obj_id_lookup_var.resolve(context) 36 38 except template.VariableDoesNotExist: 37 39 return '' … … 76 78 def __init__(self, package, module, context_var_name, obj_id, var_name, free): 77 79 self.package, self.module = package, module 80 if context_var_name is not None: 81 context_var_name = template.Variable(context_var_name) 78 82 self.context_var_name, self.obj_id = context_var_name, obj_id 79 83 self.var_name, self.free = var_name, free … … 83 87 manager = self.free and FreeComment.objects or Comment.objects 84 88 if self.context_var_name is not None: 85 self.obj_id = template.resolve_variable(self.context_var_name,context)89 self.obj_id = self.context_var_name.resolve(context) 86 90 comment_count = manager.filter(object_id__exact=self.obj_id, 87 91 content_type__app_label__exact=self.package, … … 93 97 def __init__(self, package, module, context_var_name, obj_id, var_name, free, ordering, extra_kwargs=None): 94 98 self.package, self.module = package, module 99 if context_var_name is not None: 100 context_var_name = template.Variable(context_var_name) 95 101 self.context_var_name, self.obj_id = context_var_name, obj_id 96 102 self.var_name, self.free = var_name, free … … 103 109 if self.context_var_name is not None: 104 110 try: 105 self.obj_id = template.resolve_variable(self.context_var_name,context)111 self.obj_id = self.context_var_name.resolve(context) 106 112 except template.VariableDoesNotExist: 107 113 return '' django/branches/gis/django/contrib/sessions/models.py
r6394 r6442 1 import base64, md5, random, sys, datetime 1 import os 2 import sys 3 import time 4 import datetime 5 import base64 6 import md5 7 import random 2 8 import cPickle as pickle 9 3 10 from django.db import models 4 11 from django.utils.translation import ugettext_lazy as _ django/branches/gis/django/core/handlers/wsgi.py
r6394 r6442 1 from threading import Lock 2 from pprint import pformat 3 try: 4 from cStringIO import StringIO 5 except ImportError: 6 from StringIO import StringIO 7 1 8 from django.core.handlers.base import BaseHandler 2 9 from django.core import signals … … 5 12 from django.utils.encoding import force_unicode 6 13 from django import http 7 from pprint import pformat8 from shutil import copyfileobj9 from threading import Lock10 try:11 from cStringIO import StringIO12 except ImportError:13 from StringIO import StringIO14 14 15 15 # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html … … 106 106 107 107 def is_secure(self): 108 return 'HTTPS' in self.environ and self.environ['HTTPS'] == 'on' 108 return 'wsgi.url_scheme' in self.environ \ 109 and self.environ['wsgi.url_scheme'] == 'https' 109 110 110 111 def _load_post_and_files(self): django/branches/gis/django/core/management/base.py
r6394 r6442 10 10 pass 11 11 12 def handle_default_options(options): 13 """ 14 Include any default options that all commands should accept 15 here so that ManagementUtility can handle them before searching 16 for user commands. 17 """ 18 if options.settings: 19 os.environ['DJANGO_SETTINGS_MODULE'] = options.settings 20 if options.pythonpath: 21 sys.path.insert(0, options.pythonpath) 22 12 23 class BaseCommand(object): 13 24 # Metadata about this command. … … 56 67 parser = self.create_parser(argv[0], argv[1]) 57 68 options, args = parser.parse_args(argv[2:]) 58 if options.settings: 59 os.environ['DJANGO_SETTINGS_MODULE'] = options.settings 60 if options.pythonpath: 61 sys.path.insert(0, options.pythonpath) 69 handle_default_options(options) 62 70 self.execute(*args, **options.__dict__) 63 71 django/branches/gis/django/core/management/__init__.py
r6394 r6442 1 1 import django 2 from django.core.management.base import BaseCommand, CommandError, handle_default_options 2 3 from optparse import OptionParser 3 4 import os 4 5 import sys 6 from imp import find_module 5 7 6 8 # For backwards compatibility: get_version() used to be in this module. 7 9 get_version = django.get_version 8 10 9 def load_command_class(name): 10 """ 11 Given a command name, returns the Command class instance. Raises 12 ImportError if it doesn't exist. 13 """ 14 # Let the ImportError propogate. 15 return getattr(__import__('django.core.management.commands.%s' % name, {}, {}, ['Command']), 'Command')() 11 # A cache of loaded commands, so that call_command 12 # doesn't have to reload every time it is called 13 _commands = None 14 15 def find_commands(management_dir): 16 """ 17 Given a path to a management directory, return a list of all the command names 18 that are available. Returns an empty list if no commands are defined. 19 """ 20 command_dir = os.path.join(management_dir,'commands') 21 try: 22 return [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')] 23 except OSError: 24 return [] 25 26 def find_management_module(app_name): 27 """ 28 Determine the path to the management module for the application named, 29 without acutally importing the application or the management module. 30 31 Raises ImportError if the management module cannot be found for any reason. 32 """ 33 parts = app_name.split('.') 34 parts.append('management') 35 parts.reverse() 36 path = None 37 while parts: 38 part = parts.pop() 39 f,path,descr = find_module(part, path and [path] or None) 40 return path 41 42 def load_command_class(app_name, name): 43 """ 44 Given a command name and an application name, returns the Command 45 class instance. All errors raised by the importation process 46 (ImportError, AttributeError) are allowed to propagate. 47 """ 48 return getattr(__import__('%s.management.commands.%s' % (app_name, name), 49 {}, {}, ['Command']), 'Command')() 50 51 def get_commands(load_user_commands=True, project_directory=None): 52 """ 53 Returns a dictionary of commands against the application in which 54 those commands can be found. This works by looking for a 55 management.commands package in django.core, and in each installed 56 application -- if a commands package exists, all commands in that 57 package are registered. 58 59 Core commands are always included; user-defined commands will also 60 be included if ``load_user_commands`` is True. If a project directory 61 is provided, the startproject command will be disabled, and the 62 startapp command will be modified to use that directory. 63 64 The dictionary is in the format {command_name: app_name}. Key-value 65 pairs from this dictionary can then be used in calls to 66 load_command_class(app_name, command_name) 67 68 If a specific version of a command must be loaded (e.g., with the 69 startapp command), the instantiated module can be placed in the 70 dictionary in place of the application name. 71 72 The dictionary is cached on the first call, and reused on subsequent 73 calls. 74 """ 75 global _commands 76 if _commands is None: 77 _commands = dict([(name, 'django.core') 78 for name in find_commands(__path__[0])]) 79 if load_user_commands: 80 # Get commands from all installed apps 81 from django.conf import settings 82 for app_name in settings.INSTALLED_APPS: 83 try: 84 path = find_management_module(app_name) 85 _commands.update(dict([(name, app_name) 86 for name in find_commands(path)])) 87 except ImportError: 88 pass # No management module - ignore this app 89 90 if project_directory: 91 # Remove the "startproject" command from self.commands, because 92 # that's a django-admin.py command, not a manage.py command. 93 del _commands['startproject'] 94 95 # Override the startapp command so that it always uses the 96 # project_directory, not the current working directory 97 # (which is default). 98 from django.core.management.commands.startapp import ProjectCommand 99 _commands['startapp'] = ProjectCommand(project_directory) 100 101 return _commands 16 102 17 103 def call_command(name, *args, **options): … … 26 112 call_command('sqlall', 'myapp') 27 113 """ 28 klass = load_command_class(name) 114 try: 115 app_name = get_commands()[name] 116 if isinstance(app_name, BaseCommand): 117 # If the command is already loaded, use it directly. 118 klass = app_name 119 else: 120 klass = load_command_class(app_name, name) 121 except KeyError: 122 raise CommandError, "Unknown command: %r" % name 29 123 return klass.execute(*args, **options) 124 125 class LaxOptionParser(OptionParser): 126 """ 127 An option parser that doesn't raise any errors on unknown options. 128 129 This is needed because the --settings and --pythonpath options affect 130 the commands (and thus the options) that are available to the user. 131 """ 132 def error(self, msg): 133 pass 30 134 31 135 class ManagementUtility(object): … … 39 143 self.argv = argv or sys.argv[:] 40 144 self.prog_name = os.path.basename(self.argv[0]) 41 self.commands = self.default_commands() 42 43 def default_commands(self): 44 """ 45 Returns a dictionary of instances of all available Command classes. 46 47 This works by looking for and loading all Python modules in the 48 django.core.management.commands package. 49 50 The dictionary is in the format {name: command_instance}. 51 """ 52 command_dir = os.path.join(__path__[0], 'commands') 53 names = [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')] 54 return dict([(name, load_command_class(name)) for name in names]) 55 145 self.project_directory = None 146 self.user_commands = False 147 56 148 def main_help_text(self): 57 149 """ … … 62 154 usage.append("Type '%s help <subcommand>' for help on a specific subcommand." % self.prog_name) 63 155 usage.append('Available subcommands:') 64 commands = self.commands.keys()156 commands = get_commands(self.user_commands, self.project_directory).keys() 65 157 commands.sort() 66 158 for cmd in commands: … … 75 167 """ 76 168 try: 77 return self.commands[subcommand] 169 app_name = get_commands(self.user_commands, self.project_directory)[subcommand] 170 if isinstance(app_name, BaseCommand): 171 # If the command is already loaded, use it directly. 172 klass = app_name 173 else: 174 klass = load_command_class(app_name, subcommand) 78 175 except KeyError: 79 176 sys.stderr.write("Unknown command: %r\nType '%s help' for usage.\n" % (subcommand, self.prog_name)) 80 177 sys.exit(1) 81 178 return klass 179 82 180 def execute(self): 83 181 """ … … 85 183 being run, creates a parser appropriate to that command, and runs it. 86 184 """ 185 # Preprocess options to extract --settings and --pythonpath. These options 186 # could affect the commands that are available, so they must be processed 187 # early 188 parser = LaxOptionParser(version=get_version(), 189 option_list=BaseCommand.option_list) 190 try: 191 options, args = parser.parse_args(self.argv) 192 handle_default_options(options) 193 except: 194 pass # Ignore any option errors at this point. 195 87 196 try: 88 197 subcommand = self.argv[1] … … 92 201 93 202 if subcommand == 'help': 94 if len( self.argv) > 2:95 self.fetch_command( self.argv[2]).print_help(self.prog_name, self.argv[2])203 if len(args) > 2: 204 self.fetch_command(args[2]).print_help(self.prog_name, args[2]) 96 205 else: 97 206 sys.stderr.write(self.main_help_text() + '\n') … … 117 226 def __init__(self, argv, project_directory): 118 227 super(ProjectManagementUtility, self).__init__(argv) 119 120 # Remove the "startproject" command from self.commands, because 121 # that's a django-admin.py command, not a manage.py command. 122 del self.commands['startproject'] 123 124 # Override the startapp command so that it always uses the 125 # project_directory, not the current working directory (which is default). 126 from django.core.management.commands.startapp import ProjectCommand 127 self.commands['startapp'] = ProjectCommand(project_directory) 128 228 self.project_directory = project_directory 229 self.user_commands = True 230 129 231 def setup_environ(settings_mod): 130 232 """ django/branches/gis/django/db/models/query.py
r6394 r6442 1181 1181 setattr(instance, field.attname, None) 1182 1182 1183 dispatcher.send(signal=signals.post_delete, sender=cls, instance=instance) 1183 1184 setattr(instance, cls._meta.pk.attname, None) 1184 dispatcher.send(signal=signals.post_delete, sender=cls, instance=instance)1185 1185 1186 1186 transaction.commit_unless_managed() django/branches/gis/django/middleware/http.py
r6394 r6442 55 55 return None 56 56 else: 57 # HTTP_X_FORWARDED_FOR can be a comma-separated list of IPs. 58 # Take just the last one. 59 # See http://bob.pythonmac.org/archives/2005/09/23/apache-x-forwarded-for-caveat/ 60 real_ip = real_ip.split(",")[-1].strip() 57 # HTTP_X_FORWARDED_FOR can be a comma-separated list of IPs. The 58 # client's IP will be the first one. 59 real_ip = real_ip.split(",")[0].strip() 61 60 request.META['REMOTE_ADDR'] = real_ip django/branches/gis/django/template/defaultfilters.py
r6394 r6442 1 1 "Default variable filters" 2 2 3 from django.template import resolve_variable, Library3 from django.template import Variable, Library 4 4 from django.conf import settings 5 5 from django.utils.translation import ugettext, ungettext … … 298 298 the argument. 299 299 """ 300 decorated = [(resolve_variable(u'var.' + arg, {u'var' : item}), item) for item in value] 300 var_resolve = Variable(arg).resolve 301 decorated = [(var_resolve(item), item) for item in value] 301 302 decorated.sort() 302 303 return [item[1] for item in decorated] … … 307 308 property given in the argument. 308 309 """ 309 decorated = [(resolve_variable(u'var.' + arg, {u'var' : item}), item) for item in value] 310 var_resolve = Variable(arg).resolve 311 decorated = [(var_resolve(item), item) for item in value] 310 312 decorated.sort() 311 313 decorated.reverse() django/branches/gis/django/template/defaulttags.py
r6394 r6442 1 1 "Default tags used by the template system, available to all templates." 2 2 3 from django.template import Node, NodeList, Template, Context, resolve_variable3 from django.template import Node, NodeList, Template, Context, Variable 4 4 from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END 5 5 from django.template import get_library, Library, InvalidTemplateLibrary … … 31 31 self.counter += 1 32 32 value = self.cyclevars[self.counter % self.cyclevars_len] 33 value = resolve_variable(value,context)33 value = Variable(value).resolve(context) 34 34 if self.variable_name: 35 35 context[self.variable_name] = value … … 58 58 class FirstOfNode(Node): 59 59 def __init__(self, vars): 60 self.vars = vars60 self.vars = map(Variable, vars) 61 61 62 62 def render(self, context): 63 63 for var in self.vars: 64 64 try: 65 value = resolve_variable(var,context)65 value = var.resolve(context) 66 66 except VariableDoesNotExist: 67 67 continue … … 148 148 self.nodelist = nodelist 149 149 self._last_seen = None 150 self._varlist = varlist150 self._varlist = map(Variable, varlist) 151 151 152 152 def render(self, context): … … 157 157 # Consider multiple parameters. 158 158 # This automatically behaves like a OR evaluation of the multiple variables. 159 compare_to = [ resolve_variable(var,context) for var in self._varlist]159 compare_to = [var.resolve(context) for var in self._varlist] 160 160 else: 161 161 compare_to = self.nodelist.render(context) … … 176 176 class IfEqualNode(Node): 177 177 def __init__(self, var1, var2, nodelist_true, nodelist_false, negate): 178 self.var1, self.var2 = var1, var2178 self.var1, self.var2 = Variable(var1), Variable(var2) 179 179 self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false 180 180 self.negate = negate … … 185 185 def render(self, context): 186 186 try: 187 val1 = resolve_variable(self.var1,context)187 val1 = self.var1.resolve(context) 188 188 except VariableDoesNotExist: 189 189 val1 = None 190 190 try: 191 val2 = resolve_variable(self.var2,context)191 val2 = self.var2.resolve(context) 192 192 except VariableDoesNotExist: 193 193 val2 = None django/branches/gis/django/template/__init__.py
r6394 r6442 89 89 re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END), 90 90 re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END))) 91 # matches if the string is valid number92 number_re = re.compile(r'[-+]?(\d+|\d*\.\d+)$')93 91 94 92 # global dictionary of libraries that have been loaded using get_library … … 565 563 args.append((False, constant_arg.replace(r'\"', '"'))) 566 564 elif var_arg: 567 args.append((True, var_arg))565 args.append((True, Variable(var_arg))) 568 566 filter_func = parser.find_filter(filter_name) 569 567 self.args_check(filter_name,filter_func, args) … … 572 570 if upto != len(token): 573 571 raise TemplateSyntaxError, "Could not parse the remainder: '%s' from '%s'" % (token[upto:], token) 574 self.var, self.filters = var, filters 572 self.filters = filters 573 self.var = Variable(var) 575 574 576 575 def resolve(self, context, ignore_failures=False): 577 576 try: 578 obj = resolve_variable(self.var,context)577 obj = self.var.resolve(context) 579 578 except VariableDoesNotExist: 580 579 if ignore_failures: … … 596 595 arg_vals.append(arg) 597 596 else: 598 arg_vals.append( resolve_variable(arg,context))597 arg_vals.append(arg.resolve(context)) 599 598 obj = func(obj, *arg_vals) 600 599 return obj … … 638 637 """ 639 638 Returns the resolved variable, which may contain attribute syntax, within 640 the given context. The variable may be a hard-coded string (if it begins 641 and ends with single or double quote marks). 642 643 >>> c = {'article': {'section':'News'}} 644 >>> resolve_variable('article.section', c) 645 u'News' 646 >>> resolve_variable('article', c) 647 {'section': 'News'} 648 >>> class AClass: pass 649 >>> c = AClass() 650 >>> c.article = AClass() 651 >>> c.article.section = 'News' 652 >>> resolve_variable('article.section', c) 653 u'News' 639 the given context. 640 641 Deprecated; use the Variable class instead. 642 """ 643 return Variable(path).resolve(context) 644 645 class Variable(object): 646 """ 647 A template variable, resolvable against a given context. The variable may be 648 a hard-coded string (if it begins and ends with single or double quote 649 marks):: 650 651 >>> c = {'article': {'section':'News'}} 652 >>> Variable('article.section').resolve(c) 653 u'News' 654 >>> Variable('article').resolve(c) 655 {'section': 'News'} 656 >>> class AClass: pass 657 >>> c = AClass() 658 >>> c.article = AClass() 659 >>> c.article.section = 'News' 660 >>> Variable('article.section').resolve(c) 661 u'News' 654 662 655 663 (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.') 656 664 """ 657 if number_re.match(path): 658 number_type = '.' in path and float or int 659 current = number_type(path) 660 elif path[0] in ('"', "'") and path[0] == path[-1]: 661 current = path[1:-1] 662 else: 665 666 def __init__(self, var): 667 self.var = var 668 self.literal = None 669 self.lookups = None 670 671 try: 672 # First try to treat this variable as a number. 673 # 674 # Note that this could cause an OverflowError here that we're not 675 # catching. Since this should only happen at compile time, that's 676 # probably OK. 677 self.literal = float(var) 678 679 # So it's a float... is it an int? If the original value contained a 680 # dot or an "e" then it was a float, not an int. 681 if '.' not in var and 'e' not in var.lower(): 682 self.literal = int(self.literal) 683 684 # "2." is invalid 685 if var.endswith('.'): 686 raise ValueError 687 688 except ValueError: 689 # A ValueError means that the variable isn't a number. 690 # If it's wrapped with quotes (single or double), then 691 # we're also dealing with a literal. 692 if var[0] in "\"'" and var[0] == var[-1]: 693 self.literal = var[1:-1] 694 695 else: 696 # Otherwise we'll set self.lookups so that resolve() knows we're 697 # dealing with a bonafide variable 698 self.lookups = tuple(var.split(VARIABLE_ATTRIBUTE_SEPARATOR)) 699 700 def resolve(self, context): 701 """Resolve this variable against a given context.""" 702 if self.lookups is not None: 703 # We're dealing with a variable that needs to be resolved 704 return self._resolve_lookup(context) 705 else: 706 # We're dealing with a literal, so it's already been "resolved" 707 return self.literal 708 709 def __repr__(self): 710 return "<%s: %r>" % (self.__class__.__name__, self.var) 711 712 def __str__(self): 713 return self.var 714 715 def _resolve_lookup(self, context): 716 """ 717 Performs resolution of a real variable (i.e. not a literal) against the 718 given context. 719 720 As indicated by the method's name, this method is an implementation 721 detail and shouldn't be called by external code. Use Variable.resolve() 722 instead. 723 """ 663 724 current = context 664 bits = path.split(VARIABLE_ATTRIBUTE_SEPARATOR) 665 while bits: 725 for bit in self.lookups: 666 726 try: # dictionary lookup 667 current = current[bit s[0]]727 current = current[bit] 668 728 except (TypeError, AttributeError, KeyError): 669 729 try: # attribute lookup 670 current = getattr(current, bit s[0])730 current = getattr(current, bit) 671 731 if callable(current): 672 732 if getattr(current, 'alters_data', False): … … 686 746 except (TypeError, AttributeError): 687 747 try: # list-index lookup 688 current = current[int(bit s[0])]748 current = current[int(bit)] 689 749 except (IndexError, # list index out of range 690 750 ValueError, # invalid literal for int() 691 KeyError, # current is a dict without `int(bit s[0])` key751 KeyError, # current is a dict without `int(bit)` key 692 752 TypeError, # unsubscriptable object 693 753 ): 694 raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit s[0], current)) # missing attribute754 raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute 695 755 except Exception, e: 696 756 if getattr(e, 'silent_variable_failure', False): … … 698 758 else: 699 759 raise 700 del bits[0]701 if isinstance(current, (basestring, Promise)):702 try:703 current = force_unicode(current)704 except UnicodeDecodeError:705 # Failing to convert to unicode can happen sometimes (e.g. debug706 # tracebacks). So we allow it in this particular instance.707 pass708 return current760 761 if isinstance(current, (basestring, Promise)): 762 try: 763 current = force_unicode(current) 764 except UnicodeDecodeError: 765 # Failing to convert to unicode can happen sometimes (e.g. debug 766 # tracebacks). So we allow it in this particular instance. 767 pass 768 return current 709 769 710 770 class Node(object): … … 862 922 class SimpleNode(Node): 863 923 def __init__(self, vars_to_resolve): 864 self.vars_to_resolve = vars_to_resolve924 self.vars_to_resolve = map(Variable, vars_to_resolve) 865 925 866 926 def render(self, context): 867 resolved_vars = [ resolve_variable(var,context) for var in self.vars_to_resolve]927 resolved_vars = [var.resolve(context) for var in self.vars_to_resolve] 868 928 return func(*resolved_vars) 869 929 … … 884 944 class InclusionNode(Node): 885 945 def __init__(self, vars_to_resolve): 886 self.vars_to_resolve = vars_to_resolve946 self.vars_to_resolve = map(Variable, vars_to_resolve) 887 947 888 948 def render(self, context): 889 resolved_vars = [ resolve_variable(var,context) for var in self.vars_to_resolve]949 resolved_vars = [var.resolve(context) for var in self.vars_to_resolve] 890 950 if takes_context: 891 951 args = [context] + resolved_vars django/branches/gis/django/template/loader_tags.py
r6018 r6442 1 from django.template import TemplateSyntaxError, TemplateDoesNotExist, resolve_variable1 from django.template import TemplateSyntaxError, TemplateDoesNotExist, Variable 2 2 from django.template import Library, Node 3 3 from django.template.loader import get_template, get_template_from_string, find_template_source … … 100 100 class IncludeNode(Node): 101 101 def __init__(self, template_name): 102 self.template_name = template_name102 self.template_name =
