2012-04-27 19 views
21

SQLalchemy Dame la siguiente advertencia cuando utilizo una columna Numérica con un motor de base de datos SQLite.¿Cómo debo manejar el decimal en SQLalchemy & SQLite?

SAWarning: sqlite dialecto + pysqlite hace de soporte no objetos decimales de forma nativa

Estoy tratando de averiguar la mejor manera de tener pkgPrice = Column(Numeric(12,2)) en sqlalchemy sin dejar de utilizar SQLite.

Esta pregunta [1] How to convert Python decimal to SQLite numeric? muestra una forma de utilizar sqlite3.register_adapter(D, adapt_decimal) para tener SQLite recibir y devolver decimal, pero almacenar cadenas, pero no sé cómo profundizar en el núcleo de SQLAlchemy para hacer esto todavía. Los decoradores tipo parecen el enfoque correcto, pero todavía no los logro.

¿Alguien tiene una Receta de decorador tipo SQLAlchemy que tendrá números numéricos o decimales en el modelo SQLAlchemy, pero los almacena como cadenas en SQLite?

Respuesta

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

Espero que no te importe si sugiero un pequeño cambio en tu código. :) en lugar de devolver un valor en process_result_value voy a sugerir que hacer si la rama: def process_result_value (uno mismo, valor, dialecto): si value = "Ninguno": D retorno (valor) otra cosa: return None – Tiho

+1

@van, ¿Has intentado consultar en tus nuevas columnas SqliteNumeric? El resultado no es correcto ya que la comparación de cadenas es totalmente diferente de la comparación numérica. Si haces session.query (T) .filter (T.value> 100), verás. –

+0

Además, creo que la parte load_dialect_impl no es necesaria, dado que ya ha especificado impl = types.String –

15

Dado que parece que está usando decimales para los valores de moneda, le sugiero que haga lo más seguro y almacene el valor de la moneda en su denominación más baja, p. 1610 centavos en lugar de 16.10 dólares. Entonces solo puede usar un tipo de columna Entero.

Puede que no sea la respuesta que esperaba, pero resuelve su problema y generalmente se considera un diseño sano.

+0

Mi aplicación también se ocupa de acciones y fondos mutuos, p. 123.123456. – adamek

+2

Su unidad de conteo de moneda no tiene que ser real, solo tiene que ser igual a la subdivisión más pequeña de la entidad, ya sea una acción o un fondo mutuo o un disfraz de pollo. p.ej. 1231223456 gadagongs, donde 1 gadagong se convierte, por ejemplo, en un tipo decimal con 6 dígitos de precisión para fines de representación. No es una mala idea usar el tipo Decimal para la representación externa, pero es sensato usar números enteros para la representación interna de la moneda. – JosefAssad

Cuestiones relacionadas