当我将项目的django版本更新为1.5.x时,就开始出现此问题。
我的问题是当使用mysql作为后端并且我上传文件并尝试将该文件的块保存到另一个模型时,我得到一个UnicodeDecodeError。
在django 1.4.x中,没有抛出错误,相关模型会被持久化。
要重新创建的示例项目: https://github.com/imtapps/fileuploaderror
models.py
from django.db import models
class LongBlob(models.Field):
def db_type(self, connection):
return "longblob"
class Document(models.Model):
document = LongBlob()
class Book(models.Model):
description = models.CharField(max_length=30)
document = models.ForeignKey(Document, null=True)
forms.py
from django import forms
from spikeapp.models import Document, Book
class BookForm(forms.ModelForm):
upload_file = forms.FileField()
def save(self, *args, **kwargs):
self.cleaned_data['upload_file'].open()
data = ''.join([chunk for chunk in self.cleaned_data['upload_file'].chunks()])
self.cleaned_data['upload_file'].close()
Document.objects.create(document=data)
class Meta:
model = Book
fields = ('description',)
views.py
from django.views.generic.edit import FormView
from spikeapp.forms import BookForm
class FileView(FormView):
template_name = 'file.html'
form_class = BookForm
success_url = "/"
def form_valid(self, form):
form.save()
return super(FileView, self).form_valid(form)
这是一个例外:
Traceback:
File "/home/appsdev/.virtualenvs/blobspike/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
115. response = callback(request, *callback_args, **callback_kwargs)
File "/home/appsdev/.virtualenvs/blobspike/local/lib/python2.7/site-packages/django/views/generic/base.py" in view
68. return self.dispatch(request, *args, **kwargs)
File "/home/appsdev/.virtualenvs/blobspike/local/lib/python2.7/site-packages/django/views/generic/base.py" in dispatch
86. return handler(request, *args, **kwargs)
File "/home/appsdev/.virtualenvs/blobspike/local/lib/python2.7/site-packages/django/views/generic/edit.py" in post
165. return self.form_valid(form)
File "/home/appsdev/Projects/blobspike/spikeapp/views.py" in form_valid
11. form.save()
File "/home/appsdev/Projects/blobspike/spikeapp/forms.py" in save
12. Document.objects.create(document=data)
File "/home/appsdev/.virtualenvs/blobspike/local/lib/python2.7/site-packages/django/db/models/manager.py" in create
149. return self.get_query_set().create(**kwargs)
File "/home/appsdev/.virtualenvs/blobspike/local/lib/python2.7/site-packages/django/db/models/query.py" in create
416. obj.save(force_insert=True, using=self.db)
File "/home/appsdev/.virtualenvs/blobspike/local/lib/python2.7/site-packages/django/db/models/base.py" in save
546. force_update=force_update, update_fields=update_fields)
File "/home/appsdev/.virtualenvs/blobspike/local/lib/python2.7/site-packages/django/db/models/base.py" in save_base
650. result = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw)
File "/home/appsdev/.virtualenvs/blobspike/local/lib/python2.7/site-packages/django/db/models/manager.py" in _insert
215. return insert_query(self.model, objs, fields, **kwargs)
File "/home/appsdev/.virtualenvs/blobspike/local/lib/python2.7/site-packages/django/db/models/query.py" in insert_query
1675. return query.get_compiler(using=using).execute_sql(return_id)
File "/home/appsdev/.virtualenvs/blobspike/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in execute_sql
937. cursor.execute(sql, params)
File "/home/appsdev/.virtualenvs/blobspike/local/lib/python2.7/site-packages/django/db/backends/util.py" in execute
45. sql = self.db.ops.last_executed_query(self.cursor, sql, params)
File "/home/appsdev/.virtualenvs/blobspike/local/lib/python2.7/site-packages/django/db/backends/mysql/base.py" in last_executed_query
243. return cursor._last_executed.decode('utf-8')
File "/home/appsdev/.virtualenvs/blobspike/lib/python2.7/encodings/utf_8.py" in decode
16. return codecs.utf_8_decode(input, errors, True)
Exception Type: UnicodeDecodeError at /
Exception Value: 'utf8' codec can't decode byte 0xb5 in position 67: invalid start byte
要复制的版本: MySQLdb-Python = 1.2.4
Django = 1.5.4
答案 0 :(得分:5)
你偶然发现了Django 1.5中的一个错误:#19954 Storing of Binary fields leads to Exceptions。
committed fix强制使用'replace'强制解码上次执行的查询:
return force_text(cursor._last_executed, errors='replace')
您可以编辑Django源代码,也可以应用monkeypatch:
from django.utils.encoding import force_text
from django.db.backends.mysql.base import DatabaseOperations
def fixed_last_executed_query(self, cursor, sql, params):
return force_text(cursor._last_executed, errors='replace')
DatabaseOperations.last_executed_query = fixed_last_executed_query
例如,尽早在settings
模块或包的顶部执行此操作。
我认为这个补丁没有向后移植;它到目前为止只进入1.6开发线,可能是因为1.6增加了一个新的二进制字段类型。