Django is a scalable and open-source Python web framework for building custom web applications. It was built to be fast and flexible on a variant of the MVC pattern called Model-View-Template. It has many features built in like an admin dashboard, user authentication, and form validation.

It is used on many popular large-scale platforms like Instagram and Pinterest. The projects are made up of several apps which are self-contained and can be removed and used in other projects.

Another Python framework it is often compared to is Flask. The main differences between Django and Flask are that Django is very structured and it must be used in the Django way. Flask offers much more flexibility. The current major version of Django is 2.0.

Post Overview

In this post, we use Django with the Django Rest Framework to build an API, also known as an application programming interface. This project is built and maintained separately from the main Django project. The API is used as the data source for the project I am posting using a React front end for a portfolio template. The framework is relatively straight-forward to understand and to get started with.

Specifically, the API’s database will hold information on project and blog post data. There is also a section on services which can be added, but I’ve decided to hard code that for now since it will not likely be changed often.

The steps to follow are:

  1. Create the models in Django as usual.
  2. Serialize the objects using the Django REST framework and create a view to access the data.
  3. Upload the API to a server.

The Django REST API

So, what is a REST API? REST stands for REpresentational State Transfer. API stands for Application Programming Interface, as mentioned before. This signifies that there is an interface to access the data in the application. This comes in the form of a URL.

It is generally created to allow external entities access to data so that this data can be used to build separate applications. A well-known example is the Twitter API where you can access tweets through a Twitter developer account.

They are often serialized in the form of JSON data which can be accessed through HTTP requests like GET, POST, PUT and DELETE. A GET request fetches data from the server. POST and PUT can both create data on the server. POST can create new data points while PUT is meant to update the data only. DELETE removes data.

Benefits of using a REST API

The beauty of this decoupled structure is that it makes maintenance a breeze. Especially if you want to rebuild the front-end, nothing on the database needs to be retouched. Similarly, another back-end in Spring or Node.js, for instance, can be added on without affecting the front-end code.

Another benefit is that the same back-end can be used with multiple front-ends to create different user experiences such as one for mobile, desktop and another one for wearables.

Start the Project

First, install django. conda install django works if you have anaconda installed.

make sure you have Django and the Django REST Framework installed. pip install djangorestframework should do the trick. It doesn’t seem to be available through conda the package manager for Anaconda. This can be confirmed with conda search djangorestframework.

Now, navigate to the folder where you want to create the API. In my case, I navigate to my dev folder on my desktop with cd desktop/dev.

Create a virtual environment

An additional step that might be desired here is to use a virtual environment. This comes in handy when getting the requirements.txt if deploying to Heroku.

Create the project

Next, start the project with the following command, where portfolio_site_api is a name you can choose. Note that underscores work here for the name of the project but not dashes.

$ django-admin startproject portfolio_site_api

Open the project in an editor of your choice. Here I am using Visual Studio Code. The generated files are shown below. The folder contains an inner configuration folder of the same name as the project and a manage.py file.

Within the internal folder are the settings.py and the urls.py file. The settings.py file has configuration information that we have to edit. urls.py is where we can do URL routing for views. Right now it only contains a path to the admin panel. We will see this later when we create a superuser.

folder structure

Settings.py

In order to use the Django REST framework in our project, we need to modify the setting.py file. Add 'rest_framework' to the end of the list as shown below.

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

Create the App

This app refers to the internal self-contained apps of the project, not the whole application. This can be confusing. Here, we will create 1 app and add in models for the blog posts and for the portfolio projects.

 The Portfolio Site App

To do this, type the following command where portfolioapp is the name of the app.

$ python manage.py startapp portfolioapp

manage.py in the command refers to the manage.py file in the main project folder, thus this command should be run from the portfolio_site_api directory for it to work. Hence, run cd portfolio_site_api/ to move into that folder first.

A folder with the app should now be available. The migrations folder will contain the schema to create the SQLite database once the model has been defined. admin.py is where the models are registered. models.py is where the models are defined. tests.py is where you can run unit tests.

folder structure

Add the name of the application you just made in the settings file.

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

Create the Models

We will be creating a model which contains data on each post such as the title, author, content, date created, date updated, category, image, and a slug. The next model will contain data on projects such as the title, author, and description.

To do this, open the models.py file and add in the code which follows.

from django.db import models

# Create your models here.

class Post(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=60)
    content = models.TextField()
    date_created = models.DateTimeField()
    last_modified = models.DateTimeField(auto_now = True)
    category = models.CharField(max_length=60)
    slug = models.SlugField(max_length=50)
    image = models.ImageField(upload_to='assets/images/posts/') 
 

    # add in the unicode/str line so you get the name
    def __str__(self):
        return self.title

class Project(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=60)
    description = models.TextField()
    date_created = models.DateTimeField()
    category = models.CharField(max_length=60)
    image = models.ImageField(upload_to='assets/images/projects/') 

    def __str__(self):
        return self.title

The general format for defining a field in the database is models.CharField(max_length=100). So, start with models. and call the function to create the desired field, with the appropriate parameters. There are quite a few to choose from like CharField(), TextField() and SlugField().

Note that some of the parameters may be required or an error will result. For example, the max_length parameter is required for the CharField as shown below.

title = models.CharField(max_length=100)

In other cases, they are optional as below. auto_now = True means that the field will take on the time that the resource was created.

last_modified = models.DateTimeField(auto_now = True)

The Django Model field reference is a great way to browse the different fields and parameters and choose the one which is needed.

The unique id for each field appears automatically as an AutoField so there is no need to include one manually. This is set as the primary key of the table. For the Post model schema (this will be generated after migrations are performed) this appears as below:

('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),

Displaying entry names in the Admin Panel

Without the function below the model classes (reproduced below), the names of the entries into the database will show up as generic objects of the model object type in the admin panel (the admin panel will be initialized later on). For a Post object, for example, the first object will appear as Post object (1).

In Python 3 you use the function below to prevent this from happening. In Python 2 use unicode instead of str.

def __str__(self):
    return self.title

Register the Models

Now we have to go to the admin.py file in the portfolioapp folder and register the models. To do this first import the models with from .models import Post, Project then use the syntax admin.site.register(Post) to register the models where Post is the name of the model used in models.py to write the model class.

from django.contrib import admin
from .models import Post, Project

# Register your models here.
admin.site.register(Post)
admin.site.register(Project)

Migrate the Models and Create the Tables

Notice that there are no database files in the project yet. There is no database schema or any tables yet either. This will change with this step. An SQLite database will be generated.

In order to generate these first we run python manage.py makemigrations as below.

$ python manage.py makemigrations
Migrations for 'portfolioapp':
  portfolioapp/migrations/0001_initial.py
    - Create model Post
    - Create model Project

Looking at the file structure will show the addition of 2 new files, 0001_initial.py in the migrations folder and db.sqlite3 (currently empty) in the project directory.

0001_initial.py generated the code to create the database tables. These are shown below.

# Generated by Django 2.0.1 on 2018-03-21 21:37

from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Post',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('title', models.CharField(max_length=100)),
                ('author', models.CharField(max_length=60)),
                ('content', models.TextField()),
                ('date_created', models.DateTimeField()),
                ('last_modified', models.DateTimeField(auto_now=True)),
                ('category', models.CharField(max_length=60)),
                ('slug', models.SlugField()),
                ('image', models.ImageField(upload_to='assets/images/posts/')),
            ],
        ),
        migrations.CreateModel(
            name='Project',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('title', models.CharField(max_length=100)),
                ('author', models.CharField(max_length=60)),
                ('description', models.TextField()),
                ('date_created', models.DateTimeField()),
                ('category', models.CharField(max_length=60)),
                ('image', models.ImageField(upload_to='assets/images/projects/')),
            ],
        ),
    ]

To execute this code run python manage.py migrate.

$ python manage.py migrate 
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, portfolioapp, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
...

Checking the size of the db.sqlite3 shows it contains content.

 Create a Superuser

We can now create a superuser with python manage.py createsuperuser. This gives us access to the admin panel which we will need later on for creating, updating and editing our posts and projects. This will require a username and a password.

The tables from the previous step need to be created before this step can work. I’m using 3ln as the username and tortellini for the password. I left the email blank.

$ python manage.py createsuperuser
Username (leave blank to use '3ln'): 
Email address: 
Password: 
Password (again): 
Superuser created successfully.

Login to the Admin Panel

Run the Server

In order to log into the admin panel and add in posts and projects, run the development server with python manage.py runserver. Then, go to the URL in the output http://127.0.0.1:8000/ .

$ python manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
March 21, 2018 - 22:43:51
Django version 2.0.1, using settings 'portfolio_site_api.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

The page below confirms that the app is working. This might look different if the version is not Django 2.0.

django landing

Login

To go to the admin panel and append admin to the URL like so: http://127.0.0.1:8000/. The login page should pop up in the browser. Put in the username:3ln and password:tortellini.

django landing

Now, the admin panel should appear as below. If the credentials are not correct an error message should appear. The models we created are in the Portfolioapp box.

django landing

Add Data

To add data to the database, click Add for the appropriate object type. For instance, when adding a post the following screen appears. The fields and interface were all auto-created. Great!

django landing

Now, we will add some dummy data for 3 posts and 3 projects. This data will be pulled into the React front-end for testing, so if you want to test the layout for more data/multiple rows, more data should probably be added. I’m filling in data for a hypothetical artist/photographer named Alex.

The filler text is generated from https://www.lipsum.com/. This is great for styling text and getting a feel for what the data will look like before it exists. There are more interesting versions available to try. There are also add-on generators for Visual Studio Code and Atom if those are your preferred editors.

The images I am using come from Pixabay. The links are given in the table. After the first object is added an assets folder will appear in the directory root. It carries the same path as the one which was specified when creating the database model for the ImageField. The images for the posts go to assets/images/posts and those for projects are in assets/images/projects. See the end of this section for the filled folders.

A really nice feature of these forms is that error messages specific to the fields are built-in and do not have to be manually created.

Posts
Title Author Content Date Category Slug Image
Removing Backgrounds in PhotoShop Alex Lorem... today, now Editing removing-backgrounds-in-photoshop https://bit.ly/2udc35u Responsive image
Adding Dramatic Lighting Effects in LightSpace Alex Lorem... today, now Editing adding-dramatic-lighting-effects-in-lightSpace https://bit.ly/2G2J3id Responsive image
Abstract Art Texture Techniques Alex Lorem... today, now Abstract Art Techniques abstract-art-texture-techniques https://bit.ly/2GegmlP Responsive image


The post list in the admin panel is shown below after all the entries are made. folder structure

Projects
Title Author Description Date Category Image
Nature Trip to The Deep White North Alex Lorem... today, now Photography https://bit.ly/2HWrBMO Responsive image
Safari Collection Alex Lorem... today, now Photography https://bit.ly/2G2J3id Responsive image
City Scape Series Alex Lorem... today, now Art https://bit.ly/2GegmlP Responsive image


The projects list in the admin panel is shown below after all the entries are made. folder structure

Assets Folder

The assets folder which holds all the images: folder structure

Create the REST API

Some additional steps are now needed to create the API. The data has to be serialized and converted into JSON, then views for that data and the HTTP endpoints are needed as well as a URL to navigate to the view.

serializers.py

To create the serializers, make a new file serializers.py in the portfolioapp directory. The code to import the serializers and the models is shown below. Then, create 2 serializer classes, one corresponding to each model. The structure of each class is similar, with an inner Meta class which specifies the model to reference and the fields to turn into JSON. According to the Django documentation, Meta classes are how you can give a class metadata.

The particular fields can be specified with fields = ('title', 'author', 'content') or all can be used as below.

from rest_framework import serializers
from .models import Post, Project

class PostSerializer(serializers.ModelSerializer):

    class Meta:
        model = Post
        fields = '__all__'

class ProjectSerializer(serializers.ModelSerializer):

    class Meta:
        model = Project
        fields = '__all__'

views.py

Next, the views.py file should look as shown below. There’s a few imports needed, including the model and the serializers. The 2 serializers have to be returned in the response to generate the JSON data. In this case, we only implement a GET method. For the other HTTP requests to function, they need to be defined.

from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import get_object_or_404

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

from .models import Post, Project
from .serializers import PostSerializer, ProjectSerializer

# Create your views here.
class PortfolioAppList(APIView):

    def get(self, request):
        posts = Post.objects.all()
        posts_serializer = PostSerializer(posts, many=True)

        projects = Project.objects.all()
        projects_serializer = ProjectSerializer(projects, many=True)

        return Response({
            'post' : posts_serializer.data,
            'project': projects_serializer.data
        })

urls.py

Now we have to wire up the view to a URL. To start, import the view we just created with from portfolioapp import views. In this case, I choose portfolio_app_api/.

from django.contrib import admin
from django.urls import path
from portfolioapp import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('portfolio_app_api/', views.PortfolioAppList.as_view()),
]


The Browser View

Navigate to the view in the browser using http://127.0.0.1:8000/portfolio_app_api/.

REST API view.

The JSON

The full data that was generated is below:

{
    "post": [
        {
            "id": 1,
            "title": "Removing Backgrounds in PhotoShop",
            "author": "Alex",
            "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis id ligula massa. Ut iaculis ornare ligula ac vestibulum. Cras varius orci pretium ipsum consequat varius quis ac metus. Suspendisse rutrum nunc et faucibus vestibulum. Curabitur egestas congue dui, at ullamcorper felis. Mauris at maximus tellus. Sed imperdiet dui non ante placerat, id maximus lectus ullamcorper. Ut ullamcorper commodo ante eu tincidunt. Etiam malesuada nisi eget massa mollis tincidunt. Donec enim justo, elementum eget dolor semper, sagittis congue mauris.\r\n\r\nIn varius aliquet dolor sit amet tempus. Pellentesque non quam vitae erat consequat rutrum. Nunc eget euismod erat. Cras efficitur lobortis consectetur. Ut tempus velit eget ante condimentum, facilisis mattis ligula rhoncus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nam ex sem, mattis quis nisl ut, sollicitudin tempus metus.\r\n\r\nCras rutrum ex eget orci aliquet, facilisis mollis odio auctor. In ullamcorper iaculis est eget vulputate. Duis hendrerit libero leo, eu elementum neque sodales ut. Ut nulla augue, pretium quis sagittis eu, porta a lorem. In cursus metus posuere facilisis volutpat. Ut nec venenatis risus, vel dictum dui. Morbi vitae mi ex. Vestibulum placerat eget justo a vehicula. Morbi maximus, risus quis faucibus laoreet, elit elit pellentesque nisl, in tincidunt nisl velit ut magna. Integer non est lacus. Nam commodo sem et velit lobortis, quis consectetur lacus viverra. Vestibulum interdum diam nec mi porttitor, eget aliquet quam varius. Mauris sed sapien a magna luctus congue in non metus. Aenean posuere tempor dapibus. Pellentesque accumsan arcu a tortor cursus hendrerit. Nam eros mi, pellentesque non purus at, dictum suscipit enim.\r\n\r\nEtiam scelerisque, arcu a dictum consectetur, dolor ipsum eleifend felis, et scelerisque diam ex eget leo. Integer ut placerat sem. Phasellus at hendrerit ex. Etiam purus massa, suscipit eget purus at, lobortis hendrerit metus. Nulla sagittis interdum enim, sed consectetur tortor tempus et. Sed egestas magna mi, ut elementum tortor vestibulum vel. Phasellus cursus diam eget nibh pretium condimentum. Donec mauris libero, egestas non dui lobortis, sodales bibendum tellus.\r\n\r\nVestibulum dapibus dui vestibulum, facilisis sapien vitae, rhoncus magna. Cras sapien nunc, laoreet id sollicitudin ut, suscipit sit amet dolor. Vestibulum mauris tellus, pulvinar a enim sit amet, elementum tempor arcu. Nulla facilisi. Ut dui felis, congue nec malesuada a, scelerisque non tortor. Quisque vitae magna congue, sollicitudin neque eget, fringilla metus. Pellentesque elementum nunc venenatis justo volutpat maximus. Cras tristique ex nisl, at mattis ipsum sagittis a. Mauris vel leo viverra, consequat nulla nec, sodales elit. Donec tempor id odio ac condimentum. Sed quis velit id odio vulputate suscipit. Aliquam congue molestie urna id viverra. Etiam ac elementum turpis, et fermentum nunc.",
            "date_created": "2018-03-21T23:59:05Z",
            "last_modified": "2018-03-22T18:29:18.361668Z",
            "category": "Editing",
            "slug": "removing-backgrounds-in-photoshop",
            "image": "assets/images/posts/mask.jpg"
        },
        {
            "id": 2,
            "title": "Adding Dramatic Lighting Effects in LightSpace",
            "author": "Alex",
            "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec in tincidunt enim. Sed in odio justo. Donec dictum sapien et nibh tincidunt maximus. Integer lobortis fermentum ultricies. Sed ultrices risus at laoreet blandit. Donec magna sem, placerat sit amet lobortis vel, sodales pharetra nulla. Sed sagittis dui et sapien lobortis congue. Suspendisse eleifend felis ultrices, finibus ligula sit amet, porta ligula. Etiam ultricies rutrum semper.\r\n\r\nInteger quis auctor enim. Pellentesque tellus enim, viverra quis suscipit eget, egestas sed enim. Maecenas ac purus at sem elementum scelerisque. Vestibulum mi orci, fermentum non mi vel, pretium efficitur nisi. Morbi tortor orci, dapibus id efficitur eu, sodales sit amet justo. Morbi nunc sapien, sollicitudin vel elit at, iaculis ultricies ipsum. Praesent ante ante, molestie eu mauris porta, aliquam pulvinar eros. Nunc sem tortor, pulvinar quis dolor ac, porttitor dictum turpis. Nullam ultricies vel quam sit amet congue.\r\n\r\nPhasellus lacinia, nisi et porta imperdiet, enim tellus maximus dui, vitae congue ante mi eget tellus. Quisque aliquam accumsan elit, in malesuada mi. Nulla dignissim eleifend sapien quis scelerisque. Pellentesque ultricies turpis at commodo accumsan. Pellentesque pulvinar et erat sed condimentum. Curabitur id lectus sem. Donec interdum lorem nec ultricies commodo. Nullam ut felis ornare, finibus nibh nec, malesuada elit. Aliquam erat volutpat. Maecenas ut nisi at orci lacinia aliquam.\r\n\r\nDonec in molestie mauris. Sed egestas urna dignissim finibus egestas. Vivamus in sem lectus. Integer faucibus, magna in tincidunt interdum, dolor magna fermentum turpis, porta ultrices augue ante id arcu. Vestibulum vulputate pharetra eros. Ut fermentum fermentum mi, at aliquet nulla sodales quis. Aenean mattis risus quis eros viverra, at volutpat ipsum posuere. Proin viverra augue id volutpat tristique. Vivamus congue sollicitudin tortor, ac ornare arcu sodales nec. Nulla turpis magna, pharetra vitae venenatis non, pellentesque ac libero.\r\n\r\nCras accumsan, ante ac blandit ultricies, orci dolor porttitor mi, id eleifend nunc orci laoreet magna. Aenean pretium ultricies ultrices. Etiam consequat tempus porta. In et cursus sapien, ornare ultrices ante. Proin eu sapien sem. Integer vulputate elit quis dui semper pulvinar. Aliquam lacinia, sapien ac condimentum faucibus, nulla orci luctus massa, et aliquam risus orci at libero. Duis at pulvinar orci.",
            "date_created": "2018-03-22T18:23:23Z",
            "last_modified": "2018-03-22T18:28:52.871189Z",
            "category": "Editing",
            "slug": "adding-dramatic-lighting-effects-in-lightspace",
            "image": "assets/images/posts/lantern.jpg"
        },
        {
            "id": 3,
            "title": "Abstract Art Texture Techniques",
            "author": "Alex",
            "content": "Nulla ac dolor mauris. Vestibulum varius eget ipsum eu tincidunt. Aenean quis congue quam. Nam laoreet tristique leo vel aliquam. Fusce malesuada justo lectus. Curabitur scelerisque scelerisque risus at lacinia. Praesent et posuere mi. Suspendisse in commodo lacus.",
            "date_created": "2018-03-22T20:02:10Z",
            "last_modified": "2018-03-22T20:02:53.343096Z",
            "category": "Abstract Art Techniques",
            "slug": "abstract-art-texture-techniques",
            "image": "assets/images/posts/sand.jpg"
        }
    ],
    "project": [
        {
            "id": 1,
            "title": "Nature Trip to The Deep White North",
            "author": "Alex",
            "description": "Quisque eu tincidunt massa. Cras eu nisi et mi ultrices consectetur. Ut euismod massa ac ex sagittis vulputate. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris euismod a tortor ac tincidunt. Praesent nibh nulla, semper vitae mauris quis, tempus sodales justo. Duis vitae vehicula nulla, et cursus libero. Sed eleifend interdum interdum.",
            "date_created": "2018-03-22T18:47:09Z",
            "category": "Photography",
            "image": "assets/images/projects/aurora-borealis.jpg"
        },
        {
            "id": 2,
            "title": "Safari Collection",
            "author": "Alex",
            "description": "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi efficitur, nisi sed malesuada pulvinar, lorem augue mattis magna, a egestas enim arcu suscipit erat. Aliquam vitae mauris sit amet urna sagittis consectetur. Nunc consectetur nibh ac risus euismod, sit amet commodo ligula iaculis. Vivamus malesuada semper ipsum, ultrices convallis velit molestie ac. Vivamus vitae dictum tellus, a dictum sem. Maecenas mattis eros a purus sollicitudin scelerisque. Maecenas purus mauris, commodo vel diam quis, efficitur mattis dolor. Nulla non bibendum urna. Vestibulum ipsum augue, consectetur id lacinia quis, facilisis eu leo. Proin cursus condimentum lacus, in fermentum elit tempor interdum. In hac habitasse platea dictumst. Quisque sed tellus sed est bibendum dapibus ut sit amet ligula. Ut dignissim dui euismod est volutpat luctus. Aenean volutpat lacinia lectus et accumsan. Fusce placerat sollicitudin ligula, ultrices dapibus justo varius vel.",
            "date_created": "2018-03-22T19:59:27Z",
            "category": "Photography",
            "image": "assets/images/projects/elephant.jpg"
        },
        {
            "id": 3,
            "title": "City Scape Series",
            "author": "Alex",
            "description": "Curabitur gravida tristique sapien accumsan suscipit. Aenean facilisis convallis maximus. Integer eros enim, condimentum eu ipsum feugiat, ultrices mattis turpis. Donec tristique ipsum vitae mattis scelerisque. Ut sed ante non urna tincidunt pellentesque ac vel augue. Integer auctor lectus nec fermentum egestas. Quisque quis tellus a nibh sodales convallis nec quis justo. Duis rutrum, diam a posuere vulputate, nibh augue pretium felis, id ullamcorper leo libero eu quam. Sed ac nulla interdum, vehicula metus vitae, interdum nulla.",
            "date_created": "2018-03-22T20:00:37Z",
            "category": "Art",
            "image": "assets/images/projects/lisbon.jpg"
        }
    ]
}

Conclusion

This concludes this part of the series on building the REST API. In this post, we looked at how to create a Django REST API. We covered defining and registering the models to migrate and create the tables in the database. We created a superuser and logged into the admin panel to input data points. Finally, we created the REST API by serializing the data and representing the data in a view.

In the next part, we consume the data to populate the front-end.