2013-10-04 5 views
6

Ho un'applicazione Web che utilizza Flask, SQLAlchemy e WTForms, insieme alle estensioni necessarie di Flask per far funzionare tutto. MySQL utilizza utf8_bin per tutte le tabelle e le colonne.Flask, SQLAlchemy e Jinja2 - UnicodeDecodeError

ho inserito alcuni caratteri cinesi e phpMyAdmin li visualizza correttamente, ma ogni volta che provo ad aprire una pagina ottengo la seguente eccezione:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position 0: ordinal not in range(128)

Capisco che dovrei decode('utf8') i campi voglio visualizzare, ma shouldn Questo è gestito da SQLAlchemy per me?

L'unico modo sono riuscito a fare questo lavoro è stato scorrendo la lista dei risultati e di fare qualcosa di simile a:

object.property = object.property.decode('utf8')

Ma, ovviamente, questo non dovrebbe essere fatto a mano. Cosa mi manca?

Aggiornamento: mappatura SQLAlchemy

class Thread(db.Model): 

    __tablename__ = 'Thread' 

    id = db.Column(db.Integer, primary_key=True) 
    title = db.Column(db.Unicode(255), nullable=False) 
    body = db.Column(db.Text, nullable=True) 
    date_created = db.Column(db.DateTime, nullable=False, default=datetime.now()) 
    created_by = db.Column(db.Integer, ForeignKey(User.id)) 
    user = relationship(User, backref='threads') 
    display_hash = db.Column(db.Unicode(255), nullable=False, unique=True) 
    display_name = db.Column(db.Unicode(255), nullable=True) 
    nsfw = db.Column(db.Boolean, nullable=False, default=False) 
    last_updated = db.Column(db.DateTime, nullable=False) 

    def __init__(self, title=None, body=None, category_id=None, display_name=None): 
     self.title = title 
     self.body = body 
     self.category_id = category_id 
     self.display_name = display_name 
     self.display_hash = custom_uuid() 
     self.last_updated = self.date_created 

    def __repr__(self): 
     return u'<Thread %r>' % (self.title) 

    def url_title(self): 
     """ Generates an ASCII-only slug. """ 

     result = [] 
     for word in _punct_re.split(self.title.lower()): 
      result.extend(unidecode(word).split()) 
     return unicode(u'-'.join(result)) 

Aggiornamento: Analisi dello stack

`127.0.0.1 - - [06/Oct/2013 02:37:15] "GET /index HTTP/1.1" 500 - 
Traceback (most recent call last): 
    File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__ 
    return self.wsgi_app(environ, start_response) 
    File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app 
    response = self.make_response(self.handle_exception(e)) 
    File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception 
    reraise(exc_type, exc_value, tb) 
    File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app 
    response = self.full_dispatch_request() 
    File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request 
    rv = self.handle_user_exception(e) 
    File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception 
    reraise(exc_type, exc_value, tb) 
    File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request 
    rv = self.dispatch_request() 
    File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request 
    return self.view_functions[rule.endpoint](**req.view_args) 
    File "/Users/homedirectory/Projects/Assorted/Fruit Show/app/views.py", line 90, in index 
    return render_template('index.html', threads=threads, pagination=pagination) 
    File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/templating.py", line 128, in render_template 
    context, ctx.app) 
    File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/templating.py", line 110, in _render 
    rv = template.render(context) 
    File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/jinja2/environment.py", line 969, in render 
    return self.environment.handle_exception(exc_info, True) 
    File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/jinja2/environment.py", line 742, in handle_exception 
    reraise(exc_type, exc_value, tb) 
    File "/Users/homedirectory/Projects/Assorted/Fruit Show/app/templates/index.html", line 1, in top-level template code 
    {% extends 'base.html' %} 
    File "/Users/homedirectory/Projects/Assorted/Fruit Show/app/templates/base.html", line 50, in top-level template code 
    {% block content %} 
    File "/Users/homedirectory/Projects/Assorted/Fruit Show/app/templates/index.html", line 14, in block "content" 
    <a href="{{ url_for('new_thread') }}/{{ thread.display_hash|safe }}/{{ thread.url_title()|safe }}">{{ thread.title|safe }}</a> 
    File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/jinja2/filters.py", line 747, in do_mark_safe 
    return Markup(value) 
    File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/markupsafe/__init__.py", line 72, in __new__ 
    return text_type.__new__(cls, base) 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position 0: ordinal not in range(128)` 

Aggiornamento: URL per il progetto di pronti contro termine:

https://github.com/ruipacheco/fruitshow

+0

Si prega di aggiornare la domanda con i modelli SQLAlchemy con i quali si hanno problemi. –

+0

Grazie per l'aggiornamento. Puoi anche aggiornare la tua domanda e fornire un breve snippet di codice che puoi utilizzare per duplicare l'errore, inclusa la traccia dello stack completo fornita dal codice. –

+0

Inoltre, MySQL [può utilizzare le connessioni client predefinite per usare latin1 anche se le tabelle e le colonne utilizzano unicode] (http://docs.sqlalchemy.org/en/rel_0_8/dialects/mysql.html#unicode). –

risposta

4

Il problema è con il driver MySQL che sto usando.

Ho seguito la risposta this e il passaggio del tipo di colonna da utf8_bin a utf8_general_ci ha risolto il problema.

0

l'impostazione del set di caratteri nei parametri di connessione dice solo a mysql di trascodificare le colonne da quelle che si trovano nel database alla codifica del formato richiesta. I dati sono ancora passati tra MySQL e il client come byte. In breve, devi dire allo sqlalchemy che "questo particolare" dato è dati unicode (nella codifica della connessione). Per la maggior parte delle tue colonne, hai utilizzato Unicode, che serve a questo scopo. Uno standout notevole è body, che è di tipo Text. Probabilmente vuoi UnicodeText o Text(convert_unicode=True)

+0

Nessuno dei due ha funzionato. – ruipacheco

2

Un piccolo suggerimento per il campo Slug nei modelli .

C'è una libreria denominata Webhelpers (https://pypi.python.org/pypi/WebHelpers), l'importazione e il titolo verrà automaticamente convertito in slug.

Installare WebHelpers e quindi importare urlify

from webhelpers.text import urlify 
. 
. 
. 
@property 
def slug(self): 
    return urlify(self.title) 
0

Non proprio la risposta, ma mi permetta di consiglio ftfy (Fix testo per voi) che fissa un gruppo di piccoli unicode e le questioni html fuga. Una guerra religiosa davvero fastidiosa nella codifica Unicode è l'incapacità di UTF-8 di gestire le varie codifiche di caratteri a un byte come Latin-1. Invece di andare semplicemente "oh, questo deve essere un semplice carattere latino", il decoder si agita. Quando il driver del database fa l'osservazione di "oh, questo si adatta", crea in Fatwah.