2012-04-27 11 views
21

SQLalchemy przekazuje mi następujące ostrzeżenie, gdy używam kolumny liczbowej z silnikiem bazy danych SQLite.Jak obsługiwać znaki dziesiętne w SQLalchemy i SQLite

SAWarning: Dialekt SQLite + pysqlite robi nie wsparcia dziesiętne obiektów natywnie

usiłuję dowiedzieć się najlepszym sposobem na pkgPrice = Column(Numeric(12,2)) w sqlalchemy jednocześnie przy użyciu SQLite.

To pytanie [1] How to convert Python decimal to SQLite numeric? pokazuje sposób użycia sqlite3.register_adapter(D, adapt_decimal), aby SQLite odebrał i zwrócił wartość dziesiętną, ale zapisał ciągi znaków, ale nie wiem, jak zagłębić się w rdzeń SQLAlchemy, aby to zrobić. Typ Dekoratory wyglądają jak właściwe podejście, ale jeszcze ich nie gram.

Czy ktoś ma przepis dekoratora typu SQLAlchemy, który będzie miał liczby numeryczne lub dziesiętne w modelu SQLAlchemy, ale przechowuje je jako ciągi w SQLite?

Odpowiedz

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

Mam nadzieję, że nie będziesz miał nic przeciwko, jeśli zasugeruję jedną małą zmianę w tobie. :) Zamiast powrocie wartość w process_result_value ja proponuję zrobić, jeśli oddział: def process_result_value (self, wartość, dialekt): jeśli wartość = "Brak": powrót D (wartość) else: return Brak – Tiho

+1

@van, Czy próbowałeś kwerendy na swoich nowych kolumnach SqliteNumeric? Wynik nie jest poprawny, ponieważ porównywanie ciągów znaków jest zupełnie inne niż porównanie numeryczne. Jeśli wykonasz session.query (T) .filter (T.value> 100), zobaczysz. –

+0

Ponadto myślę, że część load_dialect_impl jest niepotrzebna, biorąc pod uwagę, że zostały już określone impl = types.String –

15

Ponieważ wygląda na to, że używasz wartości dziesiętnych dla wartości walutowych, sugerowałbym, abyś zrobił to, co bezpieczne i zapisał wartość waluty w swoim najniższym nominale, np. 1610 centów zamiast 16,10 dolarów. Następnie możesz po prostu użyć typu kolumny Integer.

Może to nie być odpowiedź, której się spodziewałeś, ale rozwiązuje ona Twój problem i jest ogólnie uznawana za zdrowy projekt.

+0

Moja aplikacja obsługuje również akcje i fundusze powiernicze, np. 123.123456. – adamek

+2

Twoja jednostka liczenia waluty nie musi być prawdziwa, po prostu musi być równa najmniejszemu podziałowi jednostki, czy to funduszowi akcji, funduszowi wzajemnemu czy strojowi z kurczaka. na przykład 1231223456 gadagongs, gdzie 1 gadagong zostaje przekonwertowany na przykład na typ dziesiętny z 6 cyframi dokładności do celów reprezentacyjnych. Nie jest złym pomysłem użycie typu dziesiętnego do reprezentacji zewnętrznej, ale używanie liczb całkowitych do wewnętrznej reprezentacji waluty jest normalne. – JosefAssad

Powiązane problemy