Permalink
Browse files

Merged Unicode branch into trunk (r4952:5608). This should be fully

backwards compatible for all practical purposes.

Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702


git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
1 parent 4c958b1 commit 953badbea5a04159adbfa970f5805c0232b6a401 @malcolmt malcolmt committed Jul 4, 2007
Showing with 3,000 additions and 1,598 deletions.
  1. +2 −0 AUTHORS
  2. +1 −1 django/bin/make-messages.py
  3. +3 −0 django/conf/global_settings.py
  4. +8 −6 django/contrib/admin/filterspecs.py
  5. +95 −0 django/contrib/admin/media/js/urlify.js
  6. +5 −4 django/contrib/admin/models.py
  7. +1 −1 django/contrib/admin/templates/admin/filter.html
  8. +19 −16 django/contrib/admin/templatetags/admin_list.py
  9. +14 −13 django/contrib/admin/templatetags/admin_modify.py
  10. +3 −2 django/contrib/admin/templatetags/adminapplist.py
  11. +1 −0 django/contrib/admin/views/auth.py
  12. +2 −2 django/contrib/admin/views/decorators.py
  13. +1 −0 django/contrib/admin/views/doc.py
  14. +41 −33 django/contrib/admin/views/main.py
  15. +1 −1 django/contrib/auth/forms.py
  16. +2 −2 django/contrib/auth/management.py
  17. +20 −15 django/contrib/auth/models.py
  18. +1 −0 django/contrib/auth/views.py
  19. +2 −2 django/contrib/comments/feeds.py
  20. +1 −1 django/contrib/comments/models.py
  21. +5 −4 django/contrib/comments/views/comments.py
  22. +1 −0 django/contrib/comments/views/karma.py
  23. +2 −2 django/contrib/contenttypes/generic.py
  24. +2 −1 django/contrib/contenttypes/management.py
  25. +7 −6 django/contrib/contenttypes/models.py
  26. +18 −14 django/contrib/databrowse/datastructures.py
  27. +5 −4 django/contrib/databrowse/plugins/calendars.py
  28. +7 −5 django/contrib/databrowse/plugins/fieldchoices.py
  29. +1 −1 django/contrib/databrowse/sites.py
  30. +1 −1 django/contrib/databrowse/templates/databrowse/fieldchoice_list.html
  31. +3 −3 django/contrib/flatpages/models.py
  32. +9 −9 django/contrib/humanize/templatetags/humanize.py
  33. +6 −6 django/contrib/localflavor/au/forms.py
  34. +10 −10 django/contrib/localflavor/br/forms.py
  35. +1 −1 django/contrib/localflavor/ch/ch_states.py
  36. +3 −3 django/contrib/localflavor/ch/forms.py
  37. +8 −7 django/contrib/localflavor/cl/forms.py
  38. +1 −1 django/contrib/localflavor/de/de_states.py
  39. +6 −6 django/contrib/localflavor/de/forms.py
  40. +6 −6 django/contrib/localflavor/fi/forms.py
  41. +4 −4 django/contrib/localflavor/fr/forms.py
  42. +5 −4 django/contrib/localflavor/is_/forms.py
  43. +7 −7 django/contrib/localflavor/it/forms.py
  44. +1 −1 django/contrib/localflavor/it/it_province.py
  45. +15 −11 django/contrib/localflavor/it/util.py
  46. +3 −3 django/contrib/localflavor/jp/forms.py
  47. +48 −48 django/contrib/localflavor/jp/jp_prefectures.py
  48. +6 −6 django/contrib/localflavor/no/forms.py
  49. +5 −5 django/contrib/localflavor/no/no_municipalities.py
  50. +2 −2 django/contrib/localflavor/uk/forms.py
  51. +10 −10 django/contrib/localflavor/us/forms.py
  52. +8 −7 django/contrib/markup/templatetags/markup.py
  53. +3 −3 django/contrib/redirects/models.py
  54. +1 −1 django/contrib/sessions/models.py
  55. +2 −1 django/contrib/sitemaps/views.py
  56. +2 −2 django/contrib/sites/models.py
  57. +8 −5 django/contrib/syndication/feeds.py
  58. +39 −7 django/contrib/webdesign/lorem_ipsum.py
  59. +1 −1 django/contrib/webdesign/templatetags/webdesign.py
  60. +2 −2 django/contrib/webdesign/tests.py
  61. +3 −3 django/core/handlers/modpython.py
  62. +5 −5 django/core/handlers/wsgi.py
  63. +35 −6 django/core/mail.py
  64. +3 −3 django/core/management.py
  65. +8 −8 django/core/serializers/__init__.py
  66. +3 −2 django/core/serializers/base.py
  67. +22 −27 django/core/serializers/python.py
  68. +2 −2 django/core/serializers/pyyaml.py
  69. +42 −40 django/core/serializers/xml_serializer.py
  70. +17 −10 django/core/urlresolvers.py
  71. +61 −58 django/core/validators.py
  72. +1 −1 django/db/backends/mysql/base.py
  73. +2 −0 django/db/backends/mysql_old/base.py
  74. +49 −15 django/db/backends/oracle/base.py
  75. +5 −5 django/db/backends/oracle/creation.py
  76. +35 −15 django/db/backends/postgresql/base.py
  77. +4 −0 django/db/backends/postgresql_psycopg2/base.py
  78. +6 −13 django/db/backends/sqlite3/base.py
  79. +13 −6 django/db/backends/util.py
  80. +6 −3 django/db/models/base.py
  81. +27 −26 django/db/models/fields/__init__.py
  82. +6 −5 django/db/models/fields/related.py
  83. +4 −2 django/db/models/manipulators.py
  84. +19 −3 django/db/models/options.py
  85. +2 −1 django/db/models/query.py
  86. +82 −16 django/http/__init__.py
  87. +36 −36 django/newforms/fields.py
  88. +8 −8 django/newforms/forms.py
  89. +8 −6 django/newforms/models.py
  90. +9 −9 django/newforms/util.py
  91. +20 −20 django/newforms/widgets.py
  92. +91 −81 django/oldforms/__init__.py
  93. +21 −20 django/template/__init__.py
  94. +67 −72 django/template/defaultfilters.py
  95. +4 −3 django/template/defaulttags.py
  96. +1 −1 django/template/loaders/app_directories.py
  97. +1 −1 django/template/loaders/eggs.py
  98. +1 −1 django/template/loaders/filesystem.py
  99. +4 −4 django/templatetags/i18n.py
  100. +18 −15 django/test/client.py
  101. +6 −6 django/test/testcases.py
  102. +2 −2 django/test/utils.py
  103. +2 −1 django/utils/cache.py
  104. +28 −26 django/utils/dateformat.py
  105. +5 −1 django/utils/dates.py
  106. +68 −16 django/utils/encoding.py
  107. +29 −21 django/utils/feedgenerator.py
  108. +54 −1 django/utils/functional.py
  109. +25 −16 django/utils/html.py
  110. +35 −0 django/utils/http.py
  111. +1 −1 django/utils/stopwords.py
  112. +34 −20 django/utils/text.py
  113. +10 −10 django/utils/timesince.py
  114. +18 −5 django/utils/translation/__init__.py
  115. +9 −2 django/utils/translation/trans_null.py
  116. +63 −32 django/utils/translation/trans_real.py
  117. +10 −3 django/utils/tzinfo.py
  118. +13 −1 django/views/debug.py
  119. +4 −4 django/views/generic/create_update.py
  120. +1 −0 docs/contributing.txt
  121. +3 −3 docs/db-api.txt
  122. +1 −1 docs/forms.txt
  123. +128 −48 docs/i18n.txt
  124. +40 −10 docs/model-api.txt
  125. +1 −1 docs/newforms.txt
  126. +2 −2 docs/overview.txt
  127. +10 −0 docs/settings.txt
  128. +10 −0 docs/templates.txt
  129. +24 −7 docs/tutorial01.txt
  130. +363 −0 docs/unicode.txt
  131. +3 −2 tests/modeltests/basic/models.py
  132. +3 −3 tests/modeltests/choices/models.py
  133. +9 −9 tests/modeltests/custom_columns/models.py
  134. +4 −4 tests/modeltests/custom_managers/models.py
  135. +1 −1 tests/modeltests/custom_methods/models.py
  136. +5 −5 tests/modeltests/custom_pk/models.py
  137. +1 −1 tests/modeltests/field_defaults/models.py
  138. +10 −10 tests/modeltests/fixtures/models.py
  139. +8 −8 tests/modeltests/generic_relations/models.py
  140. +2 −2 tests/modeltests/get_latest/models.py
  141. +2 −2 tests/modeltests/get_object_or_404/models.py
  142. +2 −2 tests/modeltests/get_or_create/models.py
  143. +16 −16 tests/modeltests/lookup/models.py
  144. +2 −2 tests/modeltests/m2m_and_m2o/models.py
  145. +5 −5 tests/modeltests/m2m_intermediary/models.py
  146. +2 −2 tests/modeltests/m2m_multiple/models.py
  147. +1 −1 tests/modeltests/m2m_recursive/models.py
  148. +1 −1 tests/modeltests/m2o_recursive/models.py
  149. +1 −1 tests/modeltests/m2o_recursive2/models.py
  150. +8 −8 tests/modeltests/manipulators/models.py
  151. +2 −2 tests/modeltests/many_to_many/models.py
  152. +10 −5 tests/modeltests/many_to_one/models.py
  153. +2 −2 tests/modeltests/many_to_one_null/models.py
  154. +8 −8 tests/modeltests/model_forms/models.py
  155. +6 −6 tests/modeltests/model_inheritance/models.py
  156. +6 −6 tests/modeltests/one_to_one/models.py
  157. +2 −2 tests/modeltests/or_lookups/models.py
  158. +1 −1 tests/modeltests/ordering/models.py
  159. +1 −1 tests/modeltests/pagination/models.py
  160. +1 −1 tests/modeltests/reserved_names/models.py
  161. +3 −3 tests/modeltests/reverse_lookup/models.py
  162. +2 −2 tests/modeltests/save_delete_hooks/models.py
  163. +8 −8 tests/modeltests/select_related/models.py
  164. +5 −5 tests/modeltests/serializers/models.py
  165. +29 −7 tests/modeltests/str/models.py
  166. +7 −3 tests/modeltests/test_client/models.py
  167. +1 −1 tests/modeltests/test_client/views.py
  168. +3 −3 tests/modeltests/transactions/models.py
  169. +7 −7 tests/modeltests/validation/models.py
  170. +23 −23 tests/regressiontests/dateformat/tests.py
  171. +230 −216 tests/regressiontests/defaultfilters/tests.py
  172. +3 −3 tests/regressiontests/fixtures_regress/models.py
  173. +7 −7 tests/regressiontests/forms/localflavor.py
  174. +44 −5 tests/regressiontests/forms/regressions.py
  175. +1 −1 tests/regressiontests/forms/tests.py
  176. +43 −33 tests/regressiontests/httpwrappers/tests.py
  177. +5 −5 tests/regressiontests/humanize/tests.py
  178. 0 tests/regressiontests/i18n/__init__.py
  179. 0 tests/regressiontests/i18n/models.py
  180. +33 −0 tests/regressiontests/i18n/tests.py
  181. 0 tests/regressiontests/model_regress/__init__.py
  182. +34 −0 tests/regressiontests/model_regress/models.py
  183. +4 −4 tests/regressiontests/null_queries/models.py
  184. +6 −6 tests/regressiontests/one_to_one_regress/models.py
  185. +3 −0 tests/regressiontests/serializers_regress/tests.py
  186. +27 −11 tests/regressiontests/string_lookup/models.py
  187. +14 −7 tests/regressiontests/templates/tests.py
  188. +33 −0 tests/regressiontests/templates/unicode.py
  189. +2 −0 tests/regressiontests/templates/urls.py
  190. +11 −1 tests/regressiontests/test_client_regress/models.py
  191. +1 −1 tests/regressiontests/test_client_regress/urls.py
  192. +13 −1 tests/regressiontests/test_client_regress/views.py
  193. +26 −5 tests/regressiontests/text/tests.py
View
@@ -113,6 +113,7 @@ answer newbie questions, and generally made Django that much better:
Simon Greenhill <dev@simon.net.nz>
Owen Griffiths
Espen Grindhaug <http://grindhaug.org/>
+ Thomas Güttler <hv@tbz-pariv.de>
Brian Harring <ferringb@gmail.com>
Brant Harris
Hawkeye
@@ -147,6 +148,7 @@ answer newbie questions, and generally made Django that much better:
Bruce Kroeze <http://coderseye.com/>
Joseph Kocherhans
konrad@gwu.edu
+ kurtiss@meetro.com
lakin.wecker@gmail.com
Nick Lane <nick.lane.au@gmail.com>
Stuart Langridge <http://www.kryogenix.org/>
@@ -103,7 +103,7 @@ def make_messages():
open(os.path.join(dirpath, '%s.py' % file), "wb").write(templatize(src))
thefile = '%s.py' % file
if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
- cmd = 'xgettext %s -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
+ cmd = 'xgettext %s -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile))
(stdin, stdout, stderr) = os.popen3(cmd, 'b')
msgs = stdout.read()
@@ -97,6 +97,9 @@
DEFAULT_CONTENT_TYPE = 'text/html'
DEFAULT_CHARSET = 'utf-8'
+# Encoding of files read from disk (template and initial SQL files).
+FILE_CHARSET = 'utf-8'
+
# E-mail address that error messages come from.
SERVER_EMAIL = 'root@localhost'
@@ -7,6 +7,8 @@
"""
from django.db import models
+from django.utils.encoding import smart_unicode, iri_to_uri
+from django.utils.translation import ugettext as _
import datetime
class FilterSpec(object):
@@ -37,12 +39,12 @@ def title(self):
def output(self, cl):
t = []
if self.has_output():
- t.append(_('<h3>By %s:</h3>\n<ul>\n') % self.title())
+ t.append(_(u'<h3>By %s:</h3>\n<ul>\n') % self.title())
for choice in self.choices(cl):
- t.append('<li%s><a href="%s">%s</a></li>\n' % \
+ t.append(u'<li%s><a href="%s">%s</a></li>\n' % \
((choice['selected'] and ' class="selected"' or ''),
- choice['query_string'] ,
+ iri_to_uri(choice['query_string']),
choice['display']))
t.append('</ul>\n\n')
return "".join(t)
@@ -70,7 +72,7 @@ def choices(self, cl):
'display': _('All')}
for val in self.lookup_choices:
pk_val = getattr(val, self.field.rel.to._meta.pk.attname)
- yield {'selected': self.lookup_val == str(pk_val),
+ yield {'selected': self.lookup_val == smart_unicode(pk_val),
'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}),
'display': val}
@@ -87,7 +89,7 @@ def choices(self, cl):
'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
'display': _('All')}
for k, v in self.field.choices:
- yield {'selected': str(k) == self.lookup_val,
+ yield {'selected': smart_unicode(k) == self.lookup_val,
'query_string': cl.get_query_string({self.lookup_kwarg: k}),
'display': v}
@@ -168,7 +170,7 @@ def choices(self, cl):
'query_string': cl.get_query_string({}, [self.field.name]),
'display': _('All')}
for val in self.lookup_choices:
- val = str(val[self.field.name])
+ val = smart_unicode(val[self.field.name])
yield {'selected': self.lookup_val == val,
'query_string': cl.get_query_string({self.field.name: val}),
'display': val}
@@ -1,15 +1,110 @@
+var LATIN_MAP =
+{
+ 'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE', 'Ç':
+ 'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', 'Î': 'I',
+ 'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', 'Õ': 'O', 'Ö':
+ 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', 'Ü': 'U', 'Ý': 'Y', 'Þ': 'TH',
+ 'ß': 'ss', 'à':'a', 'á':'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', 'æ':
+ 'ae', 'ç': 'c', 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'í': 'i',
+ 'î': 'i', 'ï': 'i', 'ð': 'o', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ':
+ 'o', 'ö': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u', 'ý': 'y',
+ 'þ': 'th', 'ÿ': 'y',
+}
+var LATIN_SYMBOLS_MAP =
+{
+ '©':'(c)',
+}
+var GREEK_MAP =
+{
+ 'α':'a', 'β':'b', 'γ':'g', 'δ':'d', 'ε':'e', 'ζ':'z', 'η':'h', 'θ':'8',
+ 'ι':'i', 'κ':'k', 'λ':'l', 'μ':'m', 'ν':'n', 'ξ':'3', 'ο':'o', 'π':'p',
+ 'ρ':'r', 'σ':'s', 'τ':'t', 'υ':'y', 'φ':'f', 'χ':'x', 'ψ':'ps', 'ω':'w',
+ 'ά':'a', 'έ':'e', 'ί':'i', 'ό':'o', 'ύ':'y', 'ή':'h', 'ώ':'w', 'ς':'s',
+ 'ϊ':'i', 'ΰ':'y', 'ϋ':'y', 'ΐ':'i',
+ 'Α':'A', 'Β':'B', 'Γ':'G', 'Δ':'D', 'Ε':'E', 'Ζ':'Z', 'Η':'H', 'Θ':'8',
+ 'Ι':'I', 'Κ':'K', 'Λ':'L', 'Μ':'M', 'Ν':'N', 'Ξ':'3', 'Ο':'O', 'Π':'P',
+ 'Ρ':'R', 'Σ':'S', 'Τ':'T', 'Υ':'Y', 'Φ':'F', 'Χ':'X', 'Ψ':'PS', 'Ω':'W',
+ 'Ά':'A', 'Έ':'E', 'Ί':'I', 'Ό':'O', 'Ύ':'Y', 'Ή':'H', 'Ώ':'W', 'Ϊ':'I',
+ 'Ϋ':'Y'
+}
+var TURKISH_MAP = {
+ 'ş':'s', 'Ş':'S', 'ı':'i', 'İ':'I', 'ç':'c', 'Ç':'C', 'ü':'u', 'Ü':'U',
+ 'ö':'o', 'Ö':'O', 'ğ':'g', 'Ğ':'G',
+}
+// var RUSSIAN_MAP =
+// {
+// }
+
+var ALL_DOWNCODE_MAPS=new Array()
+ALL_DOWNCODE_MAPS[0]=LATIN_MAP
+ALL_DOWNCODE_MAPS[1]=LATIN_SYMBOLS_MAP
+ALL_DOWNCODE_MAPS[2]=GREEK_MAP
+ALL_DOWNCODE_MAPS[3]=TURKISH_MAP
+//ALL_DOWNCODE_MAPS[4]=RUSSIAN_MAP
+
+var Downcoder = new Object();
+Downcoder.Initialize = function()
+{
+ if (Downcoder.map) // already made
+ return ;
+ Downcoder.map ={}
+ Downcoder.chars = '' ;
+ for(var i in ALL_DOWNCODE_MAPS)
+ {
+ var lookup = ALL_DOWNCODE_MAPS[i]
+ for (var c in lookup)
+ {
+ Downcoder.map[c] = lookup[c] ;
+ Downcoder.chars += c ;
+ }
+ }
+ Downcoder.regex = new RegExp('[' + Downcoder.chars + ']|[^' + Downcoder.chars + ']+','g') ;
+}
+
+downcode= function( slug )
+{
+ Downcoder.Initialize() ;
+ var downcoded =""
+ var pieces = slug.match(Downcoder.regex);
+ if(pieces)
+ {
+ for (var i = 0 ; i < pieces.length ; i++)
+ {
+ if (pieces[i].length == 1)
+ {
+ var mapped = Downcoder.map[pieces[i]] ;
+ if (mapped != null)
+ {
+ downcoded+=mapped;
+ continue ;
+ }
+ }
+ downcoded+=pieces[i];
+ }
+ }
+ else
+ {
+ downcoded = slug;
+ }
+ return downcoded;
+}
+
+
function URLify(s, num_chars) {
// changes, e.g., "Petty theft" to "petty_theft"
// remove all these words from the string before urlifying
+ s = downcode(s);
removelist = ["a", "an", "as", "at", "before", "but", "by", "for", "from",
"is", "in", "into", "like", "of", "off", "on", "onto", "per",
"since", "than", "the", "this", "that", "to", "up", "via",
"with"];
r = new RegExp('\\b(' + removelist.join('|') + ')\\b', 'gi');
s = s.replace(r, '');
+ // if downcode doesn't hit, the char will be stripped here
s = s.replace(/[^-\w\s]/g, ''); // remove unneeded chars
s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces
s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens
s = s.toLowerCase(); // convert to lowercase
return s.substring(0, num_chars);// trim to first num_chars chars
}
+
@@ -1,15 +1,16 @@
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import ugettext_lazy as _
+from django.utils.encoding import smart_unicode
ADDITION = 1
CHANGE = 2
DELETION = 3
class LogEntryManager(models.Manager):
def log_action(self, user_id, content_type_id, object_id, object_repr, action_flag, change_message=''):
- e = self.model(None, None, user_id, content_type_id, str(object_id), object_repr[:200], action_flag, change_message)
+ e = self.model(None, None, user_id, content_type_id, smart_unicode(object_id), object_repr[:200], action_flag, change_message)
e.save()
class LogEntry(models.Model):
@@ -28,7 +29,7 @@ class Meta:
ordering = ('-action_time',)
def __repr__(self):
- return str(self.action_time)
+ return smart_unicode(self.action_time)
def is_addition(self):
return self.action_flag == ADDITION
@@ -48,4 +49,4 @@ def get_admin_url(self):
Returns the admin URL to edit the object represented by this log entry.
This is relative to the Django admin index page.
"""
- return "%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, self.object_id)
+ return u"%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, self.object_id)
@@ -3,6 +3,6 @@ <h3>{% blocktrans with title|escape as filter_title %} By {{ filter_title }} {%
<ul>
{% for choice in choices %}
<li{% if choice.selected %} class="selected"{% endif %}>
- <a href="{{ choice.query_string }}">{{ choice.display|escape }}</a></li>
+ <a href="{{ choice.query_string|iriencode }}">{{ choice.display|escape }}</a></li>
{% endfor %}
</ul>
@@ -6,7 +6,8 @@
from django.utils import dateformat
from django.utils.html import escape
from django.utils.text import capfirst
-from django.utils.translation import get_date_formats, get_partial_date_formats
+from django.utils.translation import get_date_formats, get_partial_date_formats, ugettext as _
+from django.utils.encoding import smart_unicode, smart_str, force_unicode
from django.template import Library
import datetime
@@ -16,11 +17,11 @@
def paginator_number(cl,i):
if i == DOT:
- return '... '
+ return u'... '
elif i == cl.page_num:
- return '<span class="this-page">%d</span> ' % (i+1)
+ return u'<span class="this-page">%d</span> ' % (i+1)
else:
- return '<a href="%s"%s>%d</a> ' % (cl.get_query_string({PAGE_VAR: i}), (i == cl.paginator.pages-1 and ' class="end"' or ''), i+1)
+ return u'<a href="%s"%s>%d</a> ' % (cl.get_query_string({PAGE_VAR: i}), (i == cl.paginator.pages-1 and ' class="end"' or ''), i+1)
paginator_number = register.simple_tag(paginator_number)
def pagination(cl):
@@ -75,10 +76,12 @@ def result_headers(cl):
admin_order_field = None
except models.FieldDoesNotExist:
# For non-field list_display values, check for the function
- # attribute "short_description". If that doesn't exist, fall
- # back to the method name. And __str__ is a special-case.
- if field_name == '__str__':
- header = lookup_opts.verbose_name
+ # attribute "short_description". If that doesn't exist, fall back
+ # to the method name. And __str__ and __unicode__ are special-cases.
+ if field_name == '__unicode__':
+ header = force_unicode(lookup_opts.verbose_name)
+ elif field_name == '__str__':
+ header = smart_str(lookup_opts.verbose_name)
else:
attr = getattr(cl.model, field_name) # Let AttributeErrors propagate.
try:
@@ -114,7 +117,7 @@ def result_headers(cl):
def _boolean_icon(field_val):
BOOLEAN_MAPPING = {True: 'yes', False: 'no', None: 'unknown'}
- return '<img src="%simg/admin/icon-%s.gif" alt="%s" />' % (settings.ADMIN_MEDIA_PREFIX, BOOLEAN_MAPPING[field_val], field_val)
+ return u'<img src="%simg/admin/icon-%s.gif" alt="%s" />' % (settings.ADMIN_MEDIA_PREFIX, BOOLEAN_MAPPING[field_val], field_val)
def items_for_result(cl, result):
first = True
@@ -136,7 +139,7 @@ def items_for_result(cl, result):
allow_tags = True
result_repr = _boolean_icon(attr)
else:
- result_repr = str(attr)
+ result_repr = smart_unicode(attr)
except (AttributeError, ObjectDoesNotExist):
result_repr = EMPTY_CHANGELIST_VALUE
else:
@@ -179,19 +182,19 @@ def items_for_result(cl, result):
elif f.choices:
result_repr = dict(f.choices).get(field_val, EMPTY_CHANGELIST_VALUE)
else:
- result_repr = escape(str(field_val))
- if result_repr == '':
+ result_repr = escape(field_val)
+ if force_unicode(result_repr) == '':
result_repr = '&nbsp;'
# If list_display_links not defined, add the link tag to the first field
- if (first and not cl.lookup_opts.admin.list_display_links) or field_name in cl.lookup_opts.admin.list_display_links:
+ if (first and not cl.lookup_opts.admin.list_display_links) or field_name in cl.lookup_opts.admin.list_display_links:
table_tag = {True:'th', False:'td'}[first]
first = False
url = cl.url_for_result(result)
- result_id = str(getattr(result, pk)) # str() is needed in case of 23L (long ints)
- yield ('<%s%s><a href="%s"%s>%s</a></%s>' % \
+ result_id = smart_unicode(getattr(result, pk)) # conversion to string is needed in case of 23L (long ints)
+ yield (u'<%s%s><a href="%s"%s>%s</a></%s>' % \
(table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %r); return false;"' % result_id or ''), result_repr, table_tag))
else:
- yield ('<td%s>%s</td>' % (row_class, result_repr))
+ yield (u'<td%s>%s</td>' % (row_class, result_repr))
def results(cl):
for res in cl.result_list:
Oops, something went wrong.

0 comments on commit 953badb

Please sign in to comment.