2010-01-06 38 views
61

Tôi đang chạy vào một vấn đề mô hình ở đây. Tôi không biết liệu tôi có nên lưu trữ tiền dưới dạng Thập phân() hay không hoặc tôi nên lưu trữ nó dưới dạng một chuỗi và tự chuyển đổi thành số thập phân. Lý do của tôi là:Django: Tôi nên lưu trữ giá trị tiền như thế nào?

PayPal yêu cầu 2 chữ số thập phân, vì vậy nếu tôi có sản phẩm là 49 đô la, PayPal muốn xem 49.00 đi qua dây. DecimalField của Django() không đặt số thập phân. Nó chỉ lưu trữ một số lượng chữ số thập phân tối đa. Vì vậy, nếu bạn có 49 trong đó, và bạn có lĩnh vực thiết lập để 2 chữ số thập phân, nó vẫn sẽ lưu nó như 49. Tôi biết rằng Django về cơ bản là loại đúc khi nó deserializes trở lại từ cơ sở dữ liệu vào một Decimal (kể từ Cơ sở dữ liệu không có các trường thập phân), vì vậy tôi không hoàn toàn quan tâm đến các vấn đề tốc độ nhiều như tôi với các vấn đề thiết kế của vấn đề này. Tôi muốn làm những gì tốt nhất cho khả năng mở rộng.

Hoặc, tốt hơn, có ai biết cách định cấu hình django DecimalField() để luôn định dạng với kiểu định dạng TWO_PLACES không.

+1

re "vì Cơ sở dữ liệu không có trường thập phân"; Microsoft Sql Server có cả hai loại dữ liệu "thập phân" và "tiền" http://msdn.microsoft.com/en-us/library/aa258271%28v=sql.80%29.aspx –

Trả lời

60

Bạn có thể muốn sử dụng phương pháp .quantize(). Điều này sẽ làm tròn giá trị thập phân cho một số vị trí, lập luận mà bạn cung cấp quy định cụ thể số nơi:

>>> from decimal import Decimal 
>>> Decimal("12.234").quantize(Decimal("0.00")) 
Decimal("12.23") 

Nó cũng có thể mất một cuộc tranh cãi để xác định những gì phương pháp làm tròn bạn muốn (hệ thống kế toán khác nhau có thể muốn khác nhau làm tròn). Thông tin thêm trong số Python docs.

Dưới đây là trường tùy chỉnh tự động tạo giá trị chính xác. Lưu ý rằng đây chỉ là khi nó được lấy ra từ cơ sở dữ liệu, và sẽ không giúp bạn khi bạn đặt nó cho mình (cho đến khi bạn lưu nó vào db và lấy lại nó!).

from django.db import models 
from decimal import Decimal 
class CurrencyField(models.DecimalField): 
    __metaclass__ = models.SubfieldBase 

    def to_python(self, value): 
     try: 
      return super(CurrencyField, self).to_python(value).quantize(Decimal("0.01")) 
     except AttributeError: 
      return None 

[sửa]

thêm __metaclass__, xem Django: Why does this custom model field not behave as expected?

+0

Tuyệt vời. Cảm ơn whrde. Đây có phải là tất cả những gì bạn phải làm để có một trường mô hình tùy chỉnh đầy đủ chức năng? (tức là, điều này sẽ làm việc chính xác giống như DecimalField ngoại trừ định dạng). – orokusaki

+1

Ngoài ra, quy ước lưu trữ các trường tùy chỉnh là gì? Tôi nghĩ tôi sẽ đặt nó vào thư mục gốc của dự án. – orokusaki

+0

Cảm ơn, tôi chỉ sử dụng điều này. Tôi nhận thấy tôi đã phải lặp lại các thuộc tính max_digits và decimal_places mỗi khi tôi sử dụng CurrencyField, vì vậy tôi đã đăng một câu trả lời được xây dựng trên máy của bạn để giải quyết vấn đề này. –

18

Tôi nghĩ bạn nên lưu trữ nó trong một định dạng thập phân và định dạng nó để 00.00 định dạng chỉ sau đó gửi nó cho PayPal, như thế này:

pricestr = "%01.2f" % price 

Nếu bạn muốn, bạn có thể thêm một phương pháp để bạn mô hình:

def formattedprice(self): 
    return "%01.2f" % self.price 
+6

Ngoài ra: lưu trữ đơn vị tiền tệ trong cơ sở dữ liệu cũng như số tiền. Tiền không chỉ là một con số. –

+0

Đúng vậy. Cảm ơn ông Shiny và New – orokusaki

+6

Ông Shiny, bạn chắc chắn không cần phải lưu trữ tiền tệ trong cơ sở dữ liệu nếu bạn biết rằng tất cả các loại tiền tệ sẽ giống nhau. Trên thực tế, hầu hết các ứng dụng không xử lý nhiều loại tiền tệ. –

10

Tôi khuyên bạn nên tránh biểu diễn trộn với bộ nhớ. Lưu trữ dữ liệu dưới dạng giá trị thập phân với 2 vị trí.

Trong lớp giao diện người dùng, hiển thị nó trong một biểu mẫu phù hợp cho người dùng (vì vậy có thể bỏ qua ".00").

Khi bạn gửi dữ liệu đến PayPal, định dạng dữ liệu như giao diện yêu cầu.

1

Bạn lưu trữ nó dưới dạng DecimalField và thêm thủ công số thập phân nếu bạn cần, như Valya nói, sử dụng các kỹ thuật định dạng cơ bản.

Bạn thậm chí có thể thêm Phương thức mô hình cho sản phẩm hoặc mô hình giao dịch sẽ nhổ ra DecimalField dưới dạng chuỗi được định dạng thích hợp.

11

tiền nên được lưu trữ trong lĩnh vực tiền bạc, mà buồn bã không tồn tại. Vì tiền là giá trị hai chiều (số lượng, tiền tệ).

python-tiền lib, có nhiều dĩa, nhưng tôi chưa tìm được cách làm việc.


Khuyến nghị:

python-tiền lẽ là ngã ba tốt nhất https://bitbucket.org/acoobe/python-money

django tiền khuyến cáo của akumria: http://pypi.python.org/pypi/django-money/ (havent cố gắng mà một chưa).

+0

Đề nghị https://github.com/reinbach/django-money thay vì akumria vì nó có một số sửa lỗi và cài đặt thông qua pip. –

3

Theo kinh nghiệm của tôi và cũng từ others, tiền được lưu trữ tốt nhất dưới dạng kết hợp tiền tệ và số tiền bằng xu.

Rất dễ dàng để xử lý và tính toán với nó.

+0

Xin lưu ý rằng điều đó không đúng đối với mỗi loại tiền tệ mà 1 trẻ vị thành niên (ví dụ: cent) bằng 0,01 đô la (đô la). – ElmoVanKielmo

+0

Tôi không nên sử dụng thuật ngữ "xu", nhưng đơn vị nhỏ nhất không có đơn vị chia nhỏ hơn nữa của loại tiền tệ đó. –

+0

Tuy nhiên, theo cách này, ứng dụng của bạn sẽ không hỗ trợ các đơn vị tiền tệ có tỷ lệ khác nhau giữa người lớn và trẻ vị thành niên cùng một lúc. – ElmoVanKielmo

4

Xây dựng về câu trả lời @ Will_Hardy của, ở đây nó là như vậy bạn không cần phải chỉ định max_digits và decimal_places mỗi lần:

from django.db import models 
from decimal import Decimal 


class CurrencyField(models.DecimalField): 
    __metaclass__ = models.SubfieldBase 

    def __init__(self, verbose_name=None, name=None, **kwargs): 
    super(CurrencyField, self). __init__(
     verbose_name=verbose_name, name=name, max_digits=10, 
     decimal_places=2, **kwargs) 

    def to_python(self, value): 
    try: 
     return super(CurrencyField, self).to_python(value).quantize(Decimal("0.01")) 
    except AttributeError: 
     return None 
+0

Tôi có một trường tương tự như vậy, nhưng tôi sử dụng mẫu 'defaults = {...' và 'defaults.update (** kwargs)' . – orokusaki

13

cuối của tôi với phiên bản bên đó cho biết thêm sự di cư của miền Nam.

from decimal import Decimal 
from django.db import models 

try: 
    from south.modelsinspector import add_introspection_rules 
except ImportError: 
    SOUTH = False 
else: 
    SOUTH = True 

class CurrencyField(models.DecimalField): 
    __metaclass__ = models.SubfieldBase 

    def __init__(self, verbose_name=None, name=None, **kwargs): 
     decimal_places = kwargs.pop('decimal_places', 2) 
     max_digits = kwargs.pop('max_digits', 10) 

     super(CurrencyField, self). __init__(
      verbose_name=verbose_name, name=name, max_digits=max_digits, 
      decimal_places=decimal_places, **kwargs) 

    def to_python(self, value): 
     try: 
      return super(CurrencyField, self).to_python(value).quantize(Decimal("0.01")) 
     except AttributeError: 
      return None 

if SOUTH: 
    add_introspection_rules([ 
     (
      [CurrencyField], 
      [], 
      { 
       "decimal_places": ["decimal_places", { "default": "2" }], 
       "max_digits": ["max_digits", { "default": "10" }], 
      }, 
     ), 
    ], ['^application\.fields\.CurrencyField']) 
+0

Đường dẫn trong "['^ application \ .fields \ .CurrencyField']" có phải được thay đổi theo dự án của tôi không? Cám ơn – pymarco

Các vấn đề liên quan