Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

unicode: Fixed a number of problems where lazily translated objects w…

…ere not

being converted back to unicode strings correctly. Fixed #4359 and #4361.


git-svn-id: http://code.djangoproject.com/svn/django/branches/unicode@5320 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit b25f6e9526ba3ccbdbe3c4f0d78813e9412a7acf 1 parent d72f630
Malcolm Tredinnick authored May 23, 2007
2  django/contrib/admin/templatetags/admin_list.py
@@ -78,7 +78,7 @@ def result_headers(cl):
78 78
             # attribute "short_description". If that doesn't exist, fall back
79 79
             # to the method name. And __str__ and __unicode__ are special-cases.
80 80
             if field_name == '__unicode__':
81  
-                header = smart_unicode(lookup_opts.verbose_name)
  81
+                header = force_unicode(lookup_opts.verbose_name)
82 82
             elif field_name == '__str__':
83 83
                 header = smart_str(lookup_opts.verbose_name)
84 84
             else:
32  django/contrib/admin/views/main.py
@@ -12,7 +12,7 @@
12 12
 from django.http import Http404, HttpResponse, HttpResponseRedirect
13 13
 from django.utils.html import escape
14 14
 from django.utils.text import capfirst, get_text_list
15  
-from django.utils.encoding import smart_unicode, smart_str
  15
+from django.utils.encoding import force_unicode, smart_str
16 16
 from django.utils.translation import ugettext as _
17 17
 import operator
18 18
 
@@ -127,11 +127,11 @@ def __init__(self, field, field_mapping, original):
127 127
         if max([bool(f.errors()) for f in self.form_fields]):
128 128
             classes.append('error')
129 129
         if classes:
130  
-            self.cell_class_attribute = ' class="%s" ' % ' '.join(classes)
  130
+            self.cell_class_attribute = u' class="%s" ' % ' '.join(classes)
131 131
         self._repr_filled = False
132 132
 
133 133
         if field.rel:
134  
-            self.related_url = '../../../%s/%s/' % (field.rel.to._meta.app_label, field.rel.to._meta.object_name.lower())
  134
+            self.related_url = u'../../../%s/%s/' % (field.rel.to._meta.app_label, field.rel.to._meta.object_name.lower())
135 135
 
136 136
     def original_value(self):
137 137
         if self.original:
@@ -144,7 +144,7 @@ def existing_display(self):
144 144
             if isinstance(self.field.rel, models.ManyToOneRel):
145 145
                 self._display = getattr(self.original, self.field.name)
146 146
             elif isinstance(self.field.rel, models.ManyToManyRel):
147  
-                self._display = u", ".join([smart_unicode(obj) for obj in getattr(self.original, self.field.name).all()])
  147
+                self._display = u", ".join([force_unicode(obj) for obj in getattr(self.original, self.field.name).all()])
148 148
             return self._display
149 149
 
150 150
     def __repr__(self):
@@ -255,7 +255,7 @@ def add_stage(request, app_label, model_name, show_delete=False, form_url='', po
255 255
         if not errors:
256 256
             new_object = manipulator.save(new_data)
257 257
             pk_value = new_object._get_pk_val()
258  
-            LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, smart_unicode(new_object), ADDITION)
  258
+            LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, force_unicode(new_object), ADDITION)
259 259
             msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object}
260 260
             # Here, we distinguish between different save types by checking for
261 261
             # the presence of keys in request.POST.
@@ -268,7 +268,7 @@ def add_stage(request, app_label, model_name, show_delete=False, form_url='', po
268 268
                 if type(pk_value) is str: # Quote if string, so JavaScript doesn't think it's a variable.
269 269
                     pk_value = '"%s"' % pk_value.replace('"', '\\"')
270 270
                 return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \
271  
-                    (pk_value, smart_unicode(new_object).replace('"', '\\"')))
  271
+                    (pk_value, force_unicode(new_object).replace('"', '\\"')))
272 272
             elif "_addanother" in request.POST:
273 273
                 request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
274 274
                 return HttpResponseRedirect(request.path)
@@ -342,7 +342,7 @@ def change_stage(request, app_label, model_name, object_id):
342 342
             change_message = ' '.join(change_message)
343 343
             if not change_message:
344 344
                 change_message = _('No fields changed.')
345  
-            LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, smart_unicode(new_object), CHANGE, change_message)
  345
+            LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, force_unicode(new_object), CHANGE, change_message)
346 346
 
347 347
             msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object}
348 348
             if "_continue" in request.POST:
@@ -431,10 +431,10 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
431 431
                 if related.field.rel.edit_inline or not related.opts.admin:
432 432
                     # Don't display link to edit, because it either has no
433 433
                     # admin or is edited inline.
434  
-                    nh(deleted_objects, current_depth, ['%s: %s' % (capfirst(related.opts.verbose_name), sub_obj), []])
  434
+                    nh(deleted_objects, current_depth, [u'%s: %s' % (capfirst(related.opts.verbose_name), sub_obj), []])
435 435
                 else:
436 436
                     # Display a link to the admin page.
437  
-                    nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
  437
+                    nh(deleted_objects, current_depth, [u'%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
438 438
                         (capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.object_name.lower(),
439 439
                         sub_obj._get_pk_val(), sub_obj), []])
440 440
                 _get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2)
@@ -445,10 +445,10 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
445 445
                 if related.field.rel.edit_inline or not related.opts.admin:
446 446
                     # Don't display link to edit, because it either has no
447 447
                     # admin or is edited inline.
448  
-                    nh(deleted_objects, current_depth, ['%s: %s' % (capfirst(related.opts.verbose_name), escape(sub_obj)), []])
  448
+                    nh(deleted_objects, current_depth, [u'%s: %s' % (capfirst(related.opts.verbose_name), escape(sub_obj)), []])
449 449
                 else:
450 450
                     # Display a link to the admin page.
451  
-                    nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
  451
+                    nh(deleted_objects, current_depth, [u'%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
452 452
                         (capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.object_name.lower(), sub_obj._get_pk_val(), escape(sub_obj)), []])
453 453
                 _get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2)
454 454
             # If there were related objects, and the user doesn't have
@@ -481,12 +481,12 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
481 481
                     # Display a link to the admin page.
482 482
                     nh(deleted_objects, current_depth, [
483 483
                         (_('One or more %(fieldname)s in %(name)s:') % {'fieldname': related.field.verbose_name, 'name':related.opts.verbose_name}) + \
484  
-                        (' <a href="../../../../%s/%s/%s/">%s</a>' % \
  484
+                        (u' <a href="../../../../%s/%s/%s/">%s</a>' % \
485 485
                             (related.opts.app_label, related.opts.module_name, sub_obj._get_pk_val(), escape(sub_obj))), []])
486 486
         # If there were related objects, and the user doesn't have
487 487
         # permission to change them, add the missing perm to perms_needed.
488 488
         if related.opts.admin and has_related_objs:
489  
-            p = '%s.%s' % (related.opts.app_label, related.opts.get_change_permission())
  489
+            p = u'%s.%s' % (related.opts.app_label, related.opts.get_change_permission())
490 490
             if not user.has_perm(p):
491 491
                 perms_needed.add(related.opts.verbose_name)
492 492
 
@@ -503,14 +503,14 @@ def delete_stage(request, app_label, model_name, object_id):
503 503
 
504 504
     # Populate deleted_objects, a data structure of all related objects that
505 505
     # will also be deleted.
506  
-    deleted_objects = ['%s: <a href="../../%s/">%s</a>' % (capfirst(opts.verbose_name), object_id, escape(obj)), []]
  506
+    deleted_objects = [u'%s: <a href="../../%s/">%s</a>' % (capfirst(opts.verbose_name), object_id, escape(obj)), []]
507 507
     perms_needed = sets.Set()
508 508
     _get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1)
509 509
 
510 510
     if request.POST: # The user has already confirmed the deletion.
511 511
         if perms_needed:
512 512
             raise PermissionDenied
513  
-        obj_display = smart_unicode(obj)
  513
+        obj_display = force_unicode(obj)
514 514
         obj.delete()
515 515
         LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, object_id, obj_display, DELETION)
516 516
         request.user.message_set.create(message=_('The %(name)s "%(obj)s" was deleted successfully.') % {'name': opts.verbose_name, 'obj': obj_display})
@@ -600,7 +600,7 @@ def get_query_string(self, new_params=None, remove=None):
600 600
                 del p[k]
601 601
             elif v is not None:
602 602
                 p[k] = v
603  
-        return '?' + '&amp;'.join(['%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20')
  603
+        return '?' + '&amp;'.join([u'%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20')
604 604
 
605 605
     def get_results(self, request):
606 606
         paginator = ObjectPaginator(self.query_set, self.lookup_opts.admin.list_per_page)
4  django/contrib/auth/models.py
@@ -3,7 +3,7 @@
3 3
 from django.db import backend, connection, models
4 4
 from django.contrib.contenttypes.models import ContentType
5 5
 from django.utils.encoding import smart_str
6  
-from django.utils.translation import ugettext_lazy, ugettext as _
  6
+from django.utils.translation import ugettext_lazy as _
7 7
 import datetime
8 8
 import urllib
9 9
 
@@ -281,7 +281,7 @@ def __init__(self):
281 281
         pass
282 282
 
283 283
     def __unicode__(self):
284  
-        return ugettext_lazy('AnonymousUser')
  284
+        return _('AnonymousUser')
285 285
 
286 286
     def __eq__(self, other):
287 287
         return isinstance(other, self.__class__)
6  django/db/models/base.py
@@ -12,7 +12,7 @@
12 12
 from django.dispatch import dispatcher
13 13
 from django.utils.datastructures import SortedDict
14 14
 from django.utils.functional import curry
15  
-from django.utils.encoding import smart_str
  15
+from django.utils.encoding import smart_str, force_unicode
16 16
 from django.conf import settings
17 17
 from itertools import izip
18 18
 import types
@@ -88,7 +88,7 @@ def __repr__(self):
88 88
 
89 89
     def __str__(self):
90 90
         if hasattr(self, '__unicode__'):
91  
-            return unicode(self).encode('utf-8')
  91
+            return force_unicode(self).encode('utf-8')
92 92
         return '%s object' % self.__class__.__name__
93 93
 
94 94
     def __eq__(self, other):
@@ -320,7 +320,7 @@ def delete(self):
320 320
 
321 321
     def _get_FIELD_display(self, field):
322 322
         value = getattr(self, field.attname)
323  
-        return dict(field.choices).get(value, value)
  323
+        return force_unicode(dict(field.choices).get(value, value))
324 324
 
325 325
     def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs):
326 326
         op = is_next and '>' or '<'
2  django/db/models/options.py
@@ -215,7 +215,7 @@ def __init__(self, fields=None, js=None, list_display=None, list_display_links=N
215 215
         save_on_top=False, list_select_related=False, manager=None, list_per_page=100):
216 216
         self.fields = fields
217 217
         self.js = js or []
218  
-        self.list_display = list_display or ['__str__']
  218
+        self.list_display = list_display or ['__unicode__']
219 219
         self.list_display_links = list_display_links or []
220 220
         self.list_filter = list_filter or []
221 221
         self.date_hierarchy = date_hierarchy
6  django/template/__init__.py
@@ -58,9 +58,9 @@
58 58
 from inspect import getargspec
59 59
 from django.conf import settings
60 60
 from django.template.context import Context, RequestContext, ContextPopException
61  
-from django.utils.functional import curry
  61
+from django.utils.functional import curry, Promise
62 62
 from django.utils.text import smart_split
63  
-from django.utils.encoding import smart_unicode, smart_str
  63
+from django.utils.encoding import smart_unicode, smart_str, force_unicode
64 64
 from django.utils.translation import ugettext as _
65 65
 
66 66
 __all__ = ('Template', 'Context', 'RequestContext', 'compile_string')
@@ -705,6 +705,8 @@ def resolve_variable(path, context):
705 705
                     else:
706 706
                         raise
707 707
             del bits[0]
  708
+    if isinstance(current, (basestring, Promise)):
  709
+        current = force_unicode(current)
708 710
     return current
709 711
 
710 712
 class Node(object):
4  tests/modeltests/choices/models.py
@@ -33,7 +33,7 @@ def __str__(self):
33 33
 >>> s.gender
34 34
 'F'
35 35
 >>> a.get_gender_display()
36  
-'Male'
  36
+u'Male'
37 37
 >>> s.get_gender_display()
38  
-'Female'
  38
+u'Female'
39 39
 """}
57  tests/regressiontests/invalid_admin_options/models.py
@@ -123,6 +123,9 @@ class ListFilterBadOne(models.Model):
123 123
     class Admin:
124 124
         list_filter = 'first_name'     
125 125
 
  126
+    def __unicode__(self):
  127
+        return self.first_name
  128
+
126 129
 model_errors += """invalid_admin_options.listfilterbadone: "admin.list_filter", if given, must be set to a list or tuple.
127 130
 """
128 131
 
@@ -140,6 +143,9 @@ def full_name(self):
140 143
     class Admin:
141 144
         list_filter = ['first_name','last_name','full_name']
142 145
 
  146
+    def __unicode__(self):
  147
+        return self.first_name
  148
+
143 149
 model_errors += """invalid_admin_options.listfilterbadtwo: "admin.list_filter" refers to 'last_name', which isn't a field.
144 150
 invalid_admin_options.listfilterbadtwo: "admin.list_filter" refers to 'full_name', which isn't a field.
145 151
 """
@@ -151,7 +157,10 @@ class DateHierarchyBadOne(models.Model):
151 157
     
152 158
     class Admin:
153 159
         date_hierarchy = 'first_name'
154  
-        
  160
+
  161
+    def __unicode__(self):
  162
+        return self.first_name
  163
+
155 164
 # TODO: Date Hierarchy needs to check if field is a date/datetime field.
156 165
 #model_errors += """invalid_admin_options.datehierarchybadone: "admin.date_hierarchy" refers to 'first_name', which isn't a date field or datetime field.
157 166
 #"""
@@ -164,6 +173,9 @@ class DateHierarchyBadTwo(models.Model):
164 173
     class Admin:
165 174
         date_hierarchy = 'nonexistent'          
166 175
 
  176
+    def __unicode__(self):
  177
+        return self.first_name
  178
+
167 179
 model_errors += """invalid_admin_options.datehierarchybadtwo: "admin.date_hierarchy" refers to 'nonexistent', which isn't a field.
168 180
 """
169 181
 
@@ -174,6 +186,9 @@ class DateHierarchyGood(models.Model):
174 186
     
175 187
     class Admin:
176 188
         date_hierarchy = 'birth_day' 
  189
+
  190
+    def __unicode__(self):
  191
+        return self.first_name
177 192
       
178 193
 class SearchFieldsBadOne(models.Model):
179 194
     "Test search_fields, must be a list or tuple."
@@ -182,6 +197,9 @@ class SearchFieldsBadOne(models.Model):
182 197
     class Admin:
183 198
         search_fields = ('nonexistent')         
184 199
 
  200
+    def __unicode__(self):
  201
+        return self.first_name
  202
+
185 203
 # TODO: Add search_fields validation
186 204
 #model_errors += """invalid_admin_options.seacrhfieldsbadone: "admin.search_fields", if given, must be set to a list or tuple.
187 205
 #"""
@@ -197,6 +215,9 @@ def _last_name(self):
197 215
     class Admin:
198 216
         search_fields = ['first_name','last_name']         
199 217
 
  218
+    def __unicode__(self):
  219
+        return self.first_name
  220
+
200 221
 # TODO: Add search_fields validation
201 222
 #model_errors += """invalid_admin_options.seacrhfieldsbadone: "admin.search_fields" refers to 'last_name', which isn't a field.
202 223
 #"""
@@ -209,6 +230,8 @@ class SearchFieldsGood(models.Model):
209 230
     class Admin:
210 231
         search_fields = ['first_name','last_name']
211 232
 
  233
+    def __unicode__(self):
  234
+        return self.first_name
212 235
 
213 236
 class JsBadOne(models.Model):
214 237
     "Test js, must be a list or tuple"
@@ -216,6 +239,9 @@ class JsBadOne(models.Model):
216 239
     
217 240
     class Admin:
218 241
         js = 'test.js'
  242
+
  243
+    def __unicode__(self):
  244
+        return self.name
219 245
         
220 246
 # TODO: Add a js validator
221 247
 #model_errors += """invalid_admin_options.jsbadone: "admin.js", if given, must be set to a list or tuple.
@@ -228,6 +254,9 @@ class SaveAsBad(models.Model):
228 254
     class Admin:
229 255
         save_as = 'not True or False'
230 256
 
  257
+    def __unicode__(self):
  258
+        return self.name
  259
+
231 260
 # TODO: Add a save_as validator.       
232 261
 #model_errors += """invalid_admin_options.saveasbad: "admin.save_as", if given, must be set to True or False.
233 262
 #"""
@@ -239,6 +268,9 @@ class SaveOnTopBad(models.Model):
239 268
     class Admin:
240 269
         save_on_top = 'not True or False'
241 270
 
  271
+    def __unicode__(self):
  272
+        return self.name
  273
+
242 274
 # TODO: Add a save_on_top validator.       
243 275
 #model_errors += """invalid_admin_options.saveontopbad: "admin.save_on_top", if given, must be set to True or False.
244 276
 #"""
@@ -250,6 +282,9 @@ class ListSelectRelatedBad(models.Model):
250 282
     class Admin:
251 283
         list_select_related = 'not True or False'
252 284
 
  285
+    def __unicode__(self):
  286
+        return self.name
  287
+
253 288
 # TODO: Add a list_select_related validator.       
254 289
 #model_errors += """invalid_admin_options.listselectrelatebad: "admin.list_select_related", if given, must be set to True or False.
255 290
 #"""
@@ -261,6 +296,9 @@ class ListPerPageBad(models.Model):
261 296
     class Admin:
262 297
         list_per_page = 89.3
263 298
 
  299
+    def __unicode__(self):
  300
+        return self.name
  301
+
264 302
 # TODO: Add a list_per_page validator.       
265 303
 #model_errors += """invalid_admin_options.listperpagebad: "admin.list_per_page", if given, must be a positive integer.
266 304
 #"""
@@ -273,6 +311,9 @@ class FieldsBadOne(models.Model):
273 311
     class Admin:
274 312
         fields = 'not a tuple'
275 313
 
  314
+    def __unicode__(self):
  315
+        return self.first_name
  316
+
276 317
 # TODO: Add a fields validator.       
277 318
 #model_errors += """invalid_admin_options.fieldsbadone: "admin.fields", if given, must be a tuple.
278 319
 #"""
@@ -284,6 +325,9 @@ class FieldsBadTwo(models.Model):
284 325
     
285 326
     class Admin:
286 327
         fields = ('Name', {'description': 'this fieldset needs fields'})
  328
+
  329
+    def __unicode__(self):
  330
+        return self.first_name
287 331
         
288 332
 # TODO: Add a fields validator.       
289 333
 #model_errors += """invalid_admin_options.fieldsbadtwo: "admin.fields" each fieldset must include a 'fields' dict.
@@ -297,6 +341,9 @@ class FieldsBadThree(models.Model):
297 341
     class Admin:
298 342
         fields = ('Name', {'fields': ('first_name','last_name'),'badoption': 'verybadoption'})
299 343
 
  344
+    def __unicode__(self):
  345
+        return self.first_name
  346
+
300 347
 # TODO: Add a fields validator.       
301 348
 #model_errors += """invalid_admin_options.fieldsbadthree: "admin.fields" fieldset options must be either 'classes' or 'description'.
302 349
 #"""
@@ -312,6 +359,9 @@ class Admin:
312 359
                   ('Name', {'fields': ('first_name','last_name'),'classes': 'collapse'}),
313 360
                   (None, {'fields': ('birth_day',),'description': 'enter your b-day'})
314 361
                   )
  362
+
  363
+    def __unicode__(self):
  364
+        return self.first_name
315 365
                   
316 366
 class OrderingBad(models.Model):
317 367
     "Test ordering, must be a field."
@@ -321,6 +371,9 @@ class OrderingBad(models.Model):
321 371
     class Admin:
322 372
         ordering = 'nonexistent'
323 373
 
  374
+    def __unicode__(self):
  375
+        return self.first_name
  376
+
324 377
 # TODO: Add a ordering validator.       
325 378
 #model_errors += """invalid_admin_options.orderingbad: "admin.ordering" refers to 'nonexistent', which isn't a field.
326 379
 #"""
@@ -334,4 +387,4 @@ class Admin:
334 387
 #        manager = 'nonexistent'
335 388
 #       
336 389
 #model_errors += """invalid_admin_options.managerbad: "admin.manager" refers to 'nonexistent', which isn't a Manager().
337  
-#"""
  390
+#"""

0 notes on commit b25f6e9

Please sign in to comment.
Something went wrong with that request. Please try again.