makemessages language_code example def python django unicode django-templates slug

python - language_code - ¿Cómo hacer que Django slugify funcione correctamente con cadenas Unicode?



encoding django (7)

¿Qué puedo hacer para evitar que slugify filter slugify caracteres alfanuméricos no ASCII? (Estoy usando Django 1.0.2)

cnprog.com tiene caracteres chinos en las URL de las preguntas, así que busqué en su código. No están usando slugify en las plantillas, sino que están llamando a este método en el modelo de Question para obtener enlaces permanentes.

def get_absolute_url(self): return ''%s%s'' % (reverse(''question'', args=[self.id]), self.title)

¿Están aplicando slugifying a las URL o no?


Además, la versión de Django de slugify no usa el indicador re.UNICODE, por lo que ni siquiera intentaría comprender el significado de /w/s en lo que respecta a los caracteres no ascii.

Esta versión personalizada funciona bien para mí:

def u_slugify(txt): """A custom version of slugify that retains non-ascii characters. The purpose of this function in the application is to make URLs more readable in a browser, so there are some added heuristics to retain as much of the title meaning as possible while excluding characters that are troublesome to read in URLs. For example, question marks will be seen in the browser URL as %3F and are thereful unreadable. Although non-ascii characters will also be hex-encoded in the raw URL, most browsers will display them as human-readable glyphs in the address bar -- those should be kept in the slug.""" txt = txt.strip() # remove trailing whitespace txt = re.sub(''/s*-/s*'',''-'', txt, re.UNICODE) # remove spaces before and after dashes txt = re.sub(''[/s/]'', ''_'', txt, re.UNICODE) # replace remaining spaces with underscores txt = re.sub(''(/d):(/d)'', r''/1-/2'', txt, re.UNICODE) # replace colons between numbers with dashes txt = re.sub(''"'', "''", txt, re.UNICODE) # replace double quotes with single quotes txt = re.sub(r''[?,:!@#~`+=$%^&//*()/[/]{}<>]'','''',txt, re.UNICODE) # remove some characters altogether return txt

Tenga en cuenta la última sustitución de expresiones regulares. Esta es una solución a un problema con la expresión más robusta r''/W'' , que parece eliminar algunos caracteres que no son ASCII o recodificarlos incorrectamente, como se ilustra en la siguiente sesión de intérprete de Python:

Python 2.5.1 (r251:54863, Jun 17 2009, 20:37:34) [GCC 4.0.1 (Apple Inc. build 5465)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import re >>> # Paste in a non-ascii string (simplified Chinese), taken from http://globallives.org/wiki/152/ >>> str = ''您認識對全球社區感興趣的中國攝影師嗎'' >>> str ''/xe6/x82/xa8/xe8/xaa/x8d/xe8/xad/x98/xe5/xb0/x8d/xe5/x85/xa8/xe7/x90/x83/xe7/xa4/xbe/xe5/x8d/x80/xe6/x84/x9f/xe8/x88/x88/xe8/xb6/xa3/xe7/x9a/x84/xe4/xb8/xad/xe5/x9c/x8b/xe6/x94/x9d/xe5/xbd/xb1/xe5/xb8/xab/xe5/x97/x8e'' >>> print str 您認識對全球社區感興趣的中國攝影師嗎 >>> # Substitute all non-word characters with X >>> re_str = re.sub(''/W'', ''X'', str, re.UNICODE) >>> re_str ''XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/xa3/xe7/x9a/x84/xe4/xb8/xad/xe5/x9c/x8b/xe6/x94/x9d/xe5/xbd/xb1/xe5/xb8/xab/xe5/x97/x8e'' >>> print re_str XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX?的中國攝影師嗎 >>> # Notice above that it retained the last 7 glyphs, ostensibly because they are word characters >>> # And where did that question mark come from? >>> >>> >>> # Now do the same with only the last three glyphs of the string >>> str = ''影師嗎'' >>> print str 影師嗎 >>> str ''/xe5/xbd/xb1/xe5/xb8/xab/xe5/x97/x8e'' >>> re.sub(''/W'',''X'',str,re.U) ''XXXXXXXXX'' >>> re.sub(''/W'',''X'',str) ''XXXXXXXXX'' >>> # Huh, now it seems to think those same characters are NOT word characters

No estoy seguro de cuál es el problema anterior, pero supongo que proviene de " lo que se clasifica como alfanumérico en la base de datos de propiedades de caracteres Unicode " y cómo se implementa. He oído que Python 3.x tiene una alta prioridad en el mejor manejo de Unicode, por lo que esto ya puede solucionarse. O tal vez es el comportamiento correcto de Python, y estoy haciendo un uso indebido de Unicode y / o del idioma chino.

Por ahora, una solución alternativa es evitar las clases de caracteres y realizar sustituciones basadas en conjuntos de caracteres explícitamente definidos.






Hay un paquete python llamado unidecode que he adoptado para el foro AskB Q & A, funciona bien para los alfabetos latinos e incluso parece razonable para el griego:

>>> import unidecode >>> from unidecode import unidecode >>> unidecode(u''διακριτικός'') ''diakritikos''

Hace algo extraño con los idiomas asiáticos:

>>> unidecode(u''影師嗎'') ''Ying Shi Ma '' >>>

¿Esto tiene sentido?

En askbot calculamos babosas de esta manera:

from unidecode import unidecode from django.template import defaultfilters slug = defaultfilters.slugify(unidecode(input_text))


Me temo que la definición de django de slug significa ascii, aunque los documentos de django no lo mencionan explícitamente. Esta es la fuente de los filtros predeterminados para slugify ... puede ver que los valores se están convirtiendo a ascii, con la opción ''ignorar'' en caso de errores:

import unicodedata value = unicodedata.normalize(''NFKD'', value).encode(''ascii'', ''ignore'') value = unicode(re.sub(''[^/w/s-]'', '''', value).strip().lower()) return mark_safe(re.sub(''[-/s]+'', ''-'', value))

En función de eso, supongo que cnprog.com no está utilizando una función oficial de slugify . Es posible que desee adaptar el fragmento de django anterior si desea un comportamiento diferente.

Habiendo dicho eso, el RFC para URLs declara que caracteres no-us-ascii (o, más específicamente, cualquier cosa que no sean los alfanuméricos y $ -_. +! * ''()) Deberían ser codificados usando la notación% hex. . Si nos fijamos en la solicitud GET en bruto real que envía su navegador (digamos, usando Firebug), verá que los caracteres chinos están de hecho codificados antes de ser enviados ... el navegador simplemente lo hace lucir bonito en la pantalla. Sospecho que esta es la razón por la cual slugify solo insiste en ascii, fwiw.