添加了对在django模型和表单中使用货币和货币字段的支持。使用py-moneyed作为货币实现。
项目描述
一个小型Django应用程序,使用py-moneyed为您的模型和表单添加货币字段的支持。
- 支持的Django版本:2.2, 3.2, 4.0, 4.1, 4.2 
- 支持的Python版本:3.7、3.8、3.9、3.10、3.11 
- 支持的PyPy版本:PyPy3(适用于Django ≤ 4.0) 
如果您需要支持旧版本的Django和Python,请参阅发行说明中提到的旧版本。
通过依赖项py-moneyed,django-money获得以下支持:
- 对正确的Money值处理的支持(使用标准的Money设计模式) 
- 货币类以及所有流通货币的定义 
- 大多数货币的正确货币符号格式化 
安装
使用pip
$ pip install django-money这将自动安装py-moneyed v1.2(或更高版本)。
将djmoney添加到您的INSTALLED_APPS中。这是在管理界面正确显示货币字段所必需的。
INSTALLED_APPS = [
   ...,
   'djmoney',
   ...
]模型使用
作为正常模型字段使用
from djmoney.models.fields import MoneyField
from django.db import models
class BankAccount(models.Model):
    balance = MoneyField(max_digits=14, decimal_places=2, default_currency='USD')为了符合某些严格的会计或金融法规,您可以考虑使用max_digits=19和decimal_places=4,更多内容请参阅此StackOverflow回答
也可以有一个可空的MoneyField
class BankAccount(models.Model):
    money = MoneyField(max_digits=10, decimal_places=2, null=True, default_currency=None)
account = BankAccount.objects.create()
assert account.money is None
assert account.money_currency is None搜索具有货币字段的模型
from djmoney.money import Money
account = BankAccount.objects.create(balance=Money(10, 'USD'))
swissAccount = BankAccount.objects.create(balance=Money(10, 'CHF'))
BankAccount.objects.filter(balance__gt=Money(1, 'USD'))
# Returns the "account" object默认货币代码长度为3,但您可以通过CURRENCY_CODE_MAX_LENGTH设置来更改它。
注意:此设置也会影响exchange插件的初始迁移,因此初始迁移运行后更改此设置将没有效果。(您需要运行manage migrate exchange zero并再次迁移以更改它)。
字段验证
字段验证有3种不同的情况:
- 根据货币的数值部分进行验证,而不考虑货币本身; 
- 根据单个货币金额进行验证; 
- 根据多个货币金额进行验证。 
所有这些都可以组合使用,如下所示
from django.db import models
from djmoney.models.fields import MoneyField
from djmoney.money import Money
from djmoney.models.validators import MaxMoneyValidator, MinMoneyValidator
class BankAccount(models.Model):
    balance = MoneyField(
        max_digits=10,
        decimal_places=2,
        validators=[
            MinMoneyValidator(10),
            MaxMoneyValidator(1500),
            MinMoneyValidator(Money(500, 'NOK')),
            MaxMoneyValidator(Money(900, 'NOK')),
            MinMoneyValidator({'EUR': 100, 'USD': 50}),
            MaxMoneyValidator({'EUR': 1000, 'USD': 500}),
        ]
    )上面模型的balance字段有以下验证:
- 所有输入值应介于10和1500之间,不考虑货币本身; 
- 挪威克朗(NOK)金额应介于500和900之间; 
- 欧元应介于100和1000之间; 
- 美元应介于50和500之间; 
构造表单数据
默认的ModelForm类将使用一个表单字段(djmoney.forms.fields.MoneyField),该字段由两个单独的字段组成,一个是金额,另一个是货币。
如果您需要直接向此类表单提供数据(例如,如果您正在编写测试用例),则需要像这样传递金额和货币:
# models.py
class Product(models.Model):
    price = MoneyField(
        max_digits=14,
        decimal_places=2,
        default_currency='EUR'
    )
# forms.py
class ProductForm(ModelForm):
    class Meta:
        model = Product
        fields = ["price"]
# tests.py
# construct the form in your test case
form = ProductForm({'price_0': 10, 'price_1': 'EUR'})添加新货币
货币列在moneyed上,此模块使用它为admin提供选择列表,也用于验证。
要添加所有项目都可用的新货币,您只需将以下几行添加到您的settings.py文件中
import moneyed
BOB = moneyed.add_currency(
    code='BOB',
    numeric='068',
    name='Peso boliviano',
    countries=('BOLIVIA', )
)要限制项目上列出的货币,请在settings.py中设置一个包含货币代码列表的CURRENCIES变量
CURRENCIES = ('USD', 'BOB')该列表必须包含有效的货币代码
此外,还可以直接指定货币选择
CURRENCIES = ('USD', 'EUR')
CURRENCY_CHOICES = [('USD', 'USD $'), ('EUR', 'EUR €')]关于模型管理器的重要说明
Django-money允许您为模型使用任何您喜欢的自定义模型管理器,但它需要包装一些方法,以便能够搜索具有货币值的模型。
对于任何使用MoneyField的模型,"objects"属性将自动进行此操作。但是,如果您将管理器分配给某些其他属性,则必须手动包装您的管理器,如下所示
from djmoney.models.managers import money_manager
class BankAccount(models.Model):
    balance = MoneyField(max_digits=10, decimal_places=2, default_currency='USD')
    accounts = money_manager(MyCustomManager())此外,money_manager包装器仅包装标准QuerySet方法。如果您定义了自定义QuerySet方法,这些方法最终没有使用任何标准方法(如“get”、“filter”等),那么您还需要手动装饰这些自定义方法,如下所示
from djmoney.models.managers import understands_money
class MyCustomQuerySet(QuerySet):
   @understands_money
   def my_custom_method(*args, **kwargs):
       # Awesome stuff关于序列化的说明
Django-money提供了一个自定义反序列化器,默认情况下没有注册,因此您需要在您的settings.py中主动注册它。
SERIALIZATION_MODULES = {"json": "djmoney.serializers"}格式本地化
如果您在设置文件中设置了USE_L10N = True,则格式会被启用。
如果配置中禁用了格式,则模板将使用默认格式。
在模板中,您可以使用特殊标签来格式化货币。
在settings.py文件中,将库djmoney的条目添加到INSTALLED_APPS。
INSTALLED_APPS += ('djmoney', )在模板中添加
{% load djmoney %}
...
{% money_localize money %}
这就是全部了。
关于标签money_localize的说明
{% money_localize <money_object> [ on(default) | off ] [as var_name] %}
{% money_localize <amount> <currency> [ on(default) | off ] [as var_name] %}
示例
相同的效果
{% money_localize money_object %}
{% money_localize money_object on %}
变量赋值
{% money_localize money_object on as NEW_MONEY_OBJECT %}
使用货币格式化数字
{% money_localize '4.5' 'USD' %}
Return::
    Money object
测试
安装所需的包
git clone https://github.com/django-money/django-money cd ./django-money/ pip install -e ".[test]" # installation with required packages for testing
运行测试的推荐方式
tox在当前Python环境中测试应用程序
make test处理汇率
要处理汇率,请将以下内容添加到您的INSTALLED_APPS中。
INSTALLED_APPS = [
    ...,
    'djmoney.contrib.exchange',
]此外,还需要安装certifi。可以通过安装带有exchange附加组件的djmoney来实现。
pip install "django-money[exchange]"要创建所需的关联,请运行python manage.py migrate。要填充这些关联的数据,您需要选择一个数据源。目前支持两种数据源 - https://openexchangerates.org/(默认)和https://fixer.io/。要选择另一个数据源,请设置EXCHANGE_BACKEND设置,将其导入为所需的后端字符串。
EXCHANGE_BACKEND = 'djmoney.contrib.exchange.backends.FixerBackend'如果您想实现自己的后端,需要扩展djmoney.contrib.exchange.backends.base.BaseExchangeBackend。上面提到的两种数据源都不是公开的,因此您必须指定访问密钥才能使用它们。
OPEN_EXCHANGE_RATES_APP_ID - '<您的实际密钥来自openexchangerates.org>'
FIXER_ACCESS_KEY - '<您的实际密钥来自fixer.io>'
后端返回基本货币的汇率,默认为USD,但可以通过BASE_CURRENCY设置进行更改。Open Exchanger Rates & Fixer支持一些额外功能,如历史数据或限制响应中的货币列表。要使用这些功能,您可以更改这些后端的默认URL。
OPEN_EXCHANGE_RATES_URL = 'https://openexchangerates.org/api/historical/2017-01-01.json?symbols=EUR,NOK,SEK,CZK'
FIXER_URL = 'http://data.fixer.io/api/2013-12-24?symbols=EUR,NOK,SEK,CZK'或者,您可以直接传递给update_rates方法。
>>> from djmoney.contrib.exchange.backends import OpenExchangeRatesBackend
>>> backend = OpenExchangeRatesBackend(url='https://openexchangerates.org/api/historical/2017-01-01.json')
>>> backend.update_rates(symbols='EUR,NOK,SEK,CZK')可以同时使用多个后端。
>>> from djmoney.contrib.exchange.backends import FixerBackend, OpenExchangeRatesBackend
>>> from djmoney.contrib.exchange.models import get_rate
>>> OpenExchangeRatesBackend().update_rates()
>>> FixerBackend().update_rates()
>>> get_rate('USD', 'EUR', backend=OpenExchangeRatesBackend.name)
>>> get_rate('USD', 'EUR', backend=FixerBackend.name)常规操作中的Money将使用EXCHANGE_BACKEND后端获取汇率。此外,还有两个管理命令用于更新和删除汇率。
$ python manage.py update_rates
Successfully updated rates from openexchangerates.org
$ python manage.py clear_rates
Successfully cleared rates for openexchangerates.org这两个命令都接受-b/--backend选项,它将只更新/清除此后端的数据。并且clear_rates接受-a/--all选项,它将清除所有后端的数据。
要设置定期更新汇率,可以使用Celery任务。
CELERY_BEAT_SCHEDULE = {
    'update_rates': {
        'task': 'path.to.your.task',
        'schedule': crontab(minute=0, hour=0),
        'kwargs': {}  # For custom arguments
    }
}示例任务实现
from django.utils.module_loading import import_string
from celery import Celery
from djmoney import settings
app = Celery('tasks', broker='pyamqp://guest@localhost//')
@app.task
def update_rates(backend=settings.EXCHANGE_BACKEND, **kwargs):
    backend = import_string(backend)()
    backend.update_rates(**kwargs)将一种货币转换为另一种货币
>>> from djmoney.money import Money
>>> from djmoney.contrib.exchange.models import convert_money
>>> convert_money(Money(100, 'EUR'), 'USD')
<Money: 122.8184375038380800 USD>汇率与Django Admin集成。
django-money 可以通过设置 Django 中的 AUTO_CONVERT_MONEY = True 来自动使用此应用程序进行货币转换。请注意,货币转换是一个有损过程,因此自动转换通常只适用于非常简单的用例。对于大多数用例,您需要明确货币转换发生的时间,自动转换可能会隐藏错误。此外,由于转换方向不同,自动转换会使您失去一些属性,如交换律(A + B == B + A)。
与 Django REST Framework 一起使用
请确保 djmoney 已添加到您的 settings.py 文件中的 INSTALLED_APPS,并且已安装 rest_framework。MoneyField 会通过 djmoney.apps.MoneyConfig.ready() 自动为 Django REST Framework 注册序列化器。
您可以按照以下方式添加可序列化的字段
from djmoney.contrib.django_rest_framework import MoneyField
class Serializers(serializers.Serializer):
    my_computed_prop = MoneyField(max_digits=10, decimal_places=2)内置序列化器按以下方式工作
class Expenses(models.Model):
    amount = MoneyField(max_digits=10, decimal_places=2)
class Serializer(serializers.ModelSerializer):
    class Meta:
        model = Expenses
        fields = '__all__'
>>> instance = Expenses.objects.create(amount=Money(10, 'EUR'))
>>> serializer = Serializer(instance=instance)
>>> serializer.data
ReturnDict([
    ('id', 1),
    ('amount_currency', 'EUR'),
    ('amount', '10.000'),
])请注意,当在序列化器中指定单个字段时,金额和货币字段是分开处理的。要实现上述相同的操作,您需要包含两个字段名
class Serializer(serializers.ModelSerializer):
    class Meta:
        model = Expenses
        fields = ('id', 'amount', 'amount_currency')自定义
如果需要自定义将 Money 实例分解到 Django 字段的过程以及反向操作,则可以使用如下自定义描述符
class MyMoneyDescriptor:
    def __get__(self, obj, type=None):
        amount = obj.__dict__[self.field.name]
        return Money(amount, "EUR")它将在调用 obj.money 时始终为所有 Money 实例使用 EUR。然后应该将其传递给 MoneyField
class Expenses(models.Model):
    amount = MoneyField(max_digits=10, decimal_places=2, money_descriptor_class=MyMoneyDescriptor)背景
此项目是 http://code.google.com/p/python-money/ 中的 Django 支持的分支。
此版本添加了测试,并包含多个关键错误修复。
项目详情
下载文件
下载适合您平台的文件。如果您不确定该选择哪个,请了解更多关于安装包的信息。
源分布
构建分布
django_money-3.5.3.tar.gz的哈希值
| 算法 | 哈希摘要 | |
|---|---|---|
| SHA256 | cb8ef1adea8c682b792cc565ace45ace9525de26e3b116290951cd78c7393eab | |
| MD5 | e435938468c67569aadf31ceb8351ea2 | |
| BLAKE2b-256 | 988ca1f63e1b94f477d6f28b890c15f5352f9ecd6861e60d7e7dd4b8a6f88634 | 
django_money-3.5.3-py3-none-any.whl的哈希值
| 算法 | 哈希摘要 | |
|---|---|---|
| SHA256 | 3020c0f6b77eb4c30bdd711c7c660af67ed4b7a4750fdbdf5894788848dc6fc6 | |
| MD5 | ae65c6e3f05b38088f5f637456834584 | |
| BLAKE2b-256 | 32055712bb009945cb8e15ca340598707782b48db65bdffc57e042a0dce19914 |