TABLE OF CONTENTS
- Introduction
- Prerequisites
- Project Setup
- Creating models
- User registration and login
- Implementing deposit view
- Conclusion
- Reference
Introduction
Paystack is a payment gateway that helps individuals and businesses in Africa to accept payments from anywhere in the world. In this guide, I will be showing you how to use Paystack as a third-party API to facilitate payments in your Django website.
Prerequisites
To follow through with this guide you will need:
- A good understanding of Python
- Basic understanding of Django
- Basic understanding of Html
- Usage of the Python request library
- A Paystack account
Now, let's dive into the guide, all codes can be found on Github in this repository.
Project Setup
Create a folder, start a virtual environment and start basic project
create a virtual environment using virtualenv env
activate the virtual environment using source env/Scripts/activate
install django using pip install django
this will install the latest version of django, however I am going to use version 3.0 in this guide, to install that do pip install django==3.0
Create a project and install apps
Now start the project using django-admin startproject zcore .
zcore is the name of the project and dot is used to start the project in the current directory.
Next step is two create two apps, one for authentication and another to handle all payments related code
python manage.py startapp accounts
python manage.py startapp payments
Add the newly installed apps in settings.py
Also add paystack secret and public keys in settings.py
PAYSTACK_SECRET_KEY = ""
PAYSTACK_PUBLIC_KEY = ""
where to find them on paystack
Navigate into both 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 zcore.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('accounts/', include("accounts.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)
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)
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
User registration and login
For the registration and login, I will be doing something very simple as it is not the focus of this guide.
Paste the code in accounts.views
from django.shortcuts import render, redirect
from django.contrib.auth.models import User
from payments.models import UserWallet
from django.contrib.auth import login, logout, authenticate
from django.contrib.auth.decorators import login_required
# Create your views here.
def register(request):
if request.method == "POST":
username = request.POST['username']
password = request.POST['password']
user = User.objects.create(username=username, password=password)
UserWallet.objects.create(user=user)
return render(request, "register.html")
def login_view(request):
if request.method == "POST":
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return redirect('initiate_payment')
else:
return redirect('login')
return render(request, 'login.html')
@login_required(login_url="login")
def logout_view(request):
logout(request)
return redirect('login')
Add the corresponding url paths for the views in urls.py
from django.urls import path
from . import views
urlpatterns = [
path('register/', views.register, name="register"),
path('login/', views.login_view, name="login"),
path('logout/', views.logout_view, name="logout"),
]
We will use dummy login and register page from bootstrap, file can be found in the github repo .
Setup templates dirs by adding 'DIRS': [os.path.join(BASE_DIR, 'templates')]
in settings.py
At this point you can run python manage.py runserver
and navigate to 127.0.0.1:8000/accounts/register
in your browser window to see the registration page.
You will see some warnings, to get rid of them makemigrations and migrate using;
python manage.py makemigrations
python manage.py migrate
Create a superuser so that we can login to django admin via 127.0.0.1:8000/admin
to see all the magic happening.
python manage.py createsuperuser
To see all payment objects in admin area register the payments model in payments.admin
from django.contrib import admin
from .models import Payment, UserWallet
class PaymentAdmin(admin.ModelAdmin):
list_display = ["id", "ref", 'amount', "verified", "date_created"]
admin.site.register(Payment, PaymentAdmin)
admin.site.register(UserWallet)
Implementing deposit view
Create two views, one to initiate the payment and another to verify payments.
In payments.views
from django.shortcuts import render, redirect
from .models import Payment, UserWallet
from django.conf import settings
def initiate_payment(request):
if request.method == "POST":
amount = request.POST['amount']
email = request.POST['email']
pk = settings.PAYSTACK_PUBLIC_KEY
payment = Payment.objects.create(amount=amount, email=email, user=request.user)
payment.save()
context = {
'payment': payment,
'field_values': request.POST,
'paystack_pub_key': pk,
'amount_value': payment.amount_value(),
}
return render(request, 'make_payment.html', context)
return render(request, 'payment.html')
def verify_payment(request, ref):
payment = Payment.objects.get(ref=ref)
verified = payment.verify_payment()
if verified:
user_wallet = UserWallet.objects.get(user=request.user)
user_wallet.balance += payment.amount
user_wallet.save()
print(request.user.username, " funded wallet successfully")
return render(request, "success.html")
return render(request, "success.html")
In payment.urls
from django.urls import path
from . import views
urlpatterns = [
path('initiate-payment/', views.initiate_payment, name='initiate_payment'),
path('verify-payment/<str:ref>/', views.verify_payment, name='verify_payment'),
]
The process flow goes like this;
- User inputs an amount to fund his wallet
- Clicks on pay then it takes them to page that displays the payment details
- Then proceeds to pay by clicking the pay button, this will open a payment modal handled by paystack, when the process is complete paystack will send a request to the
callback URL
which we set up to confirm the details of the transaction.
Code for the payment pages can be found in the repo
Conclusion
We have successfully integrated Paystack into our Django application and deposited an amount successfully.
All codes can be found in this repository
Reference
Connect with me on Twitter | Github
I hope this was helpful
Thanks for reading.
Top comments (5)
I am yet to implement this but it looks simple to implement compare with those Paystack payment integration documents I have seen out there. Thanks and more grace
thanks
Thank you so much for this tutorial. It really helpful. Everything worked fine. I like the way you braked things down step by step. Thank you one more time.
I am currently implementing your solution for Django Paystack but I am confused. Do you used a inline JS? or how. I can't see anything of such here
yes, you can check the code repository