2012-04-27 21 views
21

SQLalchemy cung cấp cho tôi cảnh báo sau khi tôi sử dụng cột Số với công cụ cơ sở dữ liệu SQLite.Làm cách nào để xử lý số thập phân trong SQLalchemy & SQLite

SAWarning: Dialect sqlite + pysqlite không hỗ trợ không đối tượng Decimal natively

Tôi đang cố gắng tìm ra cách tốt nhất để có pkgPrice = Column(Numeric(12,2)) trong SQLAlchemy trong khi vẫn sử dụng SQLite.

Câu hỏi này [1] How to convert Python decimal to SQLite numeric? cho biết cách sử dụng sqlite3.register_adapter(D, adapt_decimal) để SQLite nhận và trả về thập phân, nhưng lưu trữ chuỗi, nhưng tôi không biết cách khai thác lõi SQLAlchemy để làm điều này. Loại trang trí trông giống như cách tiếp cận đúng nhưng tôi không grok chúng được nêu ra.

Có ai có SQLAlchemy Type Decorator Recipe sẽ có số hoặc số thập phân trong mô hình SQLAlchemy, nhưng lưu trữ chúng dưới dạng chuỗi trong SQLite không?

Trả lời

16
from decimal import Decimal as D 
import sqlalchemy.types as types 

class SqliteNumeric(types.TypeDecorator): 
    impl = types.String 
    def load_dialect_impl(self, dialect): 
     return dialect.type_descriptor(types.VARCHAR(100)) 
    def process_bind_param(self, value, dialect): 
     return str(value) 
    def process_result_value(self, value, dialect): 
     return D(value) 

# can overwrite the imported type name 
# @note: the TypeDecorator does not guarantie the scale and precision. 
# you can do this with separate checks 
Numeric = SqliteNumeric 
class T(Base): 
    __tablename__ = 't' 
    id = Column(Integer, primary_key=True, nullable=False, unique=True) 
    value = Column(Numeric(12, 2), nullable=False) 
    #value = Column(SqliteNumeric(12, 2), nullable=False) 

    def __init__(self, value): 
     self.value = value 
+1

Tôi hy vọng bạn sẽ không phiền nếu tôi đề xuất một thay đổi nhỏ trong mã của bạn. :) Thay vì chỉ trả lại một giá trị trong process_result_value tôi sẽ đề nghị để thực hiện nếu chi nhánh: def process_result_value (tự, giá trị, phương ngữ): nếu value = "Không": trở lại D (giá trị) khác: return None – Tiho

+1

@van, Bạn đã thử truy vấn trên các cột SqliteNumeric mới chưa? Kết quả không chính xác khi so sánh chuỗi hoàn toàn khác so với so sánh số. Nếu bạn làm session.query (T) .filter (T.value> 100) bạn sẽ thấy. –

+0

Ngoài ra, tôi nghĩ rằng phần load_dialect_impl là không cần thiết, cho rằng bạn đã chỉ định impl = types.String –

15

Vì có vẻ như bạn đang sử dụng số thập phân cho các giá trị tiền tệ, tôi khuyên bạn nên làm điều an toàn và lưu trữ giá trị của tiền tệ theo mệnh giá thấp nhất của nó, ví dụ: 1610 xu thay vì 16,10 đô la. Sau đó, bạn chỉ có thể sử dụng một loại cột Integer.

Nó có thể không phải là câu trả lời bạn mong đợi, nhưng nó giải quyết được vấn đề của bạn và thường được coi là thiết kế lành mạnh.

+0

Ứng dụng của tôi cũng đang xử lý cổ phiếu và quỹ tương hỗ, ví dụ: 123.123456. – adamek

+2

Đơn vị tiền tệ tính của bạn không phải là thực, nó chỉ phải bằng với phân mục nhỏ nhất của thực thể, có thể là một cổ phiếu hoặc quỹ tương hỗ hoặc trang phục gà. ví dụ. 1231223456 gadagongs, trong đó 1 gadagong được chuyển đổi thành ví dụ kiểu thập phân với 6 chữ số chính xác cho mục đích biểu diễn. Nó không phải là một ý tưởng tồi để sử dụng loại thập phân cho đại diện bên ngoài, nhưng nó sane để sử dụng số nguyên cho đại diện nội bộ của tiền tệ. – JosefAssad

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