This article is for people who fall in any of the following categories:
- You’re a front end developer coming from using a DBaaS platform like Firebase.
- You’re a Django developer, who recently picked up React/Angular, or started playing with mobile apps.
- You’re a beginner front end developer, and you are intimidated by the complexity of backend development.
- You want to use a matured framework to build your backend services.
Django is a high level web framework written in Python, and has been around for many years now. Hence it is very stable, and has a lot of resources online if you ever get stuck.
Why is using Django alongside Angular, React or a Mobile SDK not straightforward?
Django is a full stack web framework, which means it comes with its own ORM, templating engine etc and it is built so that the entire application runs as a single service. But if you’re using a frontend framework, or a mobile SDK, it is designed so that the client/frontend is completely decoupled from the backend.
Then what’s the point of using Django?
We don’t need to use all of Django’s features to get the best out of it. Infact one of the major weaknesses of Django is that it is not really built for Web 2.0. But this has more to do with frontend than backend. And these weaknesses are easily addressed by the front end frameworks, bringing in all that is required for Web 2.0 to Django. Hence we are getting the best of both worlds using Django just in the backend! The only missing piece in the puzzle is a REST based communication architecture between the frontend and backend, that can facilitate complete decoupling. Django REST Framework does just that.
Proposed Architecture
Evidently, this setup will work for any Mobile/Frontend framework.
In this article, we are only going to cover what we need in Django. Django is a fairly large framework, and covering all parts of it is out of the scope of this article. However, I will try to cover the basic concepts you need to know.
If you already know Django, please feel free to skip to the section ‘Our first Django app’.
Getting started with Django
Before we get started, you need to have python and pip installed on your system. If you don’t, please go ahead and install it before you continue. We are going to use Python 3.6 in this article. To start working on our project, let’s create a virtual environment called mobileBackend
. If you don’t have virtualenv installed, install it by running pip install virtualenv
. Then run:
virtualenv -p python3 mobileBackend && cd mobileBackend
source bin/activate
These commands will create a virtual environment called mobileBackend, using Python 3 as the default python interpreter, open the directory, and activate the virtual environment. Django doesn’t have a package manager, hence we use a virtual environment to manage the package dependencies. We can get a list of all dependencies by running pip freeze
.
Installing Django and Django Rest Framework
pip install django djangorestframework
Django Rest Framework, is a library, which makes it easier for us to work with REST APIs in Django.
Now let’s create our Django project. We will call our Django project with the same name as our virtual environment. You can choose any name you want for your project and virtual environment. Here, we are going to call both mobileBackend. Run:
django-admin startproject mobileBackend && cd mobileBackend
This command creates our Django project called mobileBackend and opens the mobileBackend directory.
Here you would see two things:
- manage.py (File)
- mobileBackend (Folder)
To understand what these mysterious things are, we need to first explore how Django is structured. A Django project is a collection of apps and configuration. An app in Django is a unit of the project that has a defined purpose — e.g., If you’re building a Blog, its apps could be articles, users, activities etc. As a general rule of thumb, an app in a Django project should be something that you can describe one sentence. Ex: Users app manages all the users of the website.
When you create your project, Django by default creates an app with the same name as the project as an entry point to the project. That is why there is a folder with the same name as your project. And manage.py
is a command line utility, using which you can interact with your Django project.
Let’s give this a shot.
Running the Django development server
Run your Django development server using:
python manage.py runserver
You’ll see the following output on your terminal.
Performing system checks…
System check identified no issues (0 silenced).
You have 14 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.
March 18, 2018–21:35:59
Django version 2.0.3, using settings ‘mobileBackend.settings’
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
You can access your development server by going to http://localhost:8000/ in your browser. You’ll see the following page if everything goes well…
Nice, but you would have seen a warning when you started the development server. It said you have unapplied migrations. Please don’t be thrown off by the buzz words, it is surprisingly simple.
Model migrations
When you’re using Django, you don’t need to write SQL commands. Yes, for real. When you create a Django project, Django automatically creates a SQLite database for us. Now you can change the DB to whatever you want, but you will be interacting with the DB through Django’s ORM. This means that you will represent the tables in the databases as classes and entries in the table as objects. These classes which represents the database tables are called modelsin Django.
When you create or modify a model, you need to tell Django to create the SQL commands required to reflect the changes on the database. This process is called a migration.
A migration is a two step process. First, we need to create the migrations, and then apply the migrations.
You can create migrations using :
python manage.py makemigrations
And you apply the migrations using:
python manage.py migrate
When you create a Django project, Django creates a few models for us, and also creates the corresponding migrations. Now all we need to do is apply those migrations, which we haven’t done. This is why Django is giving us a warning that the migrations need to be applied. Let’s go back to the terminal and press Ctrl+C to stop the server and apply the migrations by running python manage.py migrate
. Now if you run python manage.py runserver
again, you’ll see the warnings disappeared! Awesome!
Django apps
Now let’s explore the contents of the app Django created for us.
cd mobileBackend
If you open the folder mobileBackend
in your project directory, you’ll find the following files.
- __init__.py
- settings.py
- urls.py
- wsgi.py
The two files that are useful to us is settings.py and urls.py. If you are keen on understanding the importance of each file fully, please read the official docs here.
settings.py holds all the configuration related to our project. And urls.py is the list of URL endpoints in our project. We will touch both of these files later in the article.
Our first Django app
Let’s go back to the root of the project and create our first Django app. In this example, let’s create a simple app which shows a list of movie actors.
cd ..
python manage.py startapp actors
startapp
is a management command that creates a Django app for us. Here we have created an app called actors. Let’s explore the contents of the app.
cd actors
As you can see Django creates an app structure for us. This is an excellent time saver, and also ensures we follow best practices when it comes to structuring our applications. Let’s see the files that are useful to us for this article.
models.py
— This file holds all the models of the app.views.py
— This file is a collection of functions which gets executed when a request to a URL endpoint is made. For each endpoint, we can specify which function to execute. We will only have the functions for the endpoints associated with the app in itsviews.py
Now let’s create our first model. Open your actors/models.py
file.
So we have created 4 fields for the actor model: first_name
, last_name
, dp
, age
. CharField
is Django’s way of saying that the values of this field will contain characters. max_length
attribute specifies the maximum number of characters allowed. blank=True
and null=True
says that empty and null values are allowed. IntegerField
can only contain integer values, hence it is suitable for age. The syntax is really simple, isn’t it?
Cool! Now we have our first model. Earlier in the article, I said when we create or change a model, we should create and apply migrations. Let’s go ahead and do that. In your terminal,
python manage.py makemigrations
The output says ‘No changes detected’. What? How is this possible? We just created a model in our actors app!
There is just one problem.
When we create a Django app, Django doesn’t automatically include the app in the project. I know, that is weird. To tell Django that the app is a part of the project, we need to include the app in the INSTALLED_APPS
list in the settings.py
file. This applies to all apps we create, and also the third party libraries we install on our Django project. When we installed Django, we also installed Django Rest Framework. We need to add that to the INSTALLED_APPS
as well.
Let’s do that now.
cd mobileBackend
Open settings.py, and find the list of INSTALLED_APPS
.
Let’s try applying migrations again.
Go to terminal and navigate to the root of your project and run:
python manage.py makemigrations
python manage.py migrate
Awesome! Now let’s create some actors. manage.py
comes with a shell, which gives us access to our models in our Django project. To use the shell, from the terminal, run:
python manage.py shell
Let’s create some actors!
from actors.models import Actor
actor1 = Actor(first_name="Tom",last_name="Cruise",dp="https://ia.media-imdb.com/images/M/MV5BMTk1MjM3NTU5M15BMl5BanBnXkFtZTcwMTMyMjAyMg@@._V1_UY317_CR14,0,214,317_AL_.jpg",age=55)
actor1.save()
actor2 = Actor(first_name="Hugh",last_name="Jackman",dp="https://images-na.ssl-images-amazon.com/images/M/MV5BNDExMzIzNjk3Nl5BMl5BanBnXkFtZTcwOTE4NDU5OA@@._V1_UX214_CR0,0,214,317_AL_.jpg",age=49)
actor2.save()
That was fairly straightforward. Before exiting the shell, let’s verify if the objects were actually saved. You can access all objects of the Actor model using:
Actor.objects.all()
This will give the following response:
<QuerySet [<Actor: Actor object (1)>, <Actor: Actor object (2)>]>
Django QuerySets
A QuerySet represents a collection of objects from your database. It can have zero, one or many filters. Filters narrow down the query results based on the given parameters. In SQL terms, a QuerySet equates to a SELECT statement, and a filter is a limiting clause such as WHERE or LIMIT. In this example when we do Actor.objects.all()
we are selecting all elements from the Actor table without any filters.
An example of a filter would be: Actor.objects.filter(age = 40)
Now that we have verified that our objects are in the database, let’s exit the shell by using Ctrl+D.
Now, let’s create an API endpoint, so that our frontend app can access the actors. Navigate to the urls.py
file in mobileBackend
app.
There is a very useful docstring describing how urls.py should be used. Django has added an 'admin/'
route by default for us. We have created a new route called 'fetch_actors/'
. We are also importing a function called fetch_actors
from actors.views
. We have not created this function as of now, but we will use this function to process the request and create a response. Let’s see what is happening here.
Whenever a user makes a request, Django first looks at this urls.py
file, and checks for a match between the request URL and the urlpatterns
specified here. If it find a match, it sends the request to the corresponding view function of that URL. A view function takes the request as an input, and produces a response. We don’t have the view function yet. So let’s create one.
Open actors/views.py
in your project. We have named our function fetch_actors
in urls.py
. We should give the function the same name.
Here, we are doing two additional imports. HttpResponse
and Actor
model. HttpResponse is a Django built in function which lets us send back Http responses. Pretty self explanatory isn’t it. We have also imported the Actor
model so that we fetch all the actor objects and send it as a response.
Let’s try visiting the URL. Please start your server, if it is not running, and go to http://localhost:8000/fetch_actors/
. You’ll see something like this:
Hmmm.. It definitely did the right thing, but this is not very useful to use isn’t it? If our frontend client were to make this request and if it gets this response, it won’t be useful at all. Just like how for two people to speak with each other, they both need to know the same language, frontend client and backend service should also speak the same language, so that the response is useful for the frontend client. And that language, in our case is, yes, you guessed it, JSON. Now how do we convert a QuerySet to JSON? Enter Django Rest Framework. This can be done using something called as a serializer.
Serializers
Again, it is just a fancy name for something very simple. A serializer represents Django models as JSON objects. There is no better way to understand this than writing some code. So we will do just that.
Let’s create a new file called serializers.py
in our actors
app.
We are using rest_framework
's default ModelSerializer
. All we need to do is create a class ActorSerializer
and specify the name of the model we want to serialize, and the fields that are required from the model as a list. You can also pass '__all__'
if you want to include all the fields. Now we can use this serializer in our view function to send the response as JSON.
Let’s modify actors/views.py
as follows:
We are importing the ActorSerializer
we just created. We are also importing two other things, an api_view
decorator, and we have replaced HttpResponse
from Django to the one from rest_framework
. The api_view
decorator wraps our view function to add the additional processing required from the rest_framework
. We also need to specify the allowed request methods, in our case, we only allow get
requests. The additional step between fetching the actor objects and returning the response to the user is the step where we are serializing the QuerySet to JSON with our ActorSerializer
. many=True
tells the serializer that there are potentially more than one object in the QuerySet. Once serialized, the JSON representation is available in serializer.data
. Hence we are sending that as a the response.Let’s trying checking our URL again.Goto http://localhost:8000/fetch_actors/
and you’ll see something like this.
Look at that! Nice, clean, JSON. Exactly what we wanted. In a few lines of code, we have
- Created a project and set up our first Django app.
- Created a model to store the actors.
- Created an API endpoint for our frontend client to consume.
- Set up a view function to respond to the API request in JSON format.
Hopefully, I have convinced you to use this architecture for your next project. Please feel free to ask any questions if you get stuck.
Thanks for reading!