Installation

Install the package

$ pip install django-payments

Most providers have additional dependencies. For example, if using stripe, you should run:

$ pip install "django-payments[stripe]"

Multiple providers can be specified comma-separated, e.g.:

$ pip install "django-payments[mercadopago,todopago]"

Hint

Use quotes as above to prevent your shell from parsing the square brackets.

Changed in version 0.15: Each provider now has extra/optional dependencies. Previously, dependencies for all providers was installed by default.

Configure Django

payments needs to be registered as a Django app by adding it to settings.py:

INSTALLED_APPS = [
  ...
  "payments",
  ...
]

Add the callback processor to your URL router (urls.py).

# urls.py
from django.conf.urls import include, path

urlpatterns = [
    path('payments/', include('payments.urls')),
]

These are URLs where notifications from payment providers will be received and where user will be redirected after completing payments.

Create a “Payment” class

Django-payments ship an abstract payments.models.BasePayment:: class. Individual projects need to subclass it and implement a few methods and may include any extra payment-related fields on this model. It is also possible to add a foreign key to an existing purchase or order model.

# mypaymentapp/models.py
from decimal import Decimal

from payments import PurchasedItem
from payments.models import BasePayment

class Payment(BasePayment):

    def get_failure_url(self) -> str:
        # Return a URL where users are redirected after
        # they fail to complete a payment:
        return 'http://example.com/failure/'

    def get_success_url(self) -> str:
        # Return a URL where users are redirected after
        # they successfully complete a payment:
        return 'http://example.com/success/'

    def get_purchased_items(self) -> Iterable[PurchasedItem]:
        # Return items that will be included in this payment.
        yield PurchasedItem(
            name='The Hound of the Baskervilles',
            sku='BSKV',
            quantity=9,
            price=Decimal(10),
            currency='USD',
        )

Create a payment view

Write a view that will handle the payment. You can obtain a form instance by passing POST data to payment.get_form():

# mypaymentapp/views.py
from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse
from payments import get_payment_model, RedirectNeeded

def payment_details(request, payment_id):
    payment = get_object_or_404(get_payment_model(), id=payment_id)
    try:
        form = payment.get_form(data=request.POST or None)
    except RedirectNeeded as redirect_to:
        return redirect(str(redirect_to))
    return TemplateResponse(request, 'payment.html',
                            {'form': form, 'payment': payment})

Note

Please note that Payment.get_form() may raise a RedirectNeeded exception. In this case, you need to redirect the user to the supplied URL.

Prepare a template that displays the form using its action and method:

<!-- templates/payment.html -->
<form action="{{ form.action }}" method="{{ form.method }}">
    {% csrf_token %}
    {{ form.as_p }}
    <p><input type="submit" value="Proceed" /></p>
</form>

Additional Django settings

Additionally, you’ll need to configure a few extra settings:

# This can be a string or callable, and should return a base host that
# will be used when receiving callbacks and notifications from payment
# providers.
#
# Keep in mind that if you use `localhost`, external servers won't be
# able to reach you for webhook notifications.
PAYMENT_HOST = 'localhost:8000'

# Whether to use TLS (HTTPS). If false, will use plain-text HTTP.
# Defaults to ``not settings.DEBUG``.
PAYMENT_USES_SSL = False

# A dotted path to your Payment class (see above).
PAYMENT_MODEL = 'mypaymentapp.Payment'

# Named configuration for your payment provider(s).
#
# Each payment processor takes different arguments.
# This setting is a tuple, where the first element is the variant's name
# (this is just a local alias), and the second element is a dict with
# the provider-specific attributes (generally API keys or alike).
#
# See Backends for details.
PAYMENT_VARIANTS = {
    'default': ('payments.dummy.DummyProvider', {})
}

# Callable to retrieve payment provider instance
#
# This is an advanced setting. It is required if defining provider
# credentials in the settings file is unsuitable. Implementations may choose
# to read provider credentials from the database or any other source that's
# suitable.
#
# Alternatively, you can provide a callable that takes two arguments:
# variant (string) and an optional payment (BasePayment).
# The callback has to return an instance of the desired payment provider.
#
# For inspiration, see the payments.core.payment_factory function, which
# retrieves the variant from the above dictionary.
PAYMENT_VARIANT_FACTORY = "mypaymentapp.provider_factory"

Hint

Variant names are used in URLs so it’s best to stick to ASCII.