2010-11-06 6 views
1

Je travaille sur un nouveau site Django et, après avoir migré dans une pile de données, j'ai commencé à utiliser un DjangoUnicodeDecodeError très frustrant. Le mauvais personnage en question est un \ xe8 (e-grave).Codage de caractères Django

Il y a deux questions épineuses:

Il arrive que dans le serveur de production, l'exécution d'un processus fcgi rieuses Apache (exécutant le même code avec la même base de données sur le serveur dev Django n'a pas de problème)

La trace de pile en question est entièrement dans le code Django. Il se produit dans le site d'administration (ailleurs aussi) lors de la récupération d'un élément à afficher, bien que le champ qui contient le mauvais caractère n'est pas réellement rendu.

Je ne suis même pas entièrement sûr de savoir où commencer le débogage, à moins d'essayer de supprimer les caractères incriminés manuellement. Je suppose qu'il s'agit d'un problème de configuration, car il est spécifique à l'environnement, mais je ne suis pas sûr de savoir par où commencer.

EDIT: Comme Daniel Roseman a souligné, l'erreur est presque certainement dans la méthode unicode - ou, plus précisément, une autre méthode qui l'appelle. Notez que les caractères incriminés sont dans un champ non référencé du tout dans le code ici. Je suppose que l'exception est levée dans une méthode qui construit l'objet à partir du résultat db - si le queryset n'est jamais évalué (par exemple si self.enabled) il n'y a pas d'erreur. Voici le code:

def get_blocking_events(self): 
    return Event.objects.filter(<get a set of events>) 

def get_blocking_reason(self): 
    blockers = self.get_blocking_events() 
    label = u'' 
    if not self.enabled: 
     label = u'Sponsor disabled' 
    elif len(blockers) > 0: 
     label = u'Pending follow-up: "{0}" ({1})'.format(blockers[0],blockers[0].creator.email) 
     if len(blockers) > 1: 
      label += u" and {0} other event".format(len(blockers)-1) 
     if len(blockers) > 2: 
      label += u"s" 
    return label 

def __unicode__(self): 
    label = self.name 
    blocking_msg = self.get_blocking_reason() 
    if len(blocking_msg): 
     label += u" ({0})".format(blocking_msg) 
    return label 

Voici la queue de la trace de la pile, pour le plaisir:

File "/opt/opt.LOCAL/Django-1.2.1/django/template/__init__.py", line 954, in render 
    dict = func(*args) 

File "/opt/opt.LOCAL/Django-1.2.1/django/contrib/admin/templatetags/admin_list.py", line 209, in result_list 
    'results': list(results(cl))} 

File "/opt/opt.LOCAL/Django-1.2.1/django/contrib/admin/templatetags/admin_list.py", line 201, in results 
    yield list(items_for_result(cl, res, None)) 

File "/opt/opt.LOCAL/Django-1.2.1/django/contrib/admin/templatetags/admin_list.py", line 138, in items_for_result 
    f, attr, value = lookup_field(field_name, result, cl.model_admin) 

File "/opt/opt.LOCAL/Django-1.2.1/django/contrib/admin/util.py", line 270, in lookup_field 
    value = attr() 

File "/opt/opt.LOCAL/Django-1.2.1/django/db/models/base.py", line 352, in __str__ 
    return force_unicode(self).encode('utf-8') 

File "/opt/opt.LOCAL/Django-1.2.1/django/utils/encoding.py", line 88, in force_unicode 
    raise DjangoUnicodeDecodeError(s, *e.args) 

DjangoUnicodeDecodeError: 'utf8' codec can't decode bytes in position 956-958: invalid data. You passed in <Sponsor: [Bad Unicode data]> (<class 'SJP.alcohol.models.Sponsor'>) 
+0

Le coupable habituel dans ces circonstances est la méthode '__unicode__' du modèle. Pouvez-vous nous montrer le code? –

+0

Qu'en est-il des données dans la base de données - vos tables utilisent-elles UTF8 ou un codage ISO Latin? –

+0

La base de données est MS SQL Server, donc je crois comprendre qu'il n'y a pas d'encodage à l'échelle de la base de données; cependant, la colonne en question est un nvarchar, ce qui signifie que les données sont encodées en UTF-16. Je noterai également que je n'ai aucun problème à lire exactement la même base de données avec le même code d'application via le serveur de développement django. –

Répondre

1

Il s'avère que cela est probablement dû à la couche FreeTDS qui se connecte à SQL Server. Alors que FreeTDS fournit un support pour la conversion automatique des encodages, ma configuration est mal configurée ou ne fonctionne pas correctement.

Plutôt que de combattre cette bataille, j'ai migré vers MySQL pour le moment.

1

Le problème ici est que dans unicode vous utilisez la ligne suivante:

label += " ({0})".format(blocking_msg) 

Et malheureusement, dans python 2.x, cela tente de formater blocking_msg en tant que chaîne ASCII. Ce que vous vouliez écrire était:

label += u" ({0})".format(blocking_msg) 
+0

Merci, mais pas de chance. Pour être sûr, j'ai converti tous les littéraux de chaîne dans ces fonctions en chaînes Unicode. –

+0

Quel est le codage dans le db? –