2013-06-25 29 views
10

Tôi có một cơ sở dữ liệu (mysql), nơi tôi muốn lưu trữ dữ liệu ngâm.Làm thế nào để chọn unicodes và lưu chúng trong cơ sở dữ liệu utf-8

Dữ liệu có thể là từ điển, có thể chứa unicode, ví dụ:

data = {1 : u'é'} 

và cơ sở dữ liệu (mysql) nằm trong utf-8.

Khi tôi dưa,

import pickle 
pickled_data = pickle.dumps(data) 
print type(pickled_data) # returns <type 'str'> 

các pickled_data kết quả là một chuỗi.

Khi tôi cố gắng lưu trữ điều này trong cơ sở dữ liệu (ví dụ: trong Textfield), điều này có thể gây ra sự cố. Cụ thể, tôi nhận được một số điểm là

UnicodeDecodeError "'utf8' codec can't decode byte 0xe9 in position X" 

khi cố gắng lưu dữ liệu đã chọn trong cơ sở dữ liệu. Điều này có ý nghĩa bởi vì pickled_data có thể có các ký tự không phải là utf-8. Câu hỏi của tôi là làm thế nào để lưu trữ pickled_data trên một cơ sở dữ liệu utf-8?

tôi nhìn thấy hai ứng cử viên có thể:

  1. Mã hóa kết quả của pickle.dump để utf-8 và lưu trữ nó. Khi tôi muốn pickle.load, tôi phải giải mã nó.

  2. Lưu trữ chuỗi đã chọn ở định dạng nhị phân (như thế nào?), Buộc tất cả các ký tự nằm trong ascii.

Vấn đề của tôi là tôi không thấy hậu quả của việc chọn một trong các tùy chọn này trong thời gian dài. Kể từ khi thay đổi đã yêu cầu một số nỗ lực, tôi được thúc đẩy để yêu cầu một ý kiến ​​về vấn đề này, yêu cầu cho các ứng viên tốt hơn cuối cùng.

(PS Đây là ví dụ hữu ích trong Django)

+0

Tùy chọn 3: Lưu trữ dữ liệu unicode dưới dạng chuỗi được mã hóa UTF-8. –

+0

Tùy chọn 4: Sử dụng loại cột nhị phân thay thế. –

+2

Dữ liệu Pickle là dữ liệu * nhị phân *. Bạn không thể mã hóa thành UTF-8 (mã hóa văn bản). –

Trả lời

13

Pickle dữ liệu là đục, dữ liệu nhị phân, ngay cả khi bạn sử dụng giao thức phiên bản 0:

>>> pickle.dumps(data, 0) 
'(dp0\nI1\nV\xe9\np1\ns.' 

Khi bạn cố gắng để lưu trữ trong một TextField , Django sẽ cố gắng giải mã dữ liệu đó thành UTF8 để lưu trữ nó; đây là những gì không thành công vì đây không phải là dữ liệu được mã hóa UTF-8; nó là dữ liệu nhị phân thay vì:

>>> pickled_data.decode('utf8') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/Users/mj/Development/venvs/stackoverflow-2.7/lib/python2.7/encodings/utf_8.py", line 16, in decode 
    return codecs.utf_8_decode(input, errors, True) 
UnicodeDecodeError: 'utf8' codec can't decode byte 0xe9 in position 9: invalid continuation byte 

Giải pháp là để không thử để lưu trữ này trong TextField. Sử dụng số BinaryField thay thế:

Trường để lưu trữ dữ liệu nhị phân thô. Nó chỉ hỗ trợ chuyển nhượng bytes. Lưu ý rằng trường này có chức năng giới hạn. Ví dụ, không thể lọc một queryset trên một giá trị BinaryField.

Bạn có giá trị bytes (chuỗi Python 2 là chuỗi byte, được đổi tên thành bytes bằng Python 3).

Nếu bạn nhấn mạnh lưu trữ dữ liệu trong trường văn bản, hãy giải mã rõ ràng dữ liệu đó là latin1; Latin 1 bản đồ giải mã byte one-on-one để codepoints Unicode:

>>> pickled_data.decode('latin1') 
u'(dp0\nI1\nV\xe9\np1\ns.' 

và chắc chắn rằng bạn mã hóa nó một lần nữa trước khi unpickling một lần nữa:

>>> encoded = pickled_data.decode('latin1') 
>>> pickle.loads(encoded) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/Users/mj/Development/Libraries/buildout.python/parts/opt/lib/python2.7/pickle.py", line 1381, in loads 
    file = StringIO(str) 
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 9: ordinal not in range(128) 
>>> pickle.loads(encoded.encode('latin1')) 
{1: u'\xe9'} 

Do lưu ý rằng nếu bạn để giá trị này đi đến trình duyệt và ngược lại trong trường văn bản, trình duyệt có thể đã thay thế các ký tự trong dữ liệu đó. Internet Explorer sẽ thay thế các ký tự \n với \r\n, ví dụ, vì nó giả định nó đang xử lý văn bản.

Không phải bạn nên cho phép chấp nhận dữ liệu dưa chuột từ kết nối mạng trong mọi trường hợp, vì that is a security hole waiting for exploitation.

+0

Tôi sẽ chờ cho binaryango của django ổn định. Trong khi đó tôi sẽ sử dụng TextField. Cảm ơn câu trả lời. –

+0

Tôi xin lỗi; Tôi đã không đánh giá cao rằng 'BinaryField' chỉ mới được thêm vào bản phát hành dev. Tôi ngạc nhiên Django đã không có một trường dữ liệu nhị phân trước đây. –

+1

@ J.C.Leitão: Và trong trường hợp dưa chua là dữ liệu bạn chấp nhận từ mạng, vui lòng đọc http://www.zopatista.com/plone/2007/11/09/one-cookie-please/; dữ liệu dưa chuột nên ** không bao giờ ** được chấp nhận từ các nguồn không đáng tin cậy. –

Các vấn đề liên quan