Code

Opened 5 years ago

Closed 4 years ago

Last modified 3 years ago

#11710 closed (fixed)

construct_change_message() with unicode verbose_name fix

Reported by: Rupe Owned by: nobody
Component: contrib.admin Version: master
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: UI/UX:

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 Rupe 5 years ago.

Download all attachments as: .zip

Change History (12)

comment:1 Changed 5 years ago by Rupe

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

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 Changed 5 years ago by ramiro

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 Changed 5 years ago by Rupe

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 Changed 5 years ago by ramiro

  • Resolution set to worksforme
  • Status changed from new to closed

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 Changed 5 years ago by kmtracey

  • Needs tests set
  • Resolution worksforme deleted
  • Status changed from closed to reopened
  • Triage Stage changed from Unreviewed to Accepted

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 Changed 5 years ago by Rupe

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.

Changed 5 years ago by Rupe

comment:7 Changed 5 years ago by Rupe

  • Needs tests unset

Now with tests

comment:8 Changed 5 years ago by Rupe

  • milestone set to 1.2

comment:9 Changed 4 years ago by kmtracey

  • Resolution set to fixed
  • Status changed from reopened to closed

(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 Changed 4 years ago by kmtracey

(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 Changed 3 years ago by jacob

  • milestone 1.2 deleted

Milestone 1.2 deleted

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.