Build Your First Python and Django Application

Build Your First Python and Django Application

We will be using Python's package manager pip to install this and other packages like Django which we will require later on. First, let's get virtualenv installed. Once that is done, create a folder called projects anywhere you like then cd into it. Once inside the projects folder, create another folder called hello.

Fix markdown issue on the section for installing pipYou may have heard of Python before, especially if you have been coding for a while.

If not, Python is a high level, general purpose programming language. What this means is that you can use it to code up anything from a simple game to a website supporting millions of users per month.

In fact, several high profile sites with millions of visitors per month rely on Python for some of their services. Examples include YouTube and Dropbox

That being said, why should you use Python in the first place? Why not one of the many other popular languages out in the wild like Ruby or PHP? Well, with Python you get the following awesome benefits:

  1. Easily readable syntax.
  2. Awesome community around the language.
  3. Easy to learn.
  4. Python is useful for a myriad of tasks from basic shell sripting to advanced web development.
When Not to Use Python

While you can easily write a Desktop app with Python using tools like wxPython, you generally would do better to use the specialized tools offered by the platform you are targeting for example .NET on Windows.

You should also not use Python when your particular use case has very specialized requirements which are better met by other languages. An example is when you are building an embedded system, a domain in which languages like C, C++ and Java dominate.

Python 2 vs Python 3

Python 2.7.x and 3.x are both being used extensively in the wild. Python 3 introduced changes into the language which required applications written in Python 2 to be rewritten in order to work with the Python 3.x branch. However, most libraries you will require to use have now been ported to Python 3.

This tutorial will use Python 3 which is at version 3.5.1 at the time of writing. The principles remain the same though and only minor syntax modifications will be required to get the code running under Python 2.7.x.

Some Python Code Samples

Hello World

As I said before, one of Python’s main benefits is its’ very easily readable syntax. How easy? Check out Python’s version of the ubiquitous Hello World.

  # This line of code will print "Hello, World!" to your terminal
    print("Hello, World!")

This code prints out Hello, World! to the console. You can easily try out this code by visiting this site, pasting the code samples in the editor on the right side of the page, and clicking the run button above the page to see the output.

Conditional Logic

Conditional logic is just as easy. Here is some code to check if a user’s age is above 18, and if it is, to print Access allowed or Access not allowed otherwise.

 # read in age
    age = int(input("What's your age?"))

    if age >= 18:
        print("Access allowed")
    elif age < 18 and age > 0:
        print("Access not allowed")
    else:
        print("Invalid age")

The input() function is used to read in keyboard input. You will therefore need to type something in the terminal prompt after running the script for rest of the script to execute. Note that the input() function is wrapped in the int() function.

This is because input() reads in values as strings and yet we need age to be an integer. We therefore have to cast the keyboard input into a string or else we will get an error for example when checking if the string is greater than 18.

Finally, note the else statement which executes for any other input which doesn’t fit the criteria being checked for in the if statements.

Abstract Data Types

Python also has some excellent built in abstract data types for holding collections of items. An example is a list which can be used to hold variables of any type. The following code shows how to create a list and iterate through it to print each item to the terminal.

# create a list called my_list
    my_list = [1, 2, 3, "python", 67,  [4, 5]]

    # go through my_list and print every item
    for item in my_list:
        print item

The code above creates a list with numbers, a string and a list (yes, lists can contain other lists!). To iterate through lists, a for-in loop comes in handy. Remember, lists are zero-indexed so we can also access list items using indexes. For example, to output the string python, you can write:

 # create a list called my_list
    my_list = [1, 2, 3, "python", 67,  [4, 5]]

    print(my_list[3])

Dictionaries

Another excellent data type Python offers out of the box is dictionaries. Dictionaries store key-value pairs, kind of like JSON objects. Creating a dictionary is quite simple as well.

 # create a dictionary
    person = {
                "name": "Amos",
                "age": 23,
                "hobbies": ["Travelling", "Swimming", "Coding", "Music"]
            }

    # iterate through the dict and print the keys
    for key in person:
        print(key)

    # iterate through the dict's keys and print their values
    for key in person:
        print(person[key])

Now that you know a little bit of Python, let’s talk about Django.

Django

Django is a Python web framework. It is free and open source and has been around since 2005. It is very mature and comes with excellent documentation and awesome features included by default. Some excellent tools it provides are:

  1. Easily readable syntax.
  2. Awesome community around the language.
  3. Easy to learn.
  4. Python is useful for a myriad of tasks from basic shell sripting to advanced web development.

There are a myriad of other useful things included in Django but you shall probably discover them as you go along. We are going to be using Django to build our website in this tutorial.

Setting Up

In this tutorial, I will show you how to get a Django website up and running. Before we get there though, first grab a copy of the latest Python from the Python website.

Note that if you are on OSX and you have Homebrew installed you can do

 brew install python3

Note that if you are on OSX and you have Homebrew installed you can do
After installing the correct version for your OS, you will need to make sure it is set up correctly. Open a terminal and type:

 python3

You should see something resembling the following:

   Python 3.5.1 (v3.5.1:37a07cee5969, Dec  5 2015, 21:12:44) 
    [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> 

This is the interactive Python shell. Hit CTRL + D to exit it for now

Next, we need to install pip. Pip is a python package manager that will enable us to get libraries we require in our app easily such as Django.

 sudo easy_install pip

Setting Up the Environment

To avoid polluting our global scope with unecessary packages, we are going to use a virtual environment to store our packages. One excellent virtual environment manager available for free is virtualenv. You can get it by doing a pip install.

 pip install virtualenv

Once that is done, create a folder called projects anywhere you like then cd into it.

mkdir projects
cd projects

Once inside the projects folder, create another folder called hello. This folder will hold our app.

mkdir hello

At this point, we need to create the environment to hold our requirements. We will do this inside the hello folder.

  virtualenv -p /usr/local/bin/python3 env

The -p switch tells virtualenv the path to the python version you want to use. Feel free to switch out the path after it with your own Python installation path. The name env is the environment name. You can also change it to something else which fits the name of your project.

Once that is done, you should have a folder called env inside your hello folder. Your structure should now look something like this.

 projects
    ├─hello
    │   ├── env

You are now ready to activate the environment and start coding!

source env/bin/activate

You will see a prompt with the environment name. That means the environment is active.

 (env)

Installing Django

This is a simple pip install. The latest Django version at the time of writing is Django 1.9.6

 pip install django

Creating an App

Now that Django is installed, we can use its start script to create a skeleton project. This is as simple as using its admin script in the following way.

 django-admin startproject helloapp

Running this command creates a skeleton django app with the following structure:

 helloapp
    ├─helloapp
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    └── manage.py

When you look into the helloapp folder that was created, you will find a file called manage.py and another folder called helloapp. This is your main project folder and contains the project’s settings in a file called settings.py and the routes in your project in the file called urls.py. Feel free to open up the settings.py file to familiarize yourself with its contents.

Ready to move on? Excellent.

Changing App Settings

Let’s change a few settings. Open up the settings.py file in your favorite editor. Find a section called Installed Apps which looks something like this.

 # helloapp/settings.py
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
    ]

Django operates on the concept of apps. An app is a self contained unit of code which can be executed on its own. An app can do many things such as serve a webpage on the browser or handle user authentication or anything else you can think of. Django comes with some default apps preinstalled such as the authentication and session manager apps. Any apps we will create or third-party apps we will need will be added at the bottom of the Installed Apps list after the default apps installed.

Before we create a custom app, let’s change the application timezone. Django uses the tz database timezones, a list of which can be found here.

The timezone setting looks like this.

 # helloapp/settings.py
    TIME_ZONE = 'UTC'

Change it to something resembling this as appropriate for your timezone.

 # helloapp/settings.py
    TIME_ZONE = 'America/Los_Angeles'

Creating your own app

It is important to note that Django apps follow the Model, View, Template paradigm. In a nutshell, the app gets data from a model, the view does something to the data and then renders a template containing the processed information. As such, Django templates correspond to views in traditional MVC and Django views can be likened to the controllers found in traditional MVC.

That being said, let’s create an app. cd into the first helloapp folder and type;

 python manage.py startapp howdy

Running this command will create an app called howdy. Your file structure should now look something like this.

helloapp
    ├── helloapp
    │        ├── __init__.py
    │        ├── settings.py
    │        ├── urls.py
    │        └── wsgi.py
    ├── howdy
    │        ├── __init__.py
    │        ├── admin.py
    │        ├── apps.py
    │        ├── migrations
    │        ├── models.py
    │        ├── tests.py
    │        └── views.py
    └── manage.py

To get Django to recognize our brand new app, we need to add the app name to the Installed Apps list in our settings.py file.

 # helloapp/settings.py
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'howdy'
    ]

Once that is done, let’s run our server and see what will be output. We mentioned that Django comes with a built in lightweight web server which, while useful during development, should never be used in production. Run the server as follows:

 python manage.py runserver

Your output should resemble the following:

Performing system checks...

    System check identified no issues (0 silenced).

    You have unapplied migrations; your app may not work properly until they are applied.
    Run 'python manage.py migrate' to apply them.

    June 04, 2016 - 07:42:08
    Django version 1.9.6, using settings 'helloapp.settings'
    Starting development server at http://127.0.0.1:8000/
    Quit the server with CONTROL-C.

If you look carefully, you will see a warning that you have unapplied migrations. Ignore that for now. Go to your browser and access http://127.0.0.1:8000/. If all is running smoothly, you should see the Django welcome page.

We are going to replace this page with our own template. But first, let’s talk migrations.

Migrations

Migrations make it easy for you to change your database schema (model) without having to lose any data. Any time you create a new database model, running migrations will update your database tables to use the new schema without you having to lose any data or go through the tedious process of dropping and recreating the database yourself.

Django comes with some migrations already created for its default apps. If your server is still running, stop it by hitting CTRL + C. Apply the migrations by typing:

python manage.py migrate

If successful, you will see an output resembling this one.

Operations to perform:
      Apply all migrations: sessions, auth, contenttypes, admin
    Running migrations:
      Rendering model states... DONE
      Applying contenttypes.0001_initial... OK
      Applying auth.0001_initial... OK
      Applying admin.0001_initial... OK
      Applying admin.0002_logentry_remove_auto_add... OK
      Applying contenttypes.0002_remove_content_type_name... OK
      Applying auth.0002_alter_permission_name_max_length... OK
      Applying auth.0003_alter_user_email_max_length... OK
      Applying auth.0004_alter_user_username_opts... OK
      Applying auth.0005_alter_user_last_login_null... OK
      Applying auth.0006_require_contenttypes_0002... OK
      Applying auth.0007_alter_validators_add_error_messages... OK
      Applying sessions.0001_initial... OK

Running the server now will not show any warnings.

Urls & Templates

When we ran the server, the default Django page was shown. We need Django to access our howdy app when someone goes to the home page URL which is /. For that, we need to define a URL which will tell Django where to look for the homepage template.

Open up the urls.py file inside the inner helloapp folder. It should look like this.

 # helloapp/urls.py
     """helloapp URL Configuration

    The `urlpatterns` list routes URLs to views. For more information please see:

    https://docs.djangoproject.com/en/1.9/topics/http/urls/

    Examples:
    Function views
        1\. Add an import:  from my_app import views
        2\. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
    Class-based views
        1\. Add an import:  from other_app.views import Home
        2\. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
    Including another URLconf
        1\. Import the include() function: from django.conf.urls import url, include
        2\. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
    """
    from django.conf.urls import url
    from django.contrib import admin

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
    ]

As you can see, there is an existing URL pattern for the Django admin site which comes by default with Django. Let’s add our own url to point to our howdy app. Edit the file to look like this.

 # helloapp/urls.py
    from django.conf.urls import url, include
    from django.contrib import admin

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^', include('howdy.urls')),
    ]

Note that we have added an import for include from django.conf.urls and added a url pattern for an empty route. When someone accesses the homepage, (in our case http://localhost:8000), Django will look for more url definitions in the howdy app. Since there are none, running the app will produce a huge stack trace due to an ImportError.

.
    .
    ImportError: No module named 'howdy.urls'

Let’s fix that. Go to the howdy app folder and create a file called urls.py. The howdy app folder should now look like this.

├── howdy
    │   ├── __init__.py
    │   ├── admin.py
    │   ├── apps.py
    │   ├── migrations
    │   │   ├── __init__.py
    │   ├── models.py
    │   ├── tests.py
    │   ├── urls.py
    │   └── views.py

Inside the new urls.py file, write this.

 # howdy/urls.py
    from django.conf.urls import url
    from howdy import views

    urlpatterns = [
        url(r'^$', views.HomePageView.as_view()),
    ]

This code imports the views from our howdy app and expects a view called HomePageView to be defined. Since we don’t have one, open the views.py file in the howdy app and write this code.

# howdy/views.py
    from django.shortcuts import render
    from django.views.generic import TemplateView

    # Create your views here.
    class HomePageView(TemplateView):
        def get(self, request, **kwargs):
            return render(request, 'index.html', context=None)

This file defines a view called HomePageView. Django views take in a request and return a response. In our case, the method get expects a HTTP GET request to the url defined in our urls.py file. On a side note, we could rename our method to post to handle HTTP POST requests.

Once a HTTP GET request has been received, the method renders a template called index.html which is just a normal HTML file which could have special Django template tags written alongside normal HTML tags. If you run the server now, you will see the following error page:

This is because we do not have any templates at all! Django looks for templates in a templates folder inside your app so go ahead and create one in your howdy app folder.

 mkdir templates

Go into the templates folder you just created and create a file called index.html

(env) hello/helloapp/howdy/templates
     > touch index.html

Inside the index.html file, paste this code.

 <!-- howdy/templates/index.html -->
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>Howdy!</title>
        </head>
        <body>
            <h1>Howdy! I am Learning Django!</h1>
        </body>
    </html>

Now run your server.

python manage.py runserver 

You should see your template rendered.

Linking pages

Let’s add another page. In your howdy/templates folder, add a file called about.html. Inside it, write this HTML code:

<!-- howdy/templates/about.html -->
<!DOCTYPE html>
<html>
   <head>
       <meta charset="utf-8">
       <title>Howdy!</title>
   </head>
   <body>
       <h1>Welcome to the about page</h1>
   <p>
   Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc quis neque ex. Donec feugiat egestas dictum. In eget erat sit amet elit pellentesque convallis nec vitae turpis. Vivamus et molestie nisl. Aenean non suscipit velit. Nunc eleifend convallis consectetur. Phasellus ornare dolor eu mi vestibulum, ornare tempus lacus imperdiet. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque ut sem ligula. Mauris volutpat vestibulum dui in cursus. Donec aliquam orci pellentesque, interdum neque sit amet, vulputate purus. Quisque volutpat cursus nisl, in volutpat velit lacinia id. Maecenas id felis diam. 
   </p>
   <a href="/">Go back home</a>
   </body>
</html>

Once done, edit the original index.html page to look like this.

<!-- howdy/templates/index.html -->
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>Howdy!</title>
        </head>
        <body>
            <h1>Howdy! I am Learning Django!</h1>
         <a href="/about/">About Me</a>
        </body>
    </html>

Clicking on the About me link won’t work quite yet because our app doesn’t have a /about/ url defined. Let’s edit the urls.py file in our howdy app to add it.

 # howdy/urls.py
    from django.conf.urls import url
    from howdy import views

    urlpatterns = [
        url(r'^$', views.HomePageView.as_view()),
        url(r'^about/$', views.AboutPageView.as_view()), # Add this /about/ route
    ]

Once we have added the route, we need to add a view to render the about.html template when we access the /about/ url. Let’s edit the views.py file in the howdy app.

 # howdy/views.py
    from django.shortcuts import render
    from django.views.generic import TemplateView

    class HomePageView(TemplateView):
        def get(self, request, **kwargs):
            return render(request, 'index.html', context=None)

    # Add this view
    class AboutPageView(TemplateView):
        template_name = "about.html"

Notice that in the second view, I did not define a get method. This is just another way of using the TemplateView class. If you set the template_name attribute, a get request to that view will automatically use the defined template. Try changing the HomePageView to use the format used in AboutPageView.

Running the server now and accessing the home page should display our original template with the newly added link to the about page.

Clicking on the About me link should direct you to the About page.

On the About me page, clicking on the Go back home link should redirect you back to our original index page. Try editing both these templates to add more information about you.

Conclusion

That was just a brief look at how to get a Django website up and running. You can read more about Django on the official Django docs. The full code for this tutorial can also be found on Github.

*Originally published by Amos Omondi at *scotch.io

===================================================================

Thanks for reading :heart: If you liked this post, share it with all of your programming buddies! Follow me on Facebook | Twitter

Learn More

☞ Complete Python Bootcamp: Go from zero to hero in Python 3

☞ Python and Django Full Stack Web Developer Bootcamp

☞ Python for Time Series Data Analysis

☞ Python Programming For Beginners From Scratch

☞ Beginner’s guide on Python: Learn python from scratch! (New)

☞ Python for Beginners: Complete Python Programming

☞ Django 2.1 & Python | The Ultimate Web Development Bootcamp

☞ Python eCommerce | Build a Django eCommerce Web Application

☞ Python Django Dev To Deployment

Python Django Tutorial | Django Course

Python Django Tutorial | Django Course

🔥Intellipaat Django course: https://intellipaat.com/python-django-training/ 👉This Python Django tutorial will help you learn what is django web development &...

This Python Django tutorial will help you learn what is django web development & application, what is django and introduction to django framework, how to install django and start programming, how to create a django project and how to build django app. There is a short django project as well to master this python django framework.

Why should you watch this Django tutorial?

You can learn Django much faster than any other programming language and this Django tutorial helps you do just that. Our Django tutorial has been created with extensive inputs from the industry so that you can learn Django and apply it for real world scenarios.

Developing Restful APIs with Python, Django and Django Rest Framework

Developing Restful APIs with Python, Django and Django Rest Framework

This article is a definitive guide for starters who want to develop projects with RESTful APIs using Python, Django and Django Rest Framework.

This article is a definitive guide for starters who want to develop projects with RESTful APIs using Python, Django and Django Rest Framework.

Introduction
  • Django is a web framework written in Python
  • Python is an interpreted high-level programming language for general-purpose programming
  • API or Application Programming Interface is a set of rules and mechanisms by which one application or component interacts with the others
  • REST or Representational State Transfer is a software architecture

REST APIs

As described in a dissertion by Roy Fielding,

REST is an "architectural style' that basically exploits the existing technology and protocols of the web.
In simple definition, it is the data representation for a client in the format that is suitable for it.

Hence, RESTful + API is a commonly used terminology for the implementation of such architecture and constraints (eg. in web services).

Here is an example GET request from GitHub's API

$ curl https://api.github.com/users/joshuadeguzman

You will see an output similar to this

{
  "login": "joshuadeguzman",
  "id": 20706361,
  "node_id": "MDQ6VXNlcjIwNzA2MzYx",
  "avatar_url": "https://avatars1.githubusercontent.com/u/20706361?v=4",
  "gravatar_id": "",
  "url": "https://api.github.com/users/joshuadeguzman",
  "html_url": "https://github.com/joshuadeguzman",
  "followers_url": "https://api.github.com/users/joshuadeguzman/followers",
  "following_url": "https://api.github.com/users/joshuadeguzman/following{/other_user}",
  "gists_url": "https://api.github.com/users/joshuadeguzman/gists{/gist_id}",
  "starred_url": "https://api.github.com/users/joshuadeguzman/starred{/owner}{/repo}",
  "subscriptions_url": "https://api.github.com/users/joshuadeguzman/subscriptions",
  "organizations_url": "https://api.github.com/users/joshuadeguzman/orgs",
  "repos_url": "https://api.github.com/users/joshuadeguzman/repos",
  "events_url": "https://api.github.com/users/joshuadeguzman/events{/privacy}",
  "received_events_url": "https://api.github.com/users/joshuadeguzman/received_events",
  "type": "User",
  "site_admin": false,
  "name": "Joshua de Guzman",
  "company": "@freelancer",
  "blog": "https://joshuadeguzman.me",
  "location": "Manila, PH",
  "email": null,
  "hireable": true,
  "bio": "Android Engineer at @freelancer. Building tools for humans.",
  "public_repos": 75,
  "public_gists": 2,
  "followers": 38,
  "following": 10,
  "created_at": "2016-07-28T15:19:54Z",
  "updated_at": "2019-06-16T10:26:39Z"
}

Shown above is a data set in JSON format.

JSON or JavaScript Object Notation is an open-standard file format that uses human-readable text to transmit data objects consisting of attribute–value pairs and array data types.
Other formats include XML, INI, CSV, etc. But today, JSON is widely use for its structure is intuitive, making it comfortable to read and map domain objects no matter what programming language is being used.

Python and Django

Python, according to its creator, Guido van Rossum, is a

high-level programming language, and its core design philosophy is all about code readability and a syntax which allows programmers to express concepts in a few lines of code.
Python uses english like words representation (eg. for methods, reserve keywords and control flow) that makes it easier for any beginner to jump right into it. It also features dynamic type system meaning it verifies the type safety of program at runtime. It also does automatic memory management.

print(5 + 5) # This will result to 10

Django is a high-level Python Web Framework that enables developers to deliver projects on time with clean and pragmatic design.

Its flagship features include a design for fast development, a secure and scalable product.

Quick Django Overview

Django's way of propagating changes to your database schema is by means of its migration modules.

Sample User model

from django.db import models

class User(models.Model):
    first_name = models.CharField(max_length=50)
    middle_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)

    def __str__(self):
        return self.name

If any changes are made on your models, run makemigrations

$ python manage.py makemigrations

Finally, you can synchronize the database with the set of models and migrations

$ python manage.py migrate

REST APIs with Django Rest Framework

DRF or Django REST Framework is a powerful and flexible toolkit for building Web APIs. It helps the developers to not reinvent the wheel by rolling out complex and solid REST API from scratch by themselves. Because when your projects become more and more complex, you will soon realise the need of using DRF or other helpful rest framework.

1. Installation & Project Setup

Create project directory

$ mkdir djangoapi

Install virtualenv via pip

A virtual environment enables a project to have additional libraries or changes in packages within its environment without disturbing global or libraries of other environments.

pip is a package management system used to install and manage software packages written in Python.

$ pip install virtualenv

To create an environment folder in your project's directory

$ cd djangoapi
$ virtualenv venv

To activate the environment

$ source venv/bin/activate

To undo these changes to your path, simply run deactivate. More on virtualenv.

Install django, djangorestframework

$ pip install django
$ pip install djangorestframework

Creating a django project

$ django-admin startproject blog

Running your project

$ python manage.py runserver

System check identified no issues (0 silenced).

You have 15 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.

August 16, 2018 - 09:58:36
Django version 2.1, using settings 'blog.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

The unapplied migrations refer to the default migration files included when you start a django project.

To synchronize these migration files, simply run migrate

$ python manage.py migrate

Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying sessions.0001_initial... OK

The default database in our project is currently set to SQLite named db.sqlite3.

Creating a django project's app

$ cd blog
$ python manage.py startapp posts

The project structure should look like

$ find .
./posts
./posts/migrations
./posts/migrations/__init__.py
./posts/models.py
./posts/__init__.py
./posts/apps.py
./posts/admin.py
./posts/tests.py
./posts/views.py
./db.sqlite3
./blog
./blog/__init__.py
./blog/__pycache__
./blog/__pycache__/settings.cpython-36.pyc
./blog/__pycache__/wsgi.cpython-36.pyc
./blog/__pycache__/__init__.cpython-36.pyc
./blog/__pycache__/urls.cpython-36.pyc
./blog/settings.py
./blog/urls.py
./blog/wsgi.py
./manage.py

2. Model

Each model instance is a definitive source of the information about your data. In general, each model pertains to a single table in your database.

# djangoapi/blog/posts/models.py
from django.db import models

# Create your models here.

class Post(models.Model):
    title = models.CharField(max_length=255)
    content = models.TextField()
    is_featured = models.BooleanField(default=False)

    def __str__(self):
        return self.name

__str__ is called by the str() built-in function and by the print statement to compute the "informal" string representation of an object.
If you try running makemigrations, django won't see those changes yet.

$ No changes detected

To solve this, add your posts app to your project's installed apps.

# djangoapi/blog/blog/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'posts' # Add it here
]

To continue with the migration of models

$ python manage.py makemigrations

Migrations for 'posts':
  posts/migrations/0001_initial.py
    - Create model Post

$ python manage.py migrate

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, posts, sessions
Running migrations:
  Applying posts.0001_initial... OK


3. Serialization

Serializers allow data structure or object state to be translated into a format that can be stored or transmitted and be reconstructed later on.

Create API's serializers.py and views.py files and isolate them like this

# posts/api
posts/api/serializers.py
posts/api/views.py

# posts/migrations
posts/migrations/

# posts
posts/admin.py
posts/apps.py
posts/models.py
posts/tests.py
posts/views.py
# posts/api/serializers.py

from ..models import Post
from rest_framework import serializers

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ('title', 'content', 'is_featured') # if not declared, all fields of the model will be shown

In this tutorial we have used ModelSerializer, more on this.

4. Views

A view function, or view for short, is a Python function that takes a Web request and returns a Web response.

# posts/api/views.py

from ..models import Post
from . import serializers
from rest_framework import generics, status
from rest_framework.response import Response

class PostListView(generics.ListAPIView):
    queryset = Post.objects.all()
    serializer_class = serializers.PostSerializer

As seen above, ListAPIView is used for read-only endpoints to represent a collection of model instances.

In this code snippet, we use generics view methods from the rest_framework, more on this.

5. URLs

This is where we setup our routes or URL paths to our designated views in which we expect specific responses for each.

# posts/urls.py

from django.urls import path
from . import views
from .api import views

urlpatterns = [
    path('', views.PostListView.as_view(), name=None)
]

6. Finalizing Setup

Ensure that the rest_framework is added to our project's apps.

# djangoapi/blog/blog/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework', # Add it here
    'posts'
]

7. Django Admin

Since we haven't setup our POST requests yet, we will be populating the database through django's admin panel.

To do that, create a superuser account admin with password 1234password.

$ python manage.py createsuperuser --email [email protected] --username admin

Password:
Password (again):
This password is too common.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

Register the model in the admin panel.

# posts/admin.py

from django.contrib import admin
from .models import Post

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

That's it. Visit the admin panel and update posts model's records. More on this.

8. Testing our API

$ python manage.py runserver
GET /api/v1/posts/
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[
    {
        "title": "Example Post #1",
        "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
        "is_featured": false
    },
    {
        "title": "Example Post #2",
        "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
        "is_featured": true
    }
]

Great. Now it's time for us to update our views and finish the standard CRUD operations.

9. Adding more views

POST is a method used for creating (sometimes updating) a resource in the database.

# posts/api/views.py

from ..models import Post
from . import serializers
from rest_framework import generics, status
from rest_framework.response import Response

class PostCreateView(generics.CreateAPIView):
    queryset = Post.objects.all()
    serializer_class = serializers.PostSerializer

    def create(self, request, *args, **kwargs):
        super(PostCreateView, self).create(request, args, kwargs)
        response = {"status_code": status.HTTP_200_OK,
                    "message": "Successfully created",
                    "result": request.data}
        return Response(response)

Most often, we separate List and Create view classes when we want to expose a list of data set while easily preventing a certain request to POST or create a resource in the database for that specific List view.

Usecase always varies for apps, you are opt to use ListCreateAPIView or even ViewSets for combining the logic for a set of related views.

Optional: Since we want to display the data in a more systematic way, we override create method and map our inline custom response handler.

Adding more views with methods GET, PATCH, DELETE to handle a specific blog post detail.

class PostDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Post.objects.all()
    serializer_class = serializers.PostSerializer

    def retrieve(self, request, *args, **kwargs):
        super(PostDetailView, self).retrieve(request, args, kwargs)
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        data = serializer.data
        response = {"status_code": status.HTTP_200_OK,
                    "message": "Successfully retrieved",
                    "result": data}
        return Response(response)

    def patch(self, request, *args, **kwargs):
        super(PostDetailView, self).patch(request, args, kwargs)
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        data = serializer.data
        response = {"status_code": status.HTTP_200_OK,
                    "message": "Successfully updated",
                    "result": data}
        return Response(response)

    def delete(self, request, *args, **kwargs):
        super(PostDetailView, self).delete(request, args, kwargs)
        response = {"status_code": status.HTTP_200_OK,
                    "message": "Successfully deleted"}
        return Response(response)

10. Updating URLs

# posts/urls.py

from django.urls import path
from . import views
from .api import views

urlpatterns = [
    path('', views.PostListView.as_view(), name=None),
    path('create/', views.PostCreateView.as_view(), name=None),
    path('<int:pk>/', views.PostDetailView.as_view(), name=None)
]

Now you can send requests to your API via Postman, your app or do a GETrequests from your browser, examples:

POST /api/v1/posts/create/
HTTP 200 OK
Allow: POST, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "status_code": 200,
    "message": "Successfully created",
    "result": {
        "csrfmiddlewaretoken": "rnSUN3XOIghnXA0yKghnQgxg0do39xhorYene5ALw3gWGThK5MjG6YjL8VUb7v2h",
        "title": "Creating a resource",
        "content": "Howdy mate!"
    }
}
GET /api/v1/posts/1/
HTTP 200 OK
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "status_code": 200,
    "message": "Successfully retrieved",
    "result": {
        "title": "Sample Post",
        "content": "Sample Post Content",
        "is_featured": false
    }
}

That's it. You have successfully managed to develop RESTful APIs with DRF! Cheers!

Source code

Available on GitHub.