diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index 8329792..9235a67 100644
|
a
|
b
|
signals.class_prepared.connect(do_pending_lookups)
|
| 87 | 87 | class RelatedField(object): |
| 88 | 88 | def contribute_to_class(self, cls, name): |
| 89 | 89 | sup = super(RelatedField, self) |
| 90 | | |
| 91 | | # Add an accessor to allow easy determination of the related query path for this field |
| 92 | | self.related_query_name = curry(self._get_related_query_name, cls._meta) |
| | 90 | |
| | 91 | # Store the opts for related_query_name() |
| | 92 | self.opts = cls._meta |
| 93 | 93 | |
| 94 | 94 | if hasattr(sup, 'contribute_to_class'): |
| 95 | 95 | sup.contribute_to_class(cls, name) |
| … |
… |
class RelatedField(object):
|
| 174 | 174 | return [] |
| 175 | 175 | raise TypeError("Related Field has invalid lookup: %s" % lookup_type) |
| 176 | 176 | |
| 177 | | def _get_related_query_name(self, opts): |
| | 177 | def related_query_name(self): |
| 178 | 178 | # This method defines the name that can be used to identify this |
| 179 | 179 | # related object in a table-spanning query. It uses the lower-cased |
| 180 | 180 | # object_name by default, but this can be overridden with the |
| 181 | 181 | # "related_name" option. |
| 182 | | return self.rel.related_name or opts.object_name.lower() |
| | 182 | return self.rel.related_name or self.opts.object_name.lower() |
| 183 | 183 | |
| 184 | 184 | class SingleRelatedObjectDescriptor(object): |
| 185 | 185 | # This class provides the functionality that makes the related-object |
diff --git a/django/utils/functional.py b/django/utils/functional.py
index e52ab76..6482e44 100644
|
a
|
b
|
def lazy(func, *resultclasses):
|
| 147 | 147 | the lazy evaluation code is triggered. Results are not memoized; the |
| 148 | 148 | function is evaluated on every access. |
| 149 | 149 | """ |
| | 150 | if len(resultclasses) == 1 and isinstance(resultclasses[0], tuple): |
| | 151 | resultclasses = resultclasses[0] |
| | 152 | |
| 150 | 153 | class __proxy__(Promise): |
| 151 | 154 | """ |
| 152 | 155 | Encapsulate a function call and act as a proxy for methods that are |
| … |
… |
def lazy(func, *resultclasses):
|
| 161 | 164 | self.__kw = kw |
| 162 | 165 | if self.__dispatch is None: |
| 163 | 166 | self.__prepare_class__() |
| 164 | | |
| | 167 | |
| | 168 | def __reduce_ex__(self, protocol): |
| | 169 | return (lazy, (self.__func, resultclasses), self.__dict__) |
| | 170 | |
| 165 | 171 | def __prepare_class__(cls): |
| 166 | 172 | cls.__dispatch = {} |
| 167 | 173 | for resultclass in resultclasses: |
diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py
index c0a0df9..da1c938 100644
|
a
|
b
|
|
| 1 | 1 | """ |
| 2 | 2 | Internationalization support. |
| 3 | 3 | """ |
| 4 | | from django.utils.functional import lazy |
| | 4 | from django.utils.functional import lazy, curry |
| 5 | 5 | from django.utils.encoding import force_unicode |
| 6 | 6 | |
| 7 | 7 | __all__ = ['gettext', 'gettext_noop', 'gettext_lazy', 'ngettext', |
| … |
… |
__all__ = ['gettext', 'gettext_noop', 'gettext_lazy', 'ngettext',
|
| 19 | 19 | # replace the functions with their real counterparts (once we do access the |
| 20 | 20 | # settings). |
| 21 | 21 | |
| 22 | | def delayed_loader(*args, **kwargs): |
| | 22 | def delayed_loader(real_name, *args, **kwargs): |
| 23 | 23 | """ |
| 24 | 24 | Replace each real_* function with the corresponding function from either |
| 25 | 25 | trans_real or trans_null (e.g. real_gettext is replaced with |
| … |
… |
def delayed_loader(*args, **kwargs):
|
| 27 | 27 | first time any i18n method is called. It replaces all the i18n methods at |
| 28 | 28 | once at that time. |
| 29 | 29 | """ |
| 30 | | import traceback |
| 31 | 30 | from django.conf import settings |
| | 31 | |
| 32 | 32 | if settings.USE_I18N: |
| 33 | | import trans_real as trans |
| | 33 | import django.utils.translation.trans_real as trans |
| 34 | 34 | else: |
| 35 | | import trans_null as trans |
| 36 | | caller = traceback.extract_stack(limit=2)[0][2] |
| 37 | | g = globals() |
| 38 | | for name in __all__: |
| 39 | | if hasattr(trans, name): |
| 40 | | g['real_%s' % name] = getattr(trans, name) |
| | 35 | import django.utils.translation.trans_null as trans |
| 41 | 36 | |
| 42 | 37 | # Make the originally requested function call on the way out the door. |
| 43 | | return g['real_%s' % caller](*args, **kwargs) |
| | 38 | return getattr(trans, real_name)(*args, **kwargs) |
| 44 | 39 | |
| 45 | 40 | g = globals() |
| 46 | 41 | for name in __all__: |
| 47 | | g['real_%s' % name] = delayed_loader |
| | 42 | g['real_%s' % name] = curry(delayed_loader, name) |
| 48 | 43 | del g, delayed_loader |
| 49 | 44 | |
| 50 | 45 | def gettext_noop(message): |
| … |
… |
def templatize(src):
|
| 102 | 97 | def deactivate_all(): |
| 103 | 98 | return real_deactivate_all() |
| 104 | 99 | |
| 105 | | def string_concat(*strings): |
| | 100 | def _string_concat(*strings): |
| 106 | 101 | """ |
| 107 | 102 | Lazy variant of string concatenation, needed for translations that are |
| 108 | 103 | constructed from multiple parts. |
| 109 | 104 | """ |
| 110 | 105 | return u''.join([force_unicode(s) for s in strings]) |
| 111 | | string_concat = lazy(string_concat, unicode) |
| | 106 | string_concat = lazy(_string_concat, unicode) |
diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
index 31150a6..941f66f 100644
|
a
|
b
|
class TranslationTests(TestCase):
|
| 46 | 46 | unicode(string_concat(...)) should not raise a TypeError - #4796 |
| 47 | 47 | """ |
| 48 | 48 | import django.utils.translation |
| 49 | | self.assertEqual(django.utils.translation, reload(django.utils.translation)) |
| 50 | 49 | self.assertEqual(u'django', unicode(django.utils.translation.string_concat("dja", "ngo"))) |
| 51 | 50 | |
| 52 | 51 | def test_safe_status(self): |