Jak powinienem obsługiwać dziesiętne w SQLalchemy & SQLite
SQLAlchemy daj mi następujące ostrzeżenie, gdy używam kolumny numerycznej z silnikiem bazy danych SQLite.
SAWarning: dialekt sqlite+pysqlite Nie nie obsługuje obiekty dziesiętne natywnie
Próbuję znaleźć najlepszy sposób, aby mieć pkgPrice = Column(Numeric(12,2))
w SQLalchemy, wciąż używając SQLite.
To pytanie[1] Jak przekonwertować Python decimal na SQLite numeric? pokazuje sposób użycia sqlite3.register_adapter(D, adapt_decimal)
aby SQLite odbierał i zwracał dziesiętne, ale przechowywał Struny, ale jeszcze nie wiem jak wkopać się w rdzeń SQLAlchemy, żeby to zrobić. Dekoratorzy typu wyglądają na właściwe podejście, ale jeszcze ich nie grok.
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?
3 answers
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-30 16:15:16
Ponieważ wygląda na to, że używasz dziesiętnych wartości waluty, sugeruję, abyś zrobił bezpieczną rzecz i przechowywał wartość waluty w 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 nie jest to odpowiedź, której się spodziewałeś, ale rozwiązuje twój problem i jest ogólnie uważany za rozsądny projekt.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-29 09:49:30
Oto rozwiązanie inspirowane zarówno @van, jak i @ JosefAssad.
class SqliteDecimal(TypeDecorator):
# This TypeDecorator use Sqlalchemy Integer as impl. It converts Decimals
# from Python to Integers which is later stored in Sqlite database.
impl = Integer
def __init__(self, scale):
# It takes a 'scale' parameter, which specifies the number of digits
# to the right of the decimal point of the number in the column.
TypeDecorator.__init__(self)
self.scale = scale
self.multiplier_int = 10 ** self.scale
def process_bind_param(self, value, dialect):
# e.g. value = Column(SqliteDecimal(2)) means a value such as
# Decimal('12.34') will be converted to 1234 in Sqlite
if value is not None:
value = int(Decimal(value) * self.multiplier_int)
return value
def process_result_value(self, value, dialect):
# e.g. Integer 1234 in Sqlite will be converted to Decimal('12.34'),
# when query takes place.
if value is not None:
value = Decimal(value) / self.multiplier_int
return value
Jak wspomniano @Jinghui Niu, gdy dziesiętny jest przechowywany jako ciągi znaków w sqlite, niektóre zapytania nie zawsze będą działać zgodnie z oczekiwaniami, np. session.query (T).filter (T. value > 100), lub rzeczy takie jak sqlalchemy.sql.ekspresja.func.min, a nawet order_by, ponieważ SQL porównuje ciągi znaków (np. " 9.2 " > "19.2" w ciągach) zamiast wartości liczbowych, jak oczekiwaliśmy w tych przypadkach.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-26 22:28:21