金字塔/ Python / SQLAlchemy编码地狱

时间:2015-03-23 15:27:54

标签: python unicode sqlalchemy pyramid

我在这里非常热闹。

所以我使用SQLAlchemy和Pyramid作为Web应用程序。此应用程序的一个功能是从一个表单解析输入,该表单通过XML-RPC桥接器传递给Ruby解析器。

当我尝试使用渲染器返回新解析对象的JSON时,会出现问题。

这是错误,后面是详细信息:

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

设置

数据库设置

整理:utf8_general_ci

模型

class Citation(Base):
    __tablename__ = 'citations'
    __table_args__ = {'autoload' : True}
    authors = relationship("Author", secondary=author_of, backref='citations')

    possible_matches = relationship("Citation", secondary=similar_to,
        primaryjoin=citation_id==similar_to.c.citation_id1,
        secondaryjoin=citation_id==similar_to.c.citation_id2
        )

    def __init__(self, citation_dict=None):
        self.__dict__.update(citation_dict)


    def __repr__(self):
        return "<Citation %d: %s (%s)>" %\
               (self.citation_id, self.title, self.year)

    @property
    def json(self):
        attrs =\
            ['pubtype', 'abstract', 'keywords', 'doi', 'url', 'address',
             'booktitle', 'chapter', 'crossref', 'edition', 'editor',
             'translator', 'howpublished', 'institution', 'journal',
             'bibtex_key', 'month', 'note', 'number', 'organization',
             'pages', 'publisher', 'location', 'school', 'series', 'title',
             'type', 'volume', 'year', 'raw', 'verified', 'last_modified',
             'entryTime', 'citation_id']
        struct = { 'authors' : [a.json for a in self.authors] }
        for attr in attrs:
            struct[attr] = getattr(self, attr, None)

        struct["auth_string"] = " ".join([a.toString() for a in self.authors])
        return struct

查看

@view_config(route_name='citation_add', request_method='POST', renderer='pubs_json')
def citation_add(request):
    raw = request.body
    citation = parser.parse(raw)[0]

    return citation.json

渲染

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

import customjson
import os
from pyramid.asset import abspath_from_asset_spec

class PubsJSONRenderer:
        def __init__(self, info):
                """ Constructor: info will be an object having the the 
                following attributes: name (the renderer name), package 
                (the package that was 'current' at the time the 
                renderer was registered), type (the renderer type 
                name), registry (the current application registry) and 
                settings (the deployment settings dictionary).        """


        def __call__(self, value, system):
                """ Call a the renderer implementation with the value 
                and the system value passed in as arguments and return 
                the result (a string or unicode object).  The value is 
                the return value of a view.         The system value is a 
                dictionary containing available system values 
                (e.g. view, context, and request). """
                request = system.get('request')
                if request is not None:
                        if not hasattr(request, 'response_content_type'):
                                request.response_content_type = 'application/json'

                return customjson.dumps(value)

customjson.py

from json import JSONEncoder
from decimal import Decimal
class ExtJsonEncoder(JSONEncoder):
    '''
    Extends ``simplejson.JSONEncoder`` by allowing it to encode any
    arbitrary generator, iterator, closure or functor.
    '''
    def default(self, c):
        # Handles generators and iterators
        if hasattr(c, '__iter__'):
            return [i for i in c]

        # Handles closures and functors
        if hasattr(c, '__call__'):
            return c()

        # Handles precise decimals with loss of precision to float.
        # Hack, but it works
        if isinstance(c, Decimal):
            return float(c)

        return JSONEncoder.default(self, c)

def dumps(*args):
    '''
    Shortcut for ``ExtJsonEncoder.encode()``
    '''
    return ExtJsonEncoder(sort_keys=False, ensure_ascii=False,
            skipkeys=True).encode(*args)

堆栈跟踪

 Traceback (most recent call last):
   File     "/var/site/siteenv/lib/python2.7/site-packages/pyramid/router.py", line 242, in __call__
     response = self.invoke_subrequest(request, use_tweens=True)
   File "/var/site/siteenv/lib/python2.7/site-packages/pyramid/router.py", line 217, in invoke_subrequest
     response = handle_request(request)
   File "/var/site/siteenv/lib/python2.7/site-packages/pyramid_debugtoolbar/toolbar.py", line 160, in toolbar_tween
     return handler(request)
   File "/var/site/siteenv/lib/python2.7/site-packages/pyramid/tweens.py", line 21, in excview_tween
     response = handler(request)
   File "/var/site/siteenv/lib/python2.7/site-packages/pyramid_tm/__init__.py", line 82, in tm_tween
     reraise(*exc_info)
   File "/var/site/siteenv/lib/python2.7/site-packages/pyramid_tm/__init__.py", line 63, in tm_tween
     response = handler(request)
   File "/var/site/siteenv/lib/python2.7/site-packages/pyramid/router.py", line 163, in handle_request
     response = view_callable(context, request)
   File "/var/site/siteenv/lib/python2.7/site-packages/pyramid/config/views.py", line 329, in attr_view
     return view(context, request)
   File "/var/site/siteenv/lib/python2.7/site-packages/pyramid/config/views.py", line 305, in predicate_wrapper
     return view(context, request)
   File "/var/site/siteenv/lib/python2.7/site-packages/pyramid/config/views.py", line 377, in rendered_view
     context)
   File "/var/site/sitvenv/lib/python2.7/site-packages/pyramid/renderers.py", line 418, in render_view
     return self.render_to_response(response, system, request=request)
   File "/var/site/siteenv/lib/python2.7/site-packages/pyramid/renderers.py", line 441, in render_to_response
     result = self.render(value, system_values, request=request)
   File "/var/site/siteenv/lib/python2.7/site-packages/pyramid/renderers.py", line 437, in render
     result = renderer(value, system_values)
   File "/var/site/renderers.py", line 30, in __call__
     return customjson.dumps(value)
   File "/var/site/customjson.py", line 38, in dumps
     skipkeys=True).encode(*args)
   File "/usr/lib/python2.7/json/encoder.py", line 203, in encode
     return ''.join(chunks)
 UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 93: ordinal not in range(128)

从解析器返回

我们加入

Allen, C. 1995 "It isn't what you think: a new idea about intentional causation." Noûs 29,1:115-126

我们从解析器中获取这样的dict对象:

{'title': '\\\\"It isn\\'t what you think: a new idea about intentional causation.\\\\"', 'journal': 'No\\\\xc3\\\\xbbs', 'author': 'Allen, C.', 'number': 1, 'volume': 29, 'date': '1995', 'type': 'article', 'pages': u'115\\u2013126'}

试过

因为应用程序在虚拟环境中运行,所以我觉得可以跳到page.py并将默认编码从ascii更改为utf-8

我尝试过编码和解码,并将charset=utf8&use_unicode=1添加到我的SQLAlchemy网址中无济于事。

我怀疑问题在于ensure_ascii=False文件中的customjson.py选项。事实上,Python 2.7 JSON编码器的文档说明如下:

  

如果ensure_ascii为False,则写入fp的一些块可能是unicode实例。这通常是因为输入包含unicode字符串或使用编码参数。除非fp.write()明确理解unicode(如在codecs.getwriter()中),否则这可能会导致错误。

设置ensure_ascii=True似乎可以解决错误。鉴于json编码器的默认编码已经utf-8,我不确定手动设置会有所帮助。我需要那些unicode字符,所以我不确定如何处理这个问题。

1 个答案:

答案 0 :(得分:0)

在客户端有一个呼叫JSON.stringify正在逃避麻烦的角色。删除此导致python正常工作。