This post is a continuation of a series I am writing on using Django as an API. In this section, I will cover initializing the Django app, creating models and migrations, and setting up PostgreSQL as a database.
Django, as I suspect many people reading this post know, is a high-level Python framework which simplifies and streamlines web development. As with other frameworks, Django does much of the heavy lifting by making design and implementation decisions for developers, providing pre-built solutions to common requirements and allowing developers to spend more time solving business-specific challenges, instead of commonplace tasks. For example, most web applications will need to interface with a database. Frameworks, like Django and Ruby on Rails, make decisions on how to implement this interface and abstract the details of this implementation away from developers, providing an easy-to-use, albeit opinionated API for database transactions. Frameworks are fantastic tools for increasing productivity in the development process by allowing developers to focus on the most meaningful and distinctive parts of a web application.
Consequently, developers need to learn the programming language to develop the application logic and the framework’s API. Every framework has its own conventions or its “way of doing things”, just as every programming language has nuances and unique features. Learning a framework’s conventions is fundamental in learning how to use the tool in the first place.
Creating a Project
Django has many conventions which guide the development process. However, the first and arguably the most important is how to set up Django Projects. Oftentimes, we refer to our projects as applications, or even apps for short, but calling your “project” an “app” in Djangoworld this would be a serious misnomer. Django reserves the word Project for the directory “…that contains all the settings for the instance of Django… [including] database configuration, Django-specific options and application-specific settings.” An app, on the other hand, is quite specifically the web application that solves a specific business challenge. In this sense, Django separates projects from apps in that a project may grow in scale such that it contains several apps within it. For example, imagine a web site that contains an e-commerce store, a blog, a polling system, and a social media app within one single domain. Django would allow us to create a single project and develop each section of the web site as individual apps within the directory structure of the project.
Navigate to the folder where the Django project will be stored, then run the following command:
django-admin startproject your-site-name
The startproject command will create a your-site-name directory within the current folder. The directory structure includes a manage.py, your-site-name subdirectory, __init__.py, settings.py, urls, py, asgi.py, wsgi.py files. I recommend taking some time to investigate the purpose of each of these files on the django website, https://docs.djangoproject.com/en/3.1/intro/tutorial01/ .
At this point you can check to see if your site runs (and it should) on your localhost. Simply run the command below inside of your after navigating into your Django project directory in the terminal:
python manage.py runserver
The runserver command starts a lightweight, development server accessible on your local machine by navigating to http://127.0.0.1:8000. Generally speaking, the localhost can be found by requesting the IP address, 127.0.0.1, in your web browser. The portion of the URL following the colon, :, is the Port which allows the server to know where your project is being run specifically on your machine.
Test-a-little: At this point you should be able to verify that the server is running in your web browser. Just load the localhost and you should see a celebratory page with a rocket taking off!
Apps are subdirectories of your directory structure which handle specific and custom functionality for your project. A project can be made of up of one or more apps by creating them within the top-level project directory.
Create a new app called api, by running the following command within the top-level project directory:
python manage.py startapp api
In this case, the api argument of the startapp command is the name of the app. However, an app can have almost any name. If, for instance, the app were to be a social media feed, simply interchange the word ‘api’ for ‘feed’. The reason that we are using api is that it is a generally-held good practice to create api endpoints and configure their urls through a route which starts with api/. This implementation is by no means the only way to create this routing, but it is how we will set up this app.
The startapp script will create a new subdirectory by the name api which contains: __init__.py, admin.py, apps.py, migrations, models.py, tests.py, views.py.
Test-a-little:We can write a quick sanity check just to make sure our app is properly connected and sending data to the browser.
Setting up Postgres
Out of the box, Django comes configured to run SQLite as its database. However it is possible, and probably recommendable, to change the database from SQLite to another, scalable SQL language. Sure, SQLite is a great solution if you are developing a local app with no intentions of scaling or deploying it into production. But SQLite is not suitable for deploying and owing to its many differences with other querying languages, it is a wiser decision to configure some other SQL from the beginning. Another reason to change SQLite is because most businesses do not use SQLite for their development. Thus, practicing with common industry tools is preferable to spending time developing skills which will not translate as easily into a position.
In this case, I have chosen to work with Postgresql which is my preferred SQL which means that the first step is to install the appropriate adapter. Run the following command within your virtual environment:
pip install psycopg2
Next, move to the project Settings.py file in order to set the Database connection settings. Since, we decided to use Postgres instead of SQLite, we must update the configuration so that Django knows to point at our Database instance instead of the default SQLite db. We will update the DATABASES dictionary with the following code:
Explain each key
IMPORTANT: Environment Variables and SecurityIt may be worth setting up an environment file in order to hide your name, user, and password information, if you plan on using version control. While setting up an environment file is outside of the scope of this post, I highly recommend following the instructions here for a painless implementation.
While the TEST is optional, it is nice to have a test db if you are planning on taking the app into production.
While we are here, it may be worth while to update your time zone settings. Simply, locate the ‘TIME_ZONE’ variable within the Settings.py file in the project folder and set the appropriate timezone string. You can reference Django for the proper formatting.
Models are a core concept of the MVC and MTV development patterns. In essence, models are the single source of truth for the attributes and the behavior of the data in your app. Functionally, they are class-based constructs within the application that point to specific tables in the database. Additionally, models allow developers to define methods for custom functionality while providing a specific space to develop these features. A general consensus among proponents of the MVC pattern is that the so called “business logic” of an application belongs in the model section.
In this example, we can create two models: Company and Employee.
from django.db import modelsclass Company(models.Model): company_name = models.CharField(max_length=200)
industry = models.CharField(max_length=200)
owner = models.CharField(max_length=200)
email = models.CharField(max_length=100) def __str__(self):
return self.company_nameclass Employee(models.Model): first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
username = models.CharField(max_length=200)
password = models.CharField(max_length=200)
email = models.CharField(max_length=100) def __str__(self):
Frameworks like Django provide an abstraction layer between the Database and the Server-side logic. Even though this is not necessary strictly-speaking, it is a welcomed feature in that it allows for developers to interact with the database in the server-side language — Python, in our case.
A migration is a way to to synchronize the Database with the model logic and maintain a record of changes to the database schema. The standard work flow is a two step process: 1) create a migration and 2) execute the changes. Django will create new migration files containing the instructions to create the tables and fields associated with your apps, each time this process is completed. In order to create a migration, Django uses the makemigrations command. Simply make your desired changes to the model class and run the following command in the terminal:
python manage.py makemigrations
Django will compare your model definitions to the previous files in the migrations directory and output the differences found in the terminal. If the information presented in the terminal is the correctly subject of the change, then run the migrate command to execute the change:
python manage.py migrate
It should also be noted that the migrate command runs through the INSTALLED_APPS list from the settings.py file and creates all the database tables required by the apps included in the list.
It is my continued hope that this blog post can provide newer developers with context surrounding the why’s of Django (and Python) as an API (and backend language), and to clarify the how’s by producing a simple, step-by-step process to follow. In the next section, I hope to cover the creating views and routes, REST conventions, CORS, and authentication. Furthermore, I will present this information in such a way that you can connect any frontend application (vanilla JS, React, Vue, Angular) to the Django API.