2012-04-27 5 views
21

SQLalchemy дает мне следующее предупреждение, когда я использую числовой столбец с движком базы данных SQLite.Как обрабатывать десятичные знаки в SQLalchemy & SQLite

SAWarning: Диалект SQLite + pysqlite делает поддержку не десятичные объекты изначально

Я пытаюсь выяснить, лучший способ иметь pkgPrice = Column(Numeric(12,2)) в SQLAlchemy в то же время с помощью SQLite.

Этот вопрос [1] How to convert Python decimal to SQLite numeric? показывает способ использования sqlite3.register_adapter(D, adapt_decimal), чтобы получать и возвращать SQLite Decimal, но хранить строки, но я не знаю, как копаться в ядре SQLAlchemy, чтобы сделать это еще. Тип Декораторы выглядят как правильный подход, но я их еще не убегаю.

У кого-нибудь есть рецепт декодера типа SQLAlchemy, который будет иметь числовые или десятичные числа в модели SQLAlchemy, но хранить их как строки в SQLite?

ответ

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

Надеюсь, вы не возражаете, если я предлагаю вам небольшое изменение кода. :) Вместо того, чтобы просто вернуть значение в process_result_value я предлагаю сделать, если ветвь: Защиту process_result_value (самость, значение, говор): если значение = «None»: возврат D (значение) еще: return None – Tiho

+1

@van, Вы пробовали запрашивать новые столбцы SqliteNumeric? Результат неверен, поскольку сравнение строк полностью отличается от численного сравнения. Если вы выполните session.query (T) .filter (T.value> 100), вы увидите. –

+0

Кроме того, я думаю, что часть load_dialect_impl не нужна, учитывая, что вы уже указали impl = types.String –

15

Поскольку похоже, что вы используете десятичные значения для значений валюты, я предлагаю вам сделать безопасную вещь и сохранить значение валюты в ее наименьшем наименовании, например. 1610 центов вместо 16,10 долларов. Тогда вы можете просто использовать тип столбца Integer.

Возможно, это был не тот ответ, который вы ожидали, но он решает вашу проблему и, как правило, считается разумным дизайном.

+0

Мое приложение также занимается запасами и паевыми инвестиционными фондами, например. 123,123456. – adamek

+2

Ваша единица валюты счета не обязательно должна быть реальной, она должна быть равна наименьшему подразделению субъекта, будь то акции или взаимный фонд или курятник. например 1231223456 gadagongs, где 1 gadagong преобразуется, например, в десятичный тип с шестью цифрами точности для целей представления. Неплохая идея использовать тип Decimal для внешнего представления, но разумно использовать целые числа для внутреннего представления валюты. – JosefAssad

Смежные вопросы