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): |