Bookmarks

You haven't yet saved any bookmarks. To bookmark a post, just click .

  • Create a Django API in These 5 Steps

  • Maybe you want to make changes to database and also reflect that back on the webpage for a user on a click of a button; without reloading, sort of like an app, right? Well what you are looking for is AJAX (Asynchronous JavaScript And XML).

    Basically we are going to do two things:

    1. Make a call to an API (Application Programming Interface) written in Django along with your project (Yes, you are going to make an API now! Yayyyy!). The API is going to perform some operation on database.
    2. Then our API, sends back data in JSON(JavaScript Object Notation) format; a good way to represent data stored in key-value pair. Then use this data to update the DOM elements.
    Why not XML?

    Because the way how JSON is represented in JavaScript, is similar to how Python data Structure “Dictionary” is created; so it gets a little easier when writing an API.

    Let’s get started.


    Step 1

    I’ll go along with an example. Let’s say a user wants to add an item to Wish List. Now we need to know two things:

    1. What is the product ID?
    2. What is the Action?

    For now Action will be add.

    Where should I save this value?

    We will keep the the product ID and action in our HTML and associate it with particular button using custom data attribute, in our case data-product and data-action in our template.

    <!- ALong with other HTML -->
    <button type="button" 
    	class="btn btn-light btn-block border mt-2 update-wishlist" 
        data-action="add" 
        data-product="{{ product.productID }}">
        <span class="text"> Add to Wishlist</span>                                 
    </button>  
    index.html

    Also add a class so that we can look up for this button in JavaScript. I used update-wishlist.


    Step 2

    Ok, but how do we pass this value to the server?

    Using JavaScript.

    Remember we added a class update-wishlist to our button. We can use getElementsByClassName or querySelectorAll function to add an event listener to our buttons.

    window.addEventListener('load',function () {
      console.log('Loaded')
      let wislistBtns = document.querySelectorAll('.update-wishlist')
      if (wislistBtns) {
          for (let i = 0; i < wislistBtns.length; i++) {
              wislistBtns[i].addEventListener('click', function () {
                  const productID = this.dataset.product
                  const action = this.dataset.action
                  console.log('productID:', productID, 'Action:', action)
                  if (user === 'AnonymousUser') {
                      console.log('User is Anonymous')
                  } else {
                      updateUserWishlist(productID, action)
                  }
              })
          }
      }
    })
    index.js

    Now, as soon as the page is loaded, the script runs, and adds the event Listener to all of our buttons with class update-wishlist.

    But wait, we haven’t wrote the function updateUserWishlist yet!
    function updateUserWishlist(productID,action){
        console.log('user:',user,' is Authenticated, sending data')
        let url= '/api/update_wishlist/'
        fetch(url,{
            method:'PUT',
            headers:{
                'Content-Type':'application/json',
                'X-CSRFToken':csrftoken,
            },
            body:JSON.stringify({'productID':productID, 'action':action})
        }).then((response)=>
            response.json()
        ).then(function (data){
                console.log('data:',data)
                updateNavbar(data)
            })
    }

    Yeah, This is where we are going to call our API and get some data.

    What’s going on here?

    Basically we are using fetch API to fetch resource from a URI, which is the endpoint of our API.

    Method (on line no. 5) provides information for the request you’re making from API. It can either of these, depending on the use case.

    • GET : To perform a ‘READ’ operation
    • POST : To perform a ‘CREATE’ operation
    • PUT & PATCH : To perform an ‘UPDATE’ operation
    • DELETE : To perform ‘DELETE’ operation

    But Remember each method specify a specific operation which could only be performed on the database. If the API doesn’t accept the method which you have specified, you’ll get an error like this in console.

    405 (Method Not Allowed)

    Headers (on line no. 6) represents response/request headers, allowing you to query them and take different actions depending on the results.

    Body (on line no. 7) represents the response to a request.

    This fetch method returns a promise containing the response (a Response object). Currently, we will send the product ID and Action.

    The response then has to be read as JSON, and pass it to another function updateNavbar() where we will update the navbar. Replace it with your own function which will update DOM elements.

    Add the file to the end of your index.html along with other JavaScript file.


    Step 3

    Now we need to process our data, but first we need to setup few things. Open up your Project in your favourite IDE/text editor and follow along.

    Step 1 : Install Django Rest Framework.

    From your project root run a terminal and write this command to install pip package.

    pip install djangorestframework

    Step 2: Let’s start with creating a new app.

    We first need to create a new app, I’ll name it serverapi . So we will run a command again in the terminal.

    python manage.py startapp serverapi

    Step 3: Add app and rest_framework to your Django settings.py file INSTALLED_APPS list

    Along with your other apps, add your server API app in this way,

    appname.apps.AppnameConfig
    # Application definition
    INSTALLED_APPS = [
      'rest_framework',
      'serverapi.apps.ServerapiConfig',
      'otherapp',
      'otherapp2',
    ]
    settings.py

    Step 4: Add URL to your Project’s main urls.py and to urls.py file of your new app.

    In your main urls.py file add the path to your URL file of your newly created app along with other URLs.

    # yourproject\urls.py
    # add your other necessary imports 
    
    urlspatterns = [
      re_path('^api/', include(('serverapi.urls', 'serverapi'), namespace='api')),
    ]
    Main urls.py

    And, now we will add a path to view function in your newly created app.

    # serverapi\urls.py
    from django.urls import path
    from serverapi import views
    
    appname = 'serverapi'
    urlpatterns = [
        path('update_wishlist/', views.updateWishlist, name='updateWishlist'),
    ]
    urls.py file of the created app

    Step 4

    Now, that we have everything setup, we can now write our views.

    # serverapi\view.py
    from rest_framework.decorators import api_view
    from django.http import JsonResponse
    
    @api_view(['PUT'])
    def updateWishlist(request):
        data = json.loads(request.body)
        productID = data['productID']
        action = data['action']
        print('ProductID:', productID)
        print('Action:   ', action)
    
        if request.user.is_authenticated:
            customer = request.user
            wishList, created = Wishlist.objects.get_or_create(customer=customer)
    
            if action == 'add':
                wishList.add_item(productID)
                return JsonResponse({'wishlistItemQuantity': wishList.get_wishlist_quantity})
    
            elif action == 'add_to_cart':
                return JsonResponse({'cartItemQuantity': wishList.add_to_cart(productID),
                                    'wishlistItemQuantity': wishList.get_wishlist_quantity})
    
    serverapi/views.py

    The api_view decorator, takes a list of HTTP methods that your view should respond to. Then we go ahead to access the data from request, so that we can see what was passed on to the server. This is wherever you need to make sure only those methods are allowed which the view is written for.

    Now, just like normal views we go ahead to process the database based on what was the action, once done we return a JsonResponse which can then be received in our JavaScript.


    Step 5

    Ok, but when did we updated the DOM elements?

    Remember we passed the Response to updateNavbar in Step 2. You can use the passed data as you may wish. For now I will be updating the navbar.

    function updateNavbar(data){
        document.getElementById('wishlist').innerHTML = 'Wishlist<span class="badge badge-danger" style="vertical-align: top;"><h7>' + data['wishlistItemQuantity'] + '</h7></span>'
    }
    updateNavbar.js

    Also, we haven’t added the CSRF(Cross Site Request Forgery protection) token. In layman terms, we want to accept request only from original application and not from an external site while pretending to be from the origin application; In a measure to avoid execution of malicious actions by attackers.

    So, either add below lines directly inside your index.html or create a new .js file and add it inside your head tag.

    let user = '{{ request.user }}'
    function getToken(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
    }
    const csrftoken = getToken('csrftoken');
    csrf.js

    Result

    This is from a part of a project I was recently working on; Shopiva.