2012-04-27 13 views
21

SQLalchemy mi danno il seguente avviso quando uso una colonna numerica con un motore di database SQLite.Come dovrei gestire il decimale in SQLalchemy e SQLite

SAWarning: Dialetto SQLite + pysqlite fa non supporto oggetti decimali nativamente

Sto cercando di capire il modo migliore per avere pkgPrice = Column(Numeric(12,2)) in SQLAlchemy pur utilizzando SQLite.

Questa domanda [1] How to convert Python decimal to SQLite numeric? mostra un modo per utilizzare sqlite3.register_adapter(D, adapt_decimal) avere SQLite ricevere e restituire decimale, ma memorizzare le stringhe, ma non so come scavare nel nucleo SQLAlchemy per farlo ancora. I decoratori di tipo sembrano l'approccio giusto ma non li sto ancora cercando.

Qualcuno ha una ricetta Decoratore tipo SQLAlchemy che avrà numeri numerici o decimali nel modello SQLAlchemy, ma li memorizzerà come stringhe in SQLite?

risposta

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

Spero non ti dispiaccia se suggerisco un piccolo cambiamento nel tuo codice. :) Invece di limitarsi a restituire un valore in process_result_value io suggerisco di fare se il lato: def process_result_value (auto, il valore, il dialetto): se value = "None":! ritorno D (valore) altro: return None – Tiho

+1

@van, hai provato a eseguire query sulle nuove colonne SqliteNumeric? Il risultato non è corretto in quanto il confronto tra stringhe è completamente diverso dal confronto numerico. Se fai session.query (T) .filter (T.value> 100) vedrai. –

+0

Inoltre, penso che la parte load_dialect_impl non sia necessaria, dato che hai già specificato impl = types.String –

15

Poiché sembra che si stiano utilizzando i decimali per i valori di valuta, suggerirei di fare la cosa sicura e di memorizzare il valore della valuta nella sua denominazione più bassa, ad es. 1610 centesimi anziché 16,10 dollari. Quindi puoi semplicemente usare un tipo di colonna Integer.

Potrebbe non essere la risposta che ti aspettavi, ma risolve il tuo problema ed è generalmente considerato un design sano.

+0

La mia app si occupa anche di azioni e fondi comuni, ad es. 123,123,456 mila. – adamek

+2

La tua unità di conteggio della valuta non deve essere reale, deve solo essere uguale alla più piccola suddivisione dell'entità, che si tratti di un fondo azionario o di fondi comuni o di un costume da pollo. per esempio. 1231223456 gadagongs, in cui 1 gadagong viene convertito ad esempio in un tipo Decimal con 6 cifre di precisione a fini di rappresentazione. Non è una cattiva idea usare il tipo Decimal per la rappresentazione esterna, ma è ragionevole usare gli interi per la rappresentazione interna della valuta. – JosefAssad

Problemi correlati