How to build a custom checkout page in minutes with Django and JavaScript.
Tags: python, javascript, tutorial, django
Published: 2019-11-25 10:17:14

---
title: How to build a custom checkout page in minutes with Django and JavaScript.
published: true
description: A tutorial that shows how to build a checkout page that accepts one time payments using Django - a Python framework.
tags: python, javascript, productivity, tutorial
---

When implementing payment options in an app, it's always a good idea to have a payment process that's as brief and straightforward as possible. In this article, we're going to build a checkout modal to process one time payments on web apps using [Rave](https://flutterwave.com/online-payments-products/rave/), Django and JavaScript. To solve the issue of using `pip` and `virtualenv` together, we'll use `pipenv` to create our development environment. If you need help setting up `pipenv`, please check out this guide.



## Setting up a Project

The first thing we'll do is install Django. Then we'll start a new project which we'll name `djangorave`.  In this project, we'll create our first app which we'll call  `payments`.  Navigate to your terminal and input the following commands:

```bash  
   # install Django
   $ pipenv install django

   # activate the pipenv shell to start a new shell subprocess
   $ pipenv shell

   (rave-checkout-python) $ django-admin startproject djangorave
   (rave-checkout-python) $ python manage.py startapp payments

```

Note that the virtual environment `rave-checkout-python` is just a part of my code directory, yours can be anything you choose. Let's add the newly installed app to the  `INSTALLED_APPS` configuration in `settings.py`:

```python  
INSTALLED_APPS = [
    'django.contrib',
    'django.contrib.admin',
    'django.contrib .auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    #update the newly installed app
    'payments.apps.PaymentsConfig',
]

```

Next, in the same folder we'll update the `urls.py` file to include the  `payments` app:

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

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

```

Our next step is to create a homepage for our application. In the  `djangorave` parent folder, create a folder named `templates` and in it, your homepage:

```python

(rave-checkout-python) $ mkdir templates
(rave-checkout-python) $ touch templates/homepage.html
```

Then we'll update the `settings.py` file so Django can access the  `templates` folder:

```python

#djangorave/settings.py

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['templates'], # add this line
        'APP_DIRS': True,
     },
]
```

We'll just fill the homepage with a basic message for now:

```python
   
   # templates/homepage.html

   My First Django app
```

Then in the `payments` folder, we'll create a `views.py` file where Django class-based and generic views will be used to render the homepage:

```python
   
   # payments/views.py

   from django.views.generic.base import TemplateView

   class HomePageView(TemplateView):
       template_name = 'homepage.html'
```

The view exists but it doesn't have a URL path yet. Let's change this by creating a  `urls.py` in our `payments` app where we'll assign a path to our view:

```python
    #payments/urls.py
    
    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('', views.HomePageView.as_view(), name='homepage'),
    ]

```

At this point, our app is good enough to be viewed on the browser. Let's synchronize the changes we've made so far to our database and start the app on our local server:

```python
  
# use the migrate command to sync to your database
(rave-checkout-python) $ python manage.py migrate

# start a local webserver with the runserver command
(rave-checkout-python) $ python manage.py runserver
```

This starts up your app on `http://127.0.0.1:8000/`. Navigate to this path on your browser and you should see your home page:


![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/sp595qn6x8s4yf8g9vd1.png)


## Integrate Rave

The second phase of building this app will be to integrate Rave into the app. Head on to Rave's [website](https://rave.flutterwave.com/signup) and sign up for an account. On your dashboard, first switch from live mode to test mode then navigate to  `Settings > API` and get your API keys:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/eopdbn9k71gnh196sguw.png)

Copy your public and secret keys and paste them at the bottom of your  `settings.py`  file. Be sure to include the inverted commas:

```python

    #settings.py
    
    RAVE_PUBLIC_KEY = 'YOUR PUBLIC KEY HERE'
    RAVE_SECRET_KEY = 'YOUR SECRET KEY HERE'

```

## Building the checkout form

Now we have our API keys, let's add Rave's [inline script](https://developer.flutterwave.com/docs/rave-inline) to our  `homepage.html` file:

```javascript

    <form>
      <script src="https://api.ravepay.co/flwv3-pug/getpaidx/api/flwpbf-inline.js"></script>
        <h3>SUPPORT NATURE WITH AS LOW AS $1</h3>
        <button type="button" onClick="payWithRave()">Donate Here</button>
    </form>
    <script>
        const publicKey = "{{ key }}";
    
        function payWithRave() {
            var x = getpaidSetup({
                PBFPubKey: publicKey,
                customer_email: "user@example.com",
                amount: 1,
                customer_phone: "234099940409",
                currency: "USD",
                txref: "rave-123456",
                custom_title: "Wildlife Park",
                onclose: function() {},
                callback: function(response) {
                    var txref = response.tx.txRef;
                    console.log("This is the response returned after a charge", response);
                    x.close();
                }
            });
        }
    </script>

```

In the above template, you'll notice there's a `{{ key }}` attribute assigned to the `publickey` constant.  It should hold the value of our Rave public key. Let's update its value in `views.py`:

```javascript
   
# payments/views.py

from django.conf import settings
from django.views.generic.base import TemplateView

class HomePageView(TemplateView):
    template_name = 'homepage.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['key'] = settings.RAVE_PUBLIC_KEY
        return context
```

Hit the refresh button and a basic HTML page that we can work with comes up:

Click on the  `Donate Here`  button and a modal customized by Rave opens up for you to make payment:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/db4k3wa6d2htd9tp8i57.png)


Make a test payment by using one of Rave's [test cards here](https://developer.flutterwave.com/docs/test-cards). Let's use `5531 8866 5214 2950`, ensure that the expiry date and CVV number are correctly inputted as well. If prompted for an OTP or PIN, use the specified values in the list of cards:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ak0t6mlx58ejuurn7gs7.png)

To confirm that payment was successful, head on to your Rave dashboard and click on  **`Transactions`**  to access your transaction history:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/cuylw6nz1vt41lfpxpg9.png)


## Payment verification from the user's end

Sure our merchants can tell that payments are being made to their Rave account but how can a user tell that their payment was successful? Let's create a page that displays a success message to a user whenever they make a successful payment. In the  `templates`  folder, create a new file  `success.html`:

```javascript
# templates/success.html

<h3>Your payment was successful<h3/>
```


Next, we'll create a view for `success.html`:

```python
   
#payments/views.py

from django.shortcuts import render
from django.conf import settings
from django.views.generic.base import TemplateView
class HomePageView(TemplateView):
    template_name = 'home.html'
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['key'] = settings.RAVE_PUBLIC_KEY
        context['logo'] = settings.WILDLIFE_LOGO
        return context

# create the view here
class Success(TemplateView):
    template_name = 'success.html'
```

Then we'll create a URL Pattern for the view:

```python

    #payments/urls.py
    
    from django.urls import path
    from . import views
    urlpatterns = [
        path('success.html', views.Success.as_view(), name='success') #add this line,
        path('', views.HomePageView.as_view(), name='home'),
    ]

```

Lastly, we'll include  `success.html`   in the  callback  function in  `homepage.html`:

```python

    callback: function(response) {
        var txref = response.tx.txRef;
        console.log("This is the response returned after a charge", response);
        if (
            response.tx.chargeResponseCode == "00" ||
            response.tx.chargeResponseCode == "0"
        ) {
            document.location.href = "success.html"
                // redirect to a success page
        } else {
            // redirect to a failure page.
        }
        x.close();
    }

```

Seems we're good to go. Let's make a test payment and see what the flow looks like:

{% youtube Okg_E8gs6S0 %}


## Summary

In a more practical scenario, we would use a more secure connection and also be more careful with handling our API keys by storing them securely in environment variables. Should you need the source code of this demo, you can find it [here](https://github.com/fullstackmafia/donation-page-django).