Integrating Paystack payments in Django

Django and Paystack Integrating

Integrating Paystack payments in Django

Introduction

Paystack is a payment gateway that helps individuals and businesses in Africa accept payments from anywhere in the world. In this guide, I will show you how to use Paystack as a third-party API to handle payments on your Django website.

Prerequisites

To follow this guide, you need:

  • A good understanding of Python

  • Basic knowledge of Django

  • Basic knowledge of HTML

  • Familiarity with the Python requests library

  • A Paystack account

Project Setup

CCreate a folder, start a virtual environment, and set up the basic project
Create a virtual environment using python -m venv env on Windows. Use virtualenv env on Mac/Linux.
Activate the virtual environment with .\env\Scripts\activate on Windows or source env/bin/activate on Mac/Linux.
Install Django using pip install django. This will install the latest version of Django, but you can use any version you prefer. It's best to use the latest version for all your projects.

Create a project and install apps
Start the project with django-admin startproject core .
core is the project name, and the dot means the project starts in the current folder.
The next step is to create two apps: one for user authentication and another for handling all payment-related code.

python manage.py startapp users
python manage.py startapp payments

Add the newly installed apps in settings.py

Also add paystack secret and public keys in settings.py

Where to find them on paystack

Navigate into both Apps folders created and add a new file called urls.py and add the following code

from django.urls import path

urlpatterns = [

]

Include these urls in main url file core.urls
Your file should look like this

from  django.contrib  import  admin
from  django.urls  import  path, include

urlpatterns  = [
    path('admin/', admin.site.urls),
    path('users/', include("users.urls")),
    path('payments/', include("payments.urls")),
]

Creating models

Next step is to create a wallet model to keep track of funds deposited by a user and a payment model to describe what a payment is.
In payments.model

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
import secrets
from .paystack  import  Paystack

# Create your models here.
class UserWallet(models.Model):
    user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
    created_at = models.DateTimeField(default=timezone.now, null=True)

    def __str__(self):
        return self.user.__str__()

class Payment(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
    amount = models.PositiveIntegerField()
    ref = models.CharField(max_length=200)
    email = models.EmailField()
    verified = models.BooleanField(default=False)
    date_created = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ('-date_created',)

    def __str__(self):
        return f"Payment for {user}: {self.amount}"

    def save(self, *args, **kwargs):
        while not self.ref:
            ref = secrets.token_urlsafe(50)
            object_with_similar_ref = Payment.objects.filter(ref=ref)
            if not object_with_similar_ref:
                self.ref = ref

        super().save(*args, **kwargs)

We will need another helper class to handle payment verification, so in the payments folder create a file called paystack.py
paste this block of code in the file

from django.conf import settings
import requests

class Paystack:
    PAYSTACK_SK = settings.PAYSTACK_SECRET_KEY
    base_url = "https://api.paystack.co/"

    def verify_payment(self, ref, *args, **kwargs):
        path = f'transaction/verify/{ref}'
        headers = {
            "Authorization": f"Bearer {self.PAYSTACK_SK}",
            "Content-Type": "application/json",
        }
        url = self.base_url + path
        response = requests.get(url, headers=headers)

        if response.status_code == 200:
            response_data = response.json()
            return response_data['status'], response_data['data']

        response_data = response.json()

        return response_data['status'], response_data['message']

you will need to install requests for this so do a quick pip install requests
with that we can now add a verify payment property on our payment model

def amount_value(self):
        return int(self.amount) * 100

def verify_payment(self):
    paystack = Paystack()
    status, result = paystack.verify_payment(self.ref, self.amount)
    if status:
        if result['amount'] / 100 == self.amount:
            self.verified = True
        self.save()
    if self.verified:
        return True
    return False

Your model should look like this:

from django.db import models

# Create your models here.
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
import secrets
from .paystack  import  Paystack

# Create your models here.
class UserWallet(models.Model):
    user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
    currency = models.CharField(max_length=50, default='NGN')
    created_at = models.DateTimeField(default=timezone.now, null=True)

    def __str__(self):
        return self.user.__str__()

class Payment(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
    amount = models.PositiveIntegerField()
    ref = models.CharField(max_length=200)
    email = models.EmailField()
    verified = models.BooleanField(default=False)
    date_created = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ('-date_created',)

    def __str__(self):
        return f"Payment: {self.amount}"

    def save(self, *args, **kwargs):
        while not self.ref:
            ref = secrets.token_urlsafe(50)
            object_with_similar_ref = Payment.objects.filter(ref=ref)
            if not object_with_similar_ref:
                self.ref = ref

        super().save(*args, **kwargs)

    def amount_value(self):
        return int(self.amount) * 100

    def verify_payment(self):
        paystack = Paystack()
        status, result = paystack.verify_payment(self.ref, self.amount)
        if status:
            if result['amount'] / 100 == self.amount:
                self.verified = True
            self.save()
        if self.verified:
            return True
        return False

To be continued.