问题
In a (postgres) SQLAlchemy model/class, I have several columns that are 'price' columns. I have read that using numeric/money/float types for this sort of data is not a good idea, so I'm storing as INTs (pennies).
I have created validators for these columns that will multiply the input value by 100 and cast to an INT upon insert and update, so that is taken care of.
How do I do the reverse? When I select this data, I want to cast these values to a float and then divide by 100. I cannot seem to find an appropriate sqlalchemy event listener to do this. Is there a correct way of doing this?
PS. As bonus points I might also want to cast to string and add a '$' prefix, so this solution would be very useful to me.
回答1:
I would not recommend using validators for this. Instead, I'd recommend using TypeDecorator; see this discussion within the SQLAlchemy documentation. You'll create a TypeDecorator for a Price type that multiplies by 100 on bind processing and divides on row processing. Here's a simple example that handles uuid types from some code I have:
from sqlalchemy.types import TypeDecorator, CHAR
import uuid
class GUID(TypeDecorator):
# Also see:
# http://docs.sqlalchemy.org/en/latest/core/custom_types.html#backend-agnostic-guid-type
impl = CHAR
def process_bind_param(self, value, dialect):
if value is None:
return value
else:
if not isinstance(value, uuid.UUID):
return uuid.UUID(value).hex
else:
return value.hex
def process_result_value(self, value, dialect):
if value is None:
return value
else:
return uuid.UUID(value)
Having impl set to char is wrong for everything besides sqlite, because that won't set the length of the column that gets declared. This should give you a good idea how to put together the price type.
来源:https://stackoverflow.com/questions/43671034/sqlalchemy-how-to-represent-data-in-python-differently-than-in-the-database