A simple wallet django app.
A wallet is owned by a user. Should you be using a custom
user model, the wallet should still work properly as it
the wallet points to settings.AUTH_USER_MODEL
.
from wallet.models import Wallet
# wallets are owned by users.
wallet = user.wallet_set.create()
from django.db import transaction
with transaction.atomic():
# We need to lock the wallet first so that we're sure
# that nobody modifies the wallet at the same time
# we're modifying it.
wallet = Wallet.select_for_update().get(pk=wallet.id)
wallet.deposit(100) # amount
from django.db import transaction
with transaction.atomic():
# We need to lock the wallet first so that we're sure
# that nobody modifies the wallet at the same time
# we're modifying it.
wallet = Wallet.select_for_update().get(pk=wallet.id)
wallet.withdraw(100) # amount
When a user tries to withdraw from a wallet with an amount
greater than its balance, the transaction raises a
wallet.errors.InsufficientBalance
error.
# wallet.current_balance # 50
# This raises an wallet.errors.InsufficentBalance.
wallet.withdraw(100)
This error inherits from django.db.IntegrityError
so that
when it is raised, the whole transaction is automatically
rolled-back.
One can transfer a values between wallets. It uses
withdraw
and deposit
internally. Should the sending
wallet have an insufficient balance,
wallet.errors.InsufficientBalance
is raised.
with transaction.atomic():
wallet = Wallet.select_for_update().get(pk=wallet_id)
transfer_to_wallet = Wallet.select_for_update().get(pk=transfer_to_wallet_id)
wallet.transfer(transfer_to_wallet, 100)
The CURRENCY_STORE_FIELD
is a django field class that
contains how the fields should be stored. By default,
it uses django.models.BigIntegerField
. It was chosen that
way for simplicity - just make cents into your smallest
unit (0.01 -> 1, 1.00 -> 100).
You can change this to decimal by adding this to your settings.py:
# settings.py
CURRENCY_STORE_FIELD = models.DecimalField(max_digits=10, decimal_places=2)
You need to run ./manage.py makemigrations
after that.