{"id":13415801,"url":"https://github.com/django-money/django-money","last_synced_at":"2025-05-14T02:08:24.642Z","repository":{"id":1497900,"uuid":"1750874","full_name":"django-money/django-money","owner":"django-money","description":"Money fields for Django forms and models.","archived":false,"fork":false,"pushed_at":"2025-04-27T13:51:27.000Z","size":1426,"stargazers_count":1703,"open_issues_count":89,"forks_count":322,"subscribers_count":26,"default_branch":"main","last_synced_at":"2025-05-11T04:01:47.369Z","etag":null,"topics":["django","money","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/django-money.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":"CONTRIBUTING.rst","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":".github/SUPPORT.rst","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2011-05-15T12:13:19.000Z","updated_at":"2025-05-09T21:38:14.000Z","dependencies_parsed_at":"2024-06-18T12:23:51.181Z","dependency_job_id":"5fa8f65e-0e1c-4ac1-a1c5-9860ebdc5995","html_url":"https://github.com/django-money/django-money","commit_stats":{"total_commits":887,"total_committers":116,"mean_commits":7.646551724137931,"dds":0.7226606538895153,"last_synced_commit":"70836851ff028367438663a500ef45604bec49a7"},"previous_names":[],"tags_count":59,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/django-money%2Fdjango-money","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/django-money%2Fdjango-money/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/django-money%2Fdjango-money/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/django-money%2Fdjango-money/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/django-money","download_url":"https://codeload.github.com/django-money/django-money/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253709188,"owners_count":21951116,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","money","python"],"created_at":"2024-07-30T21:00:52.215Z","updated_at":"2025-05-14T02:08:19.630Z","avatar_url":"https://github.com/django-money.png","language":"Python","funding_links":[],"categories":["Third-Party Packages","Python","Fields","Django Utilities"],"sub_categories":["Model Fields","Models"],"readme":"django-money\n============\n\n.. image:: https://github.com/django-money/django-money/workflows/CI/badge.svg\n   :target: https://github.com/django-money/django-money/actions\n   :alt: Build Status\n\n.. image:: http://codecov.io/github/django-money/django-money/coverage.svg?branch=main\n   :target: http://codecov.io/github/django-money/django-money?branch=main\n   :alt: Coverage Status\n\n.. image:: https://readthedocs.org/projects/django-money/badge/?version=latest\n   :target: http://django-money.readthedocs.io/en/latest/\n   :alt: Documentation Status\n\n.. image:: https://img.shields.io/pypi/v/django-money.svg\n   :target: https://pypi.python.org/pypi/django-money\n   :alt: PyPI\n\nA little Django app that uses `py-moneyed \u003chttps://github.com/py-moneyed/py-moneyed\u003e`__ to add support for Money\nfields in your models and forms.\n\n* Django versions supported: 2.2, 3.2, 4.0, 4.1, 4.2\n* Python versions supported: 3.7, 3.8, 3.9, 3.10, 3.11\n* PyPy versions supported: PyPy3 (for Django \u003c= 4.0)\n\nIf you need support for older versions of Django and Python, please refer to older releases mentioned in `the release notes \u003chttps://django-money.readthedocs.io/en/latest/changes.html\u003e`__.\n\nThrough the dependency `py-moneyed \u003chttps://github.com/py-moneyed/py-moneyed\u003e`__, ``django-money`` gets:\n\n* Support for proper Money value handling (using the standard Money\n  design pattern)\n* A currency class and definitions for all currencies in circulation\n* Formatting of most currencies with correct currency sign\n\nInstallation\n------------\n\nUsing `pip`:\n\n.. code:: bash\n\n   $ pip install django-money\n\nThis automatically installs ``py-moneyed`` v1.2 (or later).\n\nAdd ``djmoney`` to your ``INSTALLED_APPS``. This is required so that money field are displayed correctly in the admin.\n\n.. code:: python\n\n   INSTALLED_APPS = [\n      ...,\n      'djmoney',\n      ...\n   ]\n\nModel usage\n-----------\n\nUse as normal model fields:\n\n.. code:: python\n\n        from djmoney.models.fields import MoneyField\n        from django.db import models\n\n\n        class BankAccount(models.Model):\n            balance = MoneyField(max_digits=14, decimal_places=2, default_currency='USD')\n\nTo comply with certain strict accounting or financial regulations, you may consider using ``max_digits=19`` and ``decimal_places=4``, see more in this `StackOverflow answer \u003chttps://stackoverflow.com/a/224866/405682\u003e`__\n\nIt is also possible to have a nullable ``MoneyField``:\n\n.. code:: python\n\n        class BankAccount(models.Model):\n            money = MoneyField(max_digits=10, decimal_places=2, null=True, default_currency=None)\n\n        account = BankAccount.objects.create()\n        assert account.money is None\n        assert account.money_currency is None\n\nSearching for models with money fields:\n\n.. code:: python\n\n        from djmoney.money import Money\n\n\n        account = BankAccount.objects.create(balance=Money(10, 'USD'))\n        swissAccount = BankAccount.objects.create(balance=Money(10, 'CHF'))\n\n        BankAccount.objects.filter(balance__gt=Money(1, 'USD'))\n        # Returns the \"account\" object\n\nThe default currency code length is `3` but you can change it with the `CURRENCY_CODE_MAX_LENGTH` setting.\n\nCaution: this setting also affects the initial migration of the `exchange` plugin, so changing it after running\nthe initial migration has no effect. (You'd need to `manage migrate exchange zero` and migrate again if you want\nto change it).\n\nField validation\n----------------\n\nThere are 3 different possibilities for field validation:\n\n* by numeric part of money despite on currency;\n* by single money amount;\n* by multiple money amounts.\n\nAll of them could be used in a combination as is shown below:\n\n.. code:: python\n\n        from django.db import models\n        from djmoney.models.fields import MoneyField\n        from djmoney.money import Money\n        from djmoney.models.validators import MaxMoneyValidator, MinMoneyValidator\n\n\n        class BankAccount(models.Model):\n            balance = MoneyField(\n                max_digits=10,\n                decimal_places=2,\n                validators=[\n                    MinMoneyValidator(10),\n                    MaxMoneyValidator(1500),\n                    MinMoneyValidator(Money(500, 'NOK')),\n                    MaxMoneyValidator(Money(900, 'NOK')),\n                    MinMoneyValidator({'EUR': 100, 'USD': 50}),\n                    MaxMoneyValidator({'EUR': 1000, 'USD': 500}),\n                ]\n            )\n\nThe ``balance`` field from the model above has the following validation:\n\n* All input values should be between 10 and 1500 despite on currency;\n* Norwegian Crowns amount (NOK) should be between 500 and 900;\n* Euros should be between 100 and 1000;\n* US Dollars should be between 50 and 500;\n\nConstructing form data\n----------------------\n\nThe default ``ModelForm`` class will use a form field (``djmoney.forms.fields.MoneyField``) that is constructed of two separate fields for amount and currency.\n\nIf you need to feed data directly to such a form (for instance if you are writing a test case), then you need to pass amount and currency like this:\n\n\n\n.. code:: python\n\n        # models.py\n        class Product(models.Model):\n            price = MoneyField(\n                max_digits=14,\n                decimal_places=2,\n                default_currency='EUR'\n            )\n\n        # forms.py\n        class ProductForm(ModelForm):\n            class Meta:\n                model = Product\n                fields = [\"price\"]\n\n        # tests.py\n\n        # construct the form in your test case\n        form = ProductForm({'price_0': 10, 'price_1': 'EUR'})\n\n\nAdding a new Currency\n---------------------\n\nCurrencies are listed on moneyed, and this modules use this to provide a\nchoice list on the admin, also for validation.\n\nTo add a new currency available on all the project, you can simply add\nthese few lines to your ``settings.py`` file:\n\n.. code:: python\n\n        import moneyed\n\n        BOB = moneyed.add_currency(\n            code='BOB',\n            numeric='068',\n            name='Peso boliviano',\n            countries=('BOLIVIA', )\n        )\n\n\nTo restrict the currencies listed on the project set a ``CURRENCIES``\nvariable with a list of Currency codes on ``settings.py``\n\n.. code:: python\n\n        CURRENCIES = ('USD', 'BOB')\n\n**The list has to contain valid Currency codes**\n\nAdditionally there is an ability to specify currency choices directly:\n\n.. code:: python\n\n        CURRENCIES = ('USD', 'EUR')\n        CURRENCY_CHOICES = [('USD', 'USD $'), ('EUR', 'EUR €')]\n\nImportant note on model managers\n--------------------------------\n\nDjango-money leaves you to use any custom model managers you like for\nyour models, but it needs to wrap some of the methods to allow searching\nfor models with money values.\n\nThis is done automatically for the \"objects\" attribute in any model that\nuses MoneyField. However, if you assign managers to some other\nattribute, you have to wrap your manager manually, like so:\n\n.. code:: python\n\n        from djmoney.models.managers import money_manager\n\n\n        class BankAccount(models.Model):\n            balance = MoneyField(max_digits=10, decimal_places=2, default_currency='USD')\n            accounts = money_manager(MyCustomManager())\n\nAlso, the money\\_manager wrapper only wraps the standard QuerySet\nmethods. If you define custom QuerySet methods, that do not end up using\nany of the standard ones (like \"get\", \"filter\" and so on), then you also\nneed to manually decorate those custom methods, like so:\n\n.. code:: python\n\n        from djmoney.models.managers import understands_money\n\n\n        class MyCustomQuerySet(QuerySet):\n\n           @understands_money\n           def my_custom_method(*args, **kwargs):\n               # Awesome stuff\n\n\nNote on serialization\n---------------------\n\nDjango-money provides a custom deserializer, it is not registered\nby default so you will have to actively register it in your ``settings.py``.\n\n.. code:: python\n\n    SERIALIZATION_MODULES = {\"json\": \"djmoney.serializers\"}\n\n\nFormat localization\n-------------------\n\nThe formatting is turned on if you have set ``USE_L10N = True`` in the\nyour settings file.\n\nIf formatting is disabled in the configuration, then in the templates\nwill be used default formatting.\n\nIn the templates you can use a special tag to format the money.\n\nIn the file ``settings.py`` add to ``INSTALLED_APPS`` entry from the\nlibrary ``djmoney``:\n\n.. code:: python\n\n        INSTALLED_APPS += ('djmoney', )\n\nIn the template, add:\n\n::\n\n        {% load djmoney %}\n        ...\n        {% money_localize money %}\n\nand that is all.\n\nInstructions to the tag ``money_localize``:\n\n::\n\n            {% money_localize \u003cmoney_object\u003e [ on(default) | off ] [as var_name] %}\n            {% money_localize \u003camount\u003e \u003ccurrency\u003e [ on(default) | off ] [as var_name] %}\n\nExamples:\n\nThe same effect:\n\n::\n\n            {% money_localize money_object %}\n            {% money_localize money_object on %}\n\nAssignment to a variable:\n\n::\n\n            {% money_localize money_object on as NEW_MONEY_OBJECT %}\n\nFormatting the number with currency:\n\n::\n\n            {% money_localize '4.5' 'USD' %}\n\n::\n\n    Return::\n\n        Money object\n\n\nTesting\n-------\n\nInstall the required packages:\n\n::\n\n    git clone https://github.com/django-money/django-money\n\n    cd ./django-money/\n\n    pip install -e \".[test]\" # installation with required packages for testing\n\nRecommended way to run the tests:\n\n.. code:: bash\n\n    tox\n\nTesting the application in the current environment python:\n\n.. code:: bash\n\n    make test\n\nWorking with Exchange Rates\n---------------------------\n\nTo work with exchange rates, add the following to your ``INSTALLED_APPS``.\n\n.. code:: python\n\n    INSTALLED_APPS = [\n        ...,\n        'djmoney.contrib.exchange',\n    ]\n\nAlso, it is required to have ``certifi`` installed.\nIt could be done via installing ``djmoney`` with ``exchange`` extra:\n\n.. code:: bash\n\n    pip install \"django-money[exchange]\"\n\nTo create required relations run ``python manage.py migrate``. To fill these relations with data you need to choose a\ndata source. Currently, 2 data sources are supported - https://openexchangerates.org/ (default) and https://fixer.io/.\nTo choose another data source set ``EXCHANGE_BACKEND`` settings with importable string to the backend you need:\n\n.. code:: python\n\n    EXCHANGE_BACKEND = 'djmoney.contrib.exchange.backends.FixerBackend'\n\nIf you want to implement your own backend, you need to extend ``djmoney.contrib.exchange.backends.base.BaseExchangeBackend``.\nTwo data sources mentioned above are not open, so you have to specify access keys in order to use them:\n\n``OPEN_EXCHANGE_RATES_APP_ID`` - '\u003cyour actual key from openexchangerates.org\u003e'\n\n``FIXER_ACCESS_KEY`` - '\u003cyour actual key from fixer.io\u003e'\n\nBackends return rates for a base currency, by default it is USD, but could be changed via ``BASE_CURRENCY`` setting.\nOpen Exchanger Rates \u0026 Fixer supports some extra stuff, like historical data or restricting currencies\nin responses to the certain list. In order to use these features you could change default URLs for these backends:\n\n.. code:: python\n\n    OPEN_EXCHANGE_RATES_URL = 'https://openexchangerates.org/api/historical/2017-01-01.json?symbols=EUR,NOK,SEK,CZK'\n    FIXER_URL = 'http://data.fixer.io/api/2013-12-24?symbols=EUR,NOK,SEK,CZK'\n\nOr, you could pass it directly to ``update_rates`` method:\n\n.. code:: python\n\n    \u003e\u003e\u003e from djmoney.contrib.exchange.backends import OpenExchangeRatesBackend\n    \u003e\u003e\u003e backend = OpenExchangeRatesBackend(url='https://openexchangerates.org/api/historical/2017-01-01.json')\n    \u003e\u003e\u003e backend.update_rates(symbols='EUR,NOK,SEK,CZK')\n\nThere is a possibility to use multiple backends in the same time:\n\n.. code:: python\n\n    \u003e\u003e\u003e from djmoney.contrib.exchange.backends import FixerBackend, OpenExchangeRatesBackend\n    \u003e\u003e\u003e from djmoney.contrib.exchange.models import get_rate\n    \u003e\u003e\u003e OpenExchangeRatesBackend().update_rates()\n    \u003e\u003e\u003e FixerBackend().update_rates()\n    \u003e\u003e\u003e get_rate('USD', 'EUR', backend=OpenExchangeRatesBackend.name)\n    \u003e\u003e\u003e get_rate('USD', 'EUR', backend=FixerBackend.name)\n\nRegular operations with ``Money`` will use ``EXCHANGE_BACKEND`` backend to get the rates.\nAlso, there are two management commands for updating rates and removing them:\n\n.. code:: bash\n\n    $ python manage.py update_rates\n    Successfully updated rates from openexchangerates.org\n    $ python manage.py clear_rates\n    Successfully cleared rates for openexchangerates.org\n\nBoth of them accept ``-b/--backend`` option, that will update/clear data only for this backend.\nAnd ``clear_rates`` accepts ``-a/--all`` option, that will clear data for all backends.\n\nTo set up a periodic rates update you could use Celery task:\n\n.. code:: python\n\n    CELERY_BEAT_SCHEDULE = {\n        'update_rates': {\n            'task': 'path.to.your.task',\n            'schedule': crontab(minute=0, hour=0),\n            'kwargs': {}  # For custom arguments\n        }\n    }\n\nExample task implementation:\n\n.. code:: python\n\n    from django.utils.module_loading import import_string\n\n    from celery import Celery\n    from djmoney import settings\n\n\n    app = Celery('tasks', broker='pyamqp://guest@localhost//')\n\n\n    @app.task\n    def update_rates(backend=settings.EXCHANGE_BACKEND, **kwargs):\n        backend = import_string(backend)()\n        backend.update_rates(**kwargs)\n\nTo convert one currency to another:\n\n.. code:: python\n\n    \u003e\u003e\u003e from djmoney.money import Money\n    \u003e\u003e\u003e from djmoney.contrib.exchange.models import convert_money\n    \u003e\u003e\u003e convert_money(Money(100, 'EUR'), 'USD')\n    \u003cMoney: 122.8184375038380800 USD\u003e\n\nExchange rates are integrated with Django Admin.\n\ndjango-money can be configured to automatically use this app for currency\nconversions by settings ``AUTO_CONVERT_MONEY = True`` in your Django\nsettings. Note that currency conversion is a lossy process, so automatic\nconversion is usually a good strategy only for very simple use cases. For most\nuse cases you will need to be clear about exactly when currency conversion\noccurs, and automatic conversion can hide bugs. Also, with automatic conversion\nyou lose some properties like commutativity (``A + B == B + A``) due to\nconversions happening in different directions.\n\nUsage with Django REST Framework\n--------------------------------\n\nMake sure that ``djmoney`` and is in the ``INSTALLED_APPS`` of your\n``settings.py`` and that ``rest_framework`` has been installed. MoneyField will\nautomatically register a serializer for Django REST Framework through\n``djmoney.apps.MoneyConfig.ready()``.\n\nYou can add a serializable field the following way:\n\n.. code:: python\n\n    from djmoney.contrib.django_rest_framework import MoneyField\n\n    class Serializers(serializers.Serializer):\n        my_computed_prop = MoneyField(max_digits=10, decimal_places=2)\n\n\nBuilt-in serializer works in the following way:\n\n.. code:: python\n\n    class Expenses(models.Model):\n        amount = MoneyField(max_digits=10, decimal_places=2)\n\n\n    class Serializer(serializers.ModelSerializer):\n        class Meta:\n            model = Expenses\n            fields = '__all__'\n\n    \u003e\u003e\u003e instance = Expenses.objects.create(amount=Money(10, 'EUR'))\n    \u003e\u003e\u003e serializer = Serializer(instance=instance)\n    \u003e\u003e\u003e serializer.data\n    ReturnDict([\n        ('id', 1),\n        ('amount_currency', 'EUR'),\n        ('amount', '10.000'),\n    ])\n\nNote that when specifying individual fields on your serializer, the amount and currency fields are treated separately.\nTo achieve the same behaviour as above you would include both field names:\n\n.. code:: python\n\n    class Serializer(serializers.ModelSerializer):\n        class Meta:\n            model = Expenses\n            fields = ('id', 'amount', 'amount_currency')\n\nCustomization\n-------------\n\nIf there is a need to customize the process deconstructing ``Money`` instances onto Django Fields and the other way around,\nthen it is possible to use a custom descriptor like this one:\n\n.. code:: python\n\n    class MyMoneyDescriptor:\n\n        def __get__(self, obj, type=None):\n            amount = obj.__dict__[self.field.name]\n            return Money(amount, \"EUR\")\n\nIt will always use ``EUR`` for all ``Money`` instances when ``obj.money`` is called. Then it should be passed to ``MoneyField``:\n\n.. code:: python\n\n    class Expenses(models.Model):\n        amount = MoneyField(max_digits=10, decimal_places=2, money_descriptor_class=MyMoneyDescriptor)\n\n\nBackground\n----------\n\nThis project is a fork of the Django support that was in\nhttp://code.google.com/p/python-money/\n\nThis version adds tests, and comes with several critical bugfixes.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdjango-money%2Fdjango-money","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdjango-money%2Fdjango-money","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdjango-money%2Fdjango-money/lists"}