2010-04-02 26 views
51

Tengo curiosidad por saber cuál sería más apropiado como campo monetario. Haré operaciones simples como tomar la diferencia, el porcentaje entre los precios antiguos y los nuevos. Planeo mantener dos dígitos después del cero (es decir, 10.50) y la mayoría del tiempo si estos dígitos son cero, ocultaré estos números y lo mostraré como "10"Django: FloatField o DecimalField for Currency?

pd: La moneda NO está basada en dólares :)

Respuesta

89

Siempre use DecimalField por dinero. Incluso las operaciones simples (suma, resta) no son inmunes a flotar problemas de redondeo:

>>> 10.50 - 0.20 
10.300000000000001 

>>> Decimal('10.50') - Decimal('0.20') 
Decimal('10.30') 
+4

'>>> 10.50 - 0.20' en Python 2.7 get' 10.3'. – Rockallite

+0

Welp, mierda. Voy a migrar una gran cantidad de datos de mi campo/columnas FloatField a DecimalField ... – teewuane

+0

Ya tenemos un análogo de "no usar punto flotante por dinero" en el sitio http://stackoverflow.com/a/1732454/ de Bobince 604511 – aitchnyu

6

edición: El Proyecto Satchmo ya no está activo, por lo que echar un vistazo a estas alternativas para el manejo de la moneda


El Satchmo Project basado en Django tiene un CurrencyField y CurrencyWidget que vale la pena echarle un vistazo.

Salida del directorio satchmo_utils aplicación para la fuente

32

La respuesta a la pregunta es correcta, sin embargo, algunos usuarios se tropiezan con esta pregunta para averiguar la diferencia entre el DecimalField y la FloatField. El problema de redondeo de flotación que Seth plantea es un problema para la divisa.

El Django Docs Unidos

The FloatField class is sometimes mixed up with the DecimalField class. Although they both represent real numbers, they represent those numbers differently. FloatField uses Python’s float type internally, while DecimalField uses Python’s Decimal type. Read more here .

Estas son otras diferencias entre los dos campos:

DecimalField:

  • DecimalFields debe definir un 'decimal_places' y un atributo 'MAX_DIGITS'.
  • Obtiene dos validaciones de forma libre incluidas aquí de los atributos requeridos anteriormente, es decir, si establece max_digits en 4 y escribe un decimal que es 4.00000 (5 dígitos), obtendrá este error: Asegúrese de que no haya más de 4 dígitos en total.
  • También obtiene una validación de formulario similar para decimales (que en la mayoría de los buscadores también validará en el front end utilizando el atributo step en el campo de entrada. Si establece decimal_places = 1 y escribe 0.001 como el valor que tendrá obtendrá un error que el valor mínimo tiene que ser de 0,1.
  • Devuelve un decimal.Decimal, el tipo es
  • no cuenta con la validación adicional como DecimalField
  • con un tipo decimal, redondeo también se maneja para usted debido a la los atributos necesarios que deben establecerse como se describe anteriormente. Por lo tanto, desde el shell, si
  • en la base de datos (postgresql), el DecimalField se guarda D como numéricos (MAX_DIGITS, decimal_laces) el tipo y el almacenamiento se establece como "principal", desde arriba ejemplo, el tipo es numérico (4,1)

Más en DecimalField from the Django Docs.

FloatField:

  • Devuelve el construido en el tipo float,
  • Sin redondeo inteligente, y de hecho puede dar lugar a problemas de redondeo como se describe en respuesta Seths.
  • no cuenta con la validación del formulario adicional que se obtiene de DecimalField
  • En la base de datos (PostgreSQL), el FloatField se guarda como un Tipo "doble precisión", y almacenamiento se establece como "normal"

Más sobre FloatField from the Django Docs.

se aplica a ambos:

  • Ambos campos se extienden desde la clase "campo" y pueden aceptar 'en blanco', 'nulo', 'verbose_name', 'nombre', 'primary_key', 'max_length', 'unique', 'db_index', 'rel', 'default', 'editable', 'serialize', 'unique_for_date', 'unique_for_month', 'unique_for_year', 'choices', 'help_text', 'db_column', 'db_tablespace ',' auto_created ',' validators ',' error_messages 'atributos, como todos los campos que se extienden desde "Field" tendrían.
  • El widget de formulario predeterminado para ambos campos es un TextInput.

me encontré con esta pregunta en la búsqueda de la diferencia entre los dos campos, así que creo que esto ayudará a aquellos en la misma situación :)

ACTUALIZACIÓN: Para responder a la pregunta, creo que se puede conseguir lejos con cualquiera para representar la moneda, aunque Decimal es un ajuste mucho mejor. Hay un problema de redondeo cuando cuenta flotar, por lo que debe usar round(value, 2) para mantener su representación flotante redondeada a dos decimales. Aquí hay un ejemplo rápido:

>>> round(1.13 * 50 + .01, 2) 
56.51 

Todavía puede tener problemas con el flotador y la rueda. Como aquí lo vemos redondea hacia abajo en un valor de 5:

>>> round(5.685, 2) 
5.68 

Pero en este caso, se redondeará hacia arriba:

>>> round(2.995, 2) 
3.0 

Ha que ver con la forma en que el flotador está almacenado en la memoria . Ver here.

Cuestiones relacionadas