top of page
  • 5.15 Technologies

API Development in Django: Accessing Your Data With REST

Imagine this scenario: you've built an amazing Django application that's helping you manage your business more efficiently. Now you're getting requests from customers and partners requesting access to your data and functionality from their own systems. You could manually provide them with access to your database or even build custom integrations for each request, but that's time-consuming and risky.


The solution? Creating an API (Application Programming Interface) for your Django application! With an API, you can securely expose specific data and functionality from your application to other systems. Without exposing your entire database or application code. This opens a whole new world of possibilities. From building mobile apps to integrating with third-party services. But where do you start? Don't worry, we'll take a look at that, so you can start building your own API using Django.


Environment Setup

Implementing an API into your Django application does not require much configuration and setup, but we’ll walk through the different pieces to get everything up and running. This implementation uses our Django Sample Application as a starting point and builds on top of it to get the API configured. The branch for the fully configured API can be found here. This application is very simple and uses the AdminLTE framework for the frontend as well as some templates from the django-adminlte3 GitHub repository. The data is stored in a local SQL Lite database and is what will be used as the backend if you are using the repository found above.


For the initial setup of the Django API, we will be creating a new Django app, which will breakout the API code into its own area within the Django application. To create the new app, we will run the following command:

python manage.py startapp api 

After you’ve run the command, you must install the djangorestframework Python library into your Python environment. To do this, add the following to your requirements file and use Pip to install the new Python libraries. Note that versions outside of what has been specified may or may not work, so it’s best to use ~=3.14.0.

 djangorestframework~=3.14.0

Once the app is created, it must be added to the INSTALLED_APPS variable in the settings.py file; the “rest_framework” app must be added as well. The new INSTALLED_APPS variable should look like the below.

INSTALLED_APPS = [
    'app',
    'api',
    'rest_framework',
    'personnel',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

Lastly, after the settings.py file is updated, the urls.py file in the main “demoapp” folder needs to be updated to include the URLs from the new API project.

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('personnel.urls')),
    path('', include('app.urls')),
    path('', include('api.urls')),
]

There is not a urls.py file yet in the “api” app, but once one is created, all URLs defined will be available in the Django application. Now that the environment is configured, we can start looking at getting the API configured.


Configuring the API

The API is the main front-end component that will be used to interact with the backend database. Once the API endpoints are configured, you can interact with the data using different tool sets or even create integrations with other platforms from that API. For this blog, we will only be going over the GET endpoint of the API. However, you will see other methods defined in the application, such as PATCH, DELETE, and POST. Several of the endpoints are configured similarly, which is why we will not be covering each one individually. The project structure is set up using main folders for serializers and views and using the __init__.py files to manage the imports for those folders. Using this method allows easier management of the project components.

For all API endpoints other than the GET endpoint, there are serializers that are used to validate that the data being provided to the API is in the proper format. The code below is for the POST serializer. This serializer uses the PersonnelModel to validate the data that is included in the POST Request.

class PersonnelPost(serializers.ModelSerializer):
    class Meta:
        model = PersonnelModel
        exclude = []

Each serializer will be slightly different as not all requests will have all the data defined in the model. The serializers used in the function below check each item and determines what, if any, issues there are with the data provided to the API. The function below is used in each endpoint, except for the GET endpoint, as it allows repeatable responses.

def check_data(serializer, data):
    errors = list()  # Initialize a list to hold all the errors

    if type(data) == list:  # If a list was sent
        for item in data:  # For each item in the list
            serialized_data = serializer(data=item)  # Check to see if the item is compliant with the model

            if not serialized_data.is_valid():  # If the item is not valid
                errors.append(
                    {
                        f'Index {data.index(item)}': serialized_data.errors
                    }
                )  # Add the reason why it is not valid to the errors list

    else:  # Otherwise, if a dictionary was provided
        serialized_data = serializer(data=data)  # Check to see if the data is compliant with the model

        if not serialized_data.is_valid():  # If the item is not valid
            errors.append(serialized_data.errors)  # Add the reason why it is not valid to the errors list

    if errors: # If there were errors, return a response with the errors
        return JsonResponse({'errors': errors}, status=500)
    else:
        return False

Now, going back to discussing the GET endpoint for the API. This method just gathers all entries in the database for the model and returns it in a JSON response as can be seen below. The model_to_dict built-in function takes the model objects that are returned by the .all() method and converts them to a dictionary that can be passed back in a JSON response. You’ll notice that status codes are returned with the response to indicate to the result of request.

def get(self, request):
    try:
        personnel = [model_to_dict(x) for x in PersonnelModel.objects.all()]
        return JsonResponse({'data': personnel}, status=200)  # Return the results
    except:  # Otherwise, return a generic error
        return JsonResponse({'results': gettext("error_retrieving_data")}, status=500)

After configuring the API endpoints, you need to configure a path that it can be accessed over. This is where the urls.py file comes in. You will need to add a URL path that the API endpoints can be accessed through as seen below.

urlpatterns = [
    path('api/personnel', views.Personnel.as_view(), name='api-personnel'),
    path('api/personnel/<int:_id>', views.PersonnelSingle.as_view(), name='api-personnel-single'),
]

You will notice that two paths were added. One path is for querying or updating multiple instances on the backend. Whereas the other is for just a single instance using the ID of the instance.


Testing the API

Now that the API is fully configured, you can start testing it. For testing purposes, the application can be started using the following command:

Python manage.py runserver

This will start the application on port 8000 and can be accessed using the localhost address 127.0.0.1. To test the API, you can use a command line tool such as curl or an interface-based tool. For our purposes, we will be using Postman.

As you can see in the above request and output, we just query the localhost address over port 8000 using the API endpoint that we created in the previous section. That endpoint points to the View that we created and takes the Method that was used with the API request to determine what needs to be done. Since we just sent a GET request, the data that was in the database was returned.


Conclusion

While we didn’t go too in-depth into any topic with the Django API, you should now have a general understanding of how to configure one yourself. A Django API not only provides a secure and efficient way to share data and functionality with other systems, but it also creates new avenues for innovation and collaboration.


Just think about the endless possibilities that can come from building mobile apps, integrating with third-party services, or even creating your own custom integrations. The opportunities are limitless. However, as with any technological advancement, it's important to approach API development with caution and care. Hopefully, this article has helped give you a better idea of how to use and implement a Django API to get better use out of your data!


Thank you for taking the time to review this article and feel free to contact us if your project needs more advanced capabilities.

API Development in Django

Comments


bottom of page