1
0
mirror of https://github.com/django/django.git synced 2025-07-05 18:29:11 +00:00

[1.2.X] Fixed #14290 -- Made format localization faster by caching the format modules. Thanks, Teemu Kurppa and Anssi Kääriäinen for the report and initial patches.

Backport from trunk (r13898).

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@13903 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jannis Leidel 2010-09-27 15:27:07 +00:00
parent 6ee04e0f97
commit d99f19fb6a
7 changed files with 68 additions and 29 deletions

View File

@ -7,29 +7,36 @@ from django.utils.importlib import import_module
from django.utils.encoding import smart_str from django.utils.encoding import smart_str
from django.utils import dateformat, numberformat, datetime_safe from django.utils import dateformat, numberformat, datetime_safe
# format_cache is a mapping from (format_type, lang) to the format string.
# By using the cache, it is possible to avoid running get_format_modules
# repeatedly.
_format_cache = {}
_format_modules_cache = {}
def iter_format_modules(lang):
"""
Does the heavy lifting of finding format modules.
"""
if check_for_language(lang) or settings.USE_L10N:
format_locations = ['django.conf.locale.%s']
if settings.FORMAT_MODULE_PATH:
format_locations.append(settings.FORMAT_MODULE_PATH + '.%s')
format_locations.reverse()
locale = to_locale(lang)
locales = set((locale, locale.split('_')[0]))
for location in format_locations:
for loc in locales:
try:
yield import_module('.formats', location % loc)
except ImportError:
pass
def get_format_modules(reverse=False): def get_format_modules(reverse=False):
""" """
Returns an iterator over the format modules found in the project and Django Returns an iterator over the format modules found
""" """
modules = [] lang = get_language()
if not check_for_language(get_language()) or not settings.USE_L10N: modules = _format_modules_cache.setdefault(lang, list(iter_format_modules(lang)))
return modules
locale = to_locale(get_language())
if settings.FORMAT_MODULE_PATH:
format_locations = [settings.FORMAT_MODULE_PATH + '.%s']
else:
format_locations = []
format_locations.append('django.conf.locale.%s')
for location in format_locations:
for l in (locale, locale.split('_')[0]):
try:
mod = import_module('.formats', location % l)
except ImportError:
pass
else:
# Don't return duplicates
if mod not in modules:
modules.append(mod)
if reverse: if reverse:
modules.reverse() modules.reverse()
return modules return modules
@ -42,11 +49,18 @@ def get_format(format_type):
""" """
format_type = smart_str(format_type) format_type = smart_str(format_type)
if settings.USE_L10N: if settings.USE_L10N:
for module in get_format_modules(): cache_key = (format_type, get_language())
try: try:
return getattr(module, format_type) return _format_cache[cache_key] or getattr(settings, format_type)
except AttributeError: except KeyError:
pass for module in get_format_modules():
try:
val = getattr(module, format_type)
_format_cache[cache_key] = val
return val
except AttributeError:
pass
_format_cache[cache_key] = None
return getattr(settings, format_type) return getattr(settings, format_type)
def date_format(value, format=None): def date_format(value, format=None):

View File

@ -1,4 +1,6 @@
from django.conf import settings from django.conf import settings
from django.utils.safestring import mark_safe
def format(number, decimal_sep, decimal_pos, grouping=0, thousand_sep=''): def format(number, decimal_sep, decimal_pos, grouping=0, thousand_sep=''):
""" """
@ -11,15 +13,20 @@ def format(number, decimal_sep, decimal_pos, grouping=0, thousand_sep=''):
* thousand_sep: Thousand separator symbol (for example ",") * thousand_sep: Thousand separator symbol (for example ",")
""" """
use_grouping = settings.USE_L10N and \
settings.USE_THOUSAND_SEPARATOR and grouping
# Make the common case fast:
if isinstance(number, int) and not use_grouping and not decimal_pos:
return mark_safe(unicode(number))
# sign # sign
if float(number) < 0: if float(number) < 0:
sign = '-' sign = '-'
else: else:
sign = '' sign = ''
# decimal part
str_number = unicode(number) str_number = unicode(number)
if str_number[0] == '-': if str_number[0] == '-':
str_number = str_number[1:] str_number = str_number[1:]
# decimal part
if '.' in str_number: if '.' in str_number:
int_part, dec_part = str_number.split('.') int_part, dec_part = str_number.split('.')
if decimal_pos: if decimal_pos:
@ -30,13 +37,12 @@ def format(number, decimal_sep, decimal_pos, grouping=0, thousand_sep=''):
dec_part = dec_part + ('0' * (decimal_pos - len(dec_part))) dec_part = dec_part + ('0' * (decimal_pos - len(dec_part)))
if dec_part: dec_part = decimal_sep + dec_part if dec_part: dec_part = decimal_sep + dec_part
# grouping # grouping
if settings.USE_L10N and settings.USE_THOUSAND_SEPARATOR and grouping: if use_grouping:
int_part_gd = '' int_part_gd = ''
for cnt, digit in enumerate(int_part[::-1]): for cnt, digit in enumerate(int_part[::-1]):
if cnt and not cnt % grouping: if cnt and not cnt % grouping:
int_part_gd += thousand_sep int_part_gd += thousand_sep
int_part_gd += digit int_part_gd += digit
int_part = int_part_gd[::-1] int_part = int_part_gd[::-1]
return sign + int_part + dec_part return sign + int_part + dec_part

View File

@ -8,10 +8,11 @@ import pickle
from django.conf import settings from django.conf import settings
from django.template import Template, Context from django.template import Template, Context
from django.test import TestCase from django.test import TestCase
from django.utils.formats import get_format, date_format, time_format, localize, localize_input from django.utils.formats import get_format, date_format, time_format, localize, localize_input, iter_format_modules
from django.utils.numberformat import format as nformat from django.utils.numberformat import format as nformat
from django.utils.safestring import mark_safe, SafeString, SafeUnicode from django.utils.safestring import mark_safe, SafeString, SafeUnicode
from django.utils.translation import ugettext, ugettext_lazy, activate, deactivate, gettext_lazy, to_locale from django.utils.translation import ugettext, ugettext_lazy, activate, deactivate, gettext_lazy, to_locale
from django.utils.importlib import import_module
from forms import I18nForm, SelectDateForm, SelectDateWidget, CompanyForm from forms import I18nForm, SelectDateForm, SelectDateWidget, CompanyForm
@ -423,6 +424,24 @@ class FormattingTests(TestCase):
finally: finally:
deactivate() deactivate()
def test_iter_format_modules(self):
"""
Tests the iter_format_modules function.
"""
activate('de-at')
old_format_module_path = settings.FORMAT_MODULE_PATH
try:
settings.USE_L10N = True
de_format_mod = import_module('django.conf.locale.de.formats')
self.assertEqual(list(iter_format_modules('de')), [de_format_mod])
settings.FORMAT_MODULE_PATH = 'regressiontests.i18n.other.locale'
test_de_format_mod = import_module('regressiontests.i18n.other.locale.de.formats')
self.assertEqual(list(iter_format_modules('de')), [test_de_format_mod, de_format_mod])
finally:
settings.FORMAT_MODULE_PATH = old_format_module_path
deactivate()
class MiscTests(TestCase): class MiscTests(TestCase):
def test_parse_spec_http_header(self): def test_parse_spec_http_header(self):