Opened 15 years ago

Closed 15 years ago

Last modified 13 years ago

#11710 closed (fixed)

construct_change_message() with unicode verbose_name fix

Reported by: Joshua Russo Owned by: nobody
Component: contrib.admin Version: dev
Severity: Keywords: construct_change_message exception ascii unicode
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I had a verbose name for a model that used non-ascii unicode characters and that caused the construct_change_message() method to thow an exception. So I added force_unicode() around the verbose_name retrieval.

Attachments (1)

change_message_unicode_name.patch (3.1 KB ) - added by Joshua Russo 15 years ago.

Download all attachments as: .zip

Change History (12)

comment:1 by Joshua Russo, 15 years ago

Here is the error I was receiving.

Environment:

Request Method: POST
Request URL: http://localhost:8000/admin/matriz/matriz/1001/
Django Version: 1.1
Python Version: 2.5.4
Installed Applications:
['django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.admin',
 'django.contrib.admindocs',
 'adminTributaria.farramentas',
 'adminTributaria.pessoa',
 'adminTributaria.matriz']
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware')


Traceback:
File "C:\Python25\Lib\site-packages\django\core\handlers\base.py" in get_response
  92.                 response = callback(request, *callback_args, **callback_kwargs)
File "C:\Python25\lib\site-packages\django\contrib\admin\options.py" in wrapper
  226.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "C:\Python25\Lib\site-packages\django\views\decorators\cache.py" in _wrapped_view_func
  44.         response = view_func(request, *args, **kwargs)
File "C:\Python25\Lib\site-packages\django\contrib\admin\sites.py" in inner
  186.             return view(request, *args, **kwargs)
File "C:\Python25\Lib\site-packages\django\db\transaction.py" in _commit_on_success
  240.                 res = func(*args, **kw)
File "C:\Python25\lib\site-packages\django\contrib\admin\options.py" in change_view
  850.                 change_message = self.construct_change_message(request, form, formsets)
File "C:\Python25\lib\site-packages\django\contrib\admin\options.py" in construct_change_message
  526.                                              'object': force_unicode(added_object)})

Exception Type: UnicodeDecodeError at /admin/matriz/matriz/1001/
Exception Value: 'ascii' codec can't decode byte 0xc3 in position 18: ordinal not in range(128)

comment:2 by Ramiro Morales, 15 years ago

Have you really specified verbose_name for the relevant model as an unicode? Can you paste relevant excerpts of models.py (including the file encoding header at the top if the file)?

comment:3 by Joshua Russo, 15 years ago

Here is the model with the verbose name that was giving me problems. I've tried it with and without the u Unincode indicator in front of the verbose_name string.

# -*- coding: utf-8 -*-

class Matriz(modelUtils.MyModelAudit):
    """
    Localidades ondi pessoas mesti paga taxas
    Locals where a person needs to pay taxes
    """

    NumOrd        = models.IntegerField('número', primary_key=True,
        blank=True, help_text='Número de identificação. Se você deixar em branco o próximo número será dado disponível.')
    SitPredios    = fields_db.AutoCompleteCharField('situação dos prédios', max_length=50)
    SitTipoCD_Choices=((1,'Rustica'),(2,'Urbano'))
    SitTipoCD     = models.IntegerField('tipo de Situação',
        choices=SitTipoCD_Choices)
    Proprietarios = models.ManyToManyField(Pessoa, through='MatrizPropri')
    Ano           = models.IntegerField(help_text = 'Ano documentos assinar')
    Documentos    = models.ManyToManyField(Documento, through='MatrizDocs')
    Descricao     = models.TextField('descrição', max_length=4000,
        help_text = 'Descrição dos prédios, suas divisões, confrontações, ' + \
        'superfície coberta e sua aplicação')
    Rendimento    = CurrencyField('rendimento colectável', max_digits=15)
    RendTipoCD_Choices=((1,'Total'),(2,'Parcial'))
    RendTipoCD   = models.IntegerField('tipo de Rendimento',
        choices=RendTipoCD_Choices)
    Observacoes  = models.TextField('observações', max_length=2000, blank=True)

    Anular       = models.BooleanField(default=False, blank=True)
    UltimoAno    = models.IntegerField('último ano', null=True, blank=True, help_text = 'Último ano activo')
    AnularInfo   = models.CharField('informação / Razão', max_length=50, null=True, blank=True,
        help_text='O número de novo prédio e/ou o razão por anular.')

    ULTIMOANO_MISSING_ERROR = _("You need to provided an ending year for a nulled property.")

    class Meta:
        ordering = ["NumOrd"]
        verbose_name = 'prédio'
        verbose_name_plural = 'prédios'

    def __unicode__(self):
        return unicode(self.NumOrd) + ' - ' + self.SitPredios

    def save(self, force_insert=False, force_update=False):
        if self.Anular and not self.UltimoAno:
            raise ValidationError(unicode(self.ULTIMOANO_MISSING_ERROR))
        super(Matriz, self).save(force_insert, force_update)

comment:4 by Ramiro Morales, 15 years ago

Resolution: worksforme
Status: newclosed

The symptoms you describe are located in code that handles the creation of a change message for modifications of inlined models but a) I don't see any FK from your Matriz model to another model and b) Inlines can't be created for many to many relationships (of which Matriz has two), that's weird because it seems you simply pasted your whole model ()without reducing it to the relevant parts so we can try to diagnose the real problem with minimal surrounding noise. So I suspect you aren't telling us the complete story here.

I've created this simplified setup:

# -*- coding: utf-8 -*-
from django.db import models

class Foo(models.Model):
    name = models.CharField(max_length=100)

class Matriz(models.Model):
    NumOrd = models.IntegerField(u'número', primary_key=True, blank=True, help_text=u'Número de identificação. Se você deixar em branco...')
    SitPredios = models.CharField(u'situação dos prédios', max_length=50)
    foo = models.ForeignKey(Foo)

    class Meta:
        ordering = ["NumOrd"]
        verbose_name = u'prédio'
        verbose_name_plural = u'prédios'

    def __unicode__(self):
        return unicode(self.NumOrd) + u' - ' + self.SitPredios
from django.contrib import admin
from t11710.models import Matriz, Foo

class MatrizInline(admin.TabularInline):
    model = Matriz

class FooAdmin(admin.ModelAdmin):
    inlines = (MatrizInline,)

admin.site.register(Foo, FooAdmin)

And I can perform CRUD actions on Matriz instances inlined to a Foo admin form without experimenting the problem you report. Note how I used the u prefix for ALL the literals. Also, you need to be sure the real coding of the models.py file is UTF-8, using the # -*- coding: utf-8 -*- header isn't enough. i.e.:

$ file t11710/models.py
t11710/models.py: UTF-8 Unicode Java program text

Because of that, and because the ticket tracker isn't the place to have this kind of conversation (I suggest to post additional details to the django-users mailing), I'm closing this ticket.

comment:5 by Karen Tracey, 15 years ago

Needs tests: set
Resolution: worksforme
Status: closedreopened
Triage Stage: UnreviewedAccepted

In the non-inline add case we do call force_unicode on the verbose name:

http://code.djangoproject.com/browser/django/tags/releases/1.1/django/contrib/admin/options.py#L599

We should do it also in the places pointed out here. Ramiro, your case works because you made the verbose name a unicode string. But a utf-8 bytestring would be perfectly valid there as far as Django is concerned, and that is the case that fails. Note you have to make some change to the inline objects for an existing parent object in order to trigger the error....if you just add an inline along with the parent the log message doesn't say anything about the added inline so the bug isn't triggered.

comment:6 by Joshua Russo, 15 years ago

I didn't realize that I was receiving that error only when I edited an inline model. I didn't know how much information to give before, for fear of giving too much. The inline model within the Matriz admin page also has a verbose name with unicode characters.

by Joshua Russo, 15 years ago

comment:7 by Joshua Russo, 15 years ago

Needs tests: unset

Now with tests

comment:8 by Joshua Russo, 15 years ago

milestone: 1.2

comment:9 by Karen Tracey, 15 years ago

Resolution: fixed
Status: reopenedclosed

(In [12650]) Fixed #11710: Made a small test change to ensure utf-8 bytestrings in
verbose_names don't cause a server error when the admin change log message is
built. The necessary code fix was made for #12966 in r12627. Thanks Rupe.

comment:10 by Karen Tracey, 15 years ago

(In [12651]) [1.1.X] Fixed #11710: Made a small test change to ensure utf-8 bytestrings in verbose_names don't cause a server error when the admin change log message is built. The necessary code fix was made for #12966 in r12627. Thanks Rupe.

r12650 from trunk.

comment:11 by Jacob, 13 years ago

milestone: 1.2

Milestone 1.2 deleted

Note: See TracTickets for help on using tickets.
Back to Top