What are we building?
In this tutorial, we will be building a Django application from the ground up which will allow the user to query Github data through the use of a form. To build our application, we’ll be using a wide array of technologies. We’ll use pip for Python package dependency management, bower for front-end dependency management, Twitter Bootstrap for design, Requests for making HTTP requests, the Github API as our data source, and of course, Django.
This tutorial assumes very little, so we’ll cover the following concepts throughout:
- Model, View, Controllers (MVC)
- JavaScript Object Notation (JSON)
- RESTful APIs
- Application flow within Django applications
The complete source for this project can be found here.
Application Flow
The behavior of any Django Application (or web frameworks, in general) can be broken down as follows:
- The user visits a URL, such as
/amazon/games
- This triggers a request to that URL, which is looked up in our URL dispatcher
- The URL dispatcher will map this URL to a function within our Views
- The corresponding View function will then access models, perform queries or fetch data as needed, which is bundled up and passed into a template
- The data passed into the template is then displayed to the user using HTML
By following this flow, it becomes easier to reason about our applications even when they begin to grow larger and larger.
Models, Views, Controllers
The core structure of any web framework can be broken into three parts: the Models, Views, and Controllers. This pattern allows developers to have a separation of concerns when building an application, and allows us to impose a logical structure to our projects. Let’s go over these parts in more detail.
Models
Within a web framework, Models are your data layer. At any given time, your models will represent what your objects in your database will look like. For example, take a look at the following Django model shown below:
Where first_name
, last_name
and age
will be fields in each Student
object. Django provides easy to use validation methods through CharField
, IntegerField
and much more, allowing model fields to only accept certain inputs.
Under the hood, Django will use these models to create Structured Query Language, which in turn will store these models into a SQL database (MySQL, SQLite3, PostgreSQL). Using these methods, we won’t have to write our own database logic using SQL.
Views
A view is typically a visual representation of our underlying data layer (models). Views can update models as well as retrieve data from them through a query, which in turn would be passed to an HTML template.
In Django, views generally consist of a combination of templates, the URL dispatcher, and a views.py
file. When a user navigates to a URL, a callback function is run which maps that particular url (such as /games
) to a method named games
within views.py
which may in turn query models or some external API, and finally pass that data to a template using methods such as
render.
Controllers
In Django, controllers are generally described as the underlying mechanisms of the framework itself which sends web requests to the appropriate view in combination with the URL dispatcher. In a sense, Django is more of a “Model, Template, View” framework as there are no explicit “Controllers”.
RESTful APIs
Without getting too deep into the meaning of “RESTful API”, this term essentially means that there exists a web service which understands HTTP requests (GET, PUT/UPDATE, CREATE, DELETE). Any program that can send a web request (such as a Python program using the Requests library) can interact with these web service and receive data back in the form of either JSON or XML. This application will make use of the Requests library to send HTTP GET requests to Github’s RESTful API which in turn will return JSON, which we will parse and render through an HTML template.
JSON
JavaScript Object Notation (JSON) is a way to store information in a lightweight, organized structure, containing a series of key/value pairs which can easily be parsed (extracted).
JSON is used for websites such as Twitter, Facebook and Flickr to update asynchonously (without page reloads), and is the core in developing full-stack JavaScript applications. A sample snippet of JSON from Facebook can be seen below:
Step 0: Installation
Before we can get started, we’ll need to get some dependencies out of the way. To begin, we’ll need to install the
Python Package Manager, pip
. Mac, Linux and Windows users may refer here for instructions for installing pip
.
Tip: I highly recommend creating a Virtual Environment. These environments allow you to effectively "sandbox" python packages, which is great for development.
With pip
in tow, we’ll install the following dependencies:
- Django
- Requests
To do so, simple run the following commands in your terminal:
With that all said and done, let’s get into the development of the application.
Step 1: Starting our project
To kick things off, let’s create our Django project. Within your terminal:
Where demonstration is the name you choose for your own project.
Warning: Avoid using names such as django or test, these names will collide with built-in Python packages.
Let’s take a look at our brand new project:
Breaking down each of these files:
-
demonstration/manage.py: A command-line program allowing users to interact with their Django applications.
-
demonstration/demonstration/init.py: An empty file signifying that this directory is considered a Python package.
-
demonstration/demonstration/settings.py: A file consisting of key-value pairs for configuring your Django application. You can configure your databases, setup paths to static files, and much more.
-
demonstration/demonstration/urls.py: Allows us to map view functions to URLs, which is essentially a table of contents for our application. You can read much more about it here.
-
demonstration/demonstration/wsgi.py: Allows us to deploy WSGI-compatible web servers, which you can read about more here.
Running the server
Django comes pre-packaged with it’s own web server, which is pretty awesome. It allows us to run our application locally, and view any changes that we’ve made. To do so, let’s go ahead and run the following command:
Tip: I recommend having multiple terminal sessions open, one for having the Django server running, one for opening up text editors and one for comitting to a repository if you are using version control while building this application.
When running this command, you’ll be greeted with the following error in your terminal:
Let’s go ahead and fix that. You can stop the server using Control + C
(Command + C
on a Mac). Go ahead and run the following command:
This command will build all of the default database tables that Django needs for built-in services such as user authentication. For now, this isn’t too relevant to us.
Note: This will generate a db.sqlite3 database file, which would generally contain information regarding our models. For this project, we won't be dealing with the database.
Once again, we’ll run the server:
Navigate to http://127.0.0.1:8000/ and you’ll be greeted with the nice shiny page:
Great! You’ve run your first Django web application. However, as the message states, we haven’t configured any URLs yet. We’ll get to that shortly, but for now let’s actually create our application.
Step 2: Creating your application
You’re probably thinking, “Didn’t we already create our application?” Not quite, that was our project environment that we setup earlier. Within a Django Project, there can exist many “Applications”, one of which we’ll create right now:
Where app is the name you’ve chosen for this specific application. It is within this folder that we’ll be writing a bulk of our code in, with the exception of modifying the base urls.py
and settings.py
file.
Breaking down these files:
-
app/admin.py: Allows us to register our models to view on the Django Admin Site.
-
app/migrations: Keeps track of our migrations which are essentially Django’s way of propagating changes that are made to our models.
-
app/models.py: Stores our representations of objects which will be stored in our database.
-
app/tests.py: Our unit tests will live here. Although Django calls these tests “unit tests”, they’re actually closer to integration tests.
-
app/views.py: All of our views will live here, which are mapped to URLs.
With that, we’ve successfully generated our project scaffold. Before moving on, we’ll configure our Settings.py
while which will be important going forward.
Configuring Settings.py
Settings.py
contains various configuration options available, such as changing your database and so much more. For this project, we’ll need to add the following lines anywhere in this file:
This will configure our paths for our Static files (CSS, JavaScript, images, etc) as well as the path to our template files.
Lastly, we’ll need to register your application (named app) under the Installed Apps section:
We’ll now move onto configuring a basic URL which will print out “Hello World”.
Step 3: Your First View
As mentioned earlier, URLs map to functions in your views.py
which in turn will pass data to a template. Within app/views.py:
Tip: Python has a great style guide, which I highly recommend taking a look at. At the very least, learn to adopt not mixing tabs with spaces, which will make your code consistent and avoid errors when running your Python code.
In order to map urls to our view methods, we’ll need to configure them. Within our root URLs file within the demonstration folder, we’ll configure our urls to be proceeded by app/
:
Now, our URLs may be accessed as http://127.0.0.1:8000/app/<view url>
. We’ll now create a new urls.py
file within app/:
And we’ll add the following content:
Tip: You can read more about URL configuration here.
After configuring your app/urls.py as shown, you should be prompted with the following response when you navigate to http://127.0.0.1:8000/app/:
We’ve successfully mapped the /app/
url to the index
function within app/views.py. Pretty simple, right? At this point,
can you see the application flow that we described earlier? To further emphasize this, try and see if you can create a new url, map it to your view, and display the string My second view!
on your own. We’ll include the code to do so below:
If we navigate to http://127.0.0.1:8000/app/test/, you should be greeted with the text “My second view!”.
Alright, you should be getting the hang of it now. We’ve been making some toy views, but how about we move onto displaying some meaningful data to the user? In particular, we’ll display the Github profile information for a given user.
Step 4: Integrating the Github API
The Github API contains a collection of URLs which a developer can query using HTTP methods to retrieve data, in the form of JSON. In order to leverage this API, we’ll use the Python Requests library which will make this process simple. From the API for users, we can get profile information by using the following URL:
Where :user is the name of the Github user you’d like to query profile information about. Before we display this data in Django, I highly encourage you to open up a terminal shell and try the following:
You should be presented with the following data:
As easy as that, we performed an HTTP GET request to the API endpoint and received JSON back. Let’s go ahead and wire this up in Django. As an exercise, try to create the urls and view method yourself before moving forward.
Going forward, we’ll need a method to load json strings easily. Be sure to import json
as shown in the code snippet below:
Navigate to http://127.0.0.1:8000/app/profile and you’ll be greeted with the following response:
At the moment, the output is kind of messy. Let’s update our view profile
view to bundle up the values in the JSON that we are interested in displaying to the user:
Which will return the new response:
As of now, we’ve covered a bunch of topics in only < 30 lines of Python. Let’s take a moment to recap what we’ve learned:
- Creating our project structure
- Learned the basics of MVC
- Mapping our URLs
- Writing several view methods
- APIs, and how to query data using Requests
- Displaying data to the user
You might be thinking that our design leaves plenty to be desired. If so, you’re right. We’ll use the Twitter Bootstrap library to spruce things up within a template, but before that we’ll install Bower to grab our front-end dependencies.
Bower
Bower is a front-end dependency manager for your project. In laymans terms, it is a command-line program which you can utilize to download libraries such as Twitter Bootstrap. The beauty of this approach is that we can generate a bower.json
file, which any user can copy and use to download a bunch of packages easily - as opposed to going to each site, and manually copy/pasting/saving out files.
In this step, I’ll walk you through downloading Twitter bootstrap as well as generating your own bower.json
. Before we do this, we’ll create a .bowerrc
file.
In the same directory as manage.py
, create a .bowerrc
file with the following content:
Anytime we run bower
, it will output the downloaded files within the directory listed here.
Tip: There is a huge array of configuration options which can be used, for those curious.
And now in our command line, we can simply run:
This will download Twitter Bootstrap into our project directory, as specified within our .bowerrc
file.
Step 5: Templating
Templates in Django are essentially HTML files which we pass in a context which then renders our data to the user. Before we can create our first template, we’ll need to create some folders. In the same directory as your app/views.py:
Within our templates/app folder, we’ll create our profile.html
:
Most of this is just Bootstrap classes for styling, but there is one important syntax to observe here:
This syntax allows us to iterate over a data structure using a for
loop, which should look familiar. Within this for
loop, we do the following:
In this case, data
is an array of dictionaries, in which each dictionary has the name
, blog
, and public_repos
keys (and a few others, listed in the above snippet for brevity). Here we access these properties and display them using the double curly braces syntax, which are template varaible placeholders which will take on the value of the expression within.
Tip: For deeper insight to templating and variables, check out the documentation here.
With this new template in hand, let’s reload our profile
page:
Awesome, we’ve got a nice layout. As of now, our view method is essentially hardcoded - we can’t query any particular user’s Github information. We’ll need to come up with a way to ask the user for an input, and to do this we’ll move onto forms.
Step 6: Forms
Forms are the bread and butter of web applications - every web programmer will come across them at one point or another. Forms essentially allow users to interact with your web application through various fields for input, usually for registration pages or in our case, performing a query.
To begin, we’ll go ahead and build our form within our profile.html
:
Let’s break this down in pieces:
This is simply a CSS class which we’ll use to style our form with.
Here we are creating our form
element which is styled by our CSS class using:
We’re also specifying the type of HTTP method this form will perform after submission:
Once we submit our form, it will perform an HTTP post request which will send the input that the user inputs as parameters to the following url:
Where /app/profile/
is our view function which will handle the POST request.
The csrf_token
will protect against any cross site forgery attacks.
Next, we look at our input field:
Which has the following attributes:
The most important attribute to pay attention to is name=user
. This name
parameter will have it’s value user
sent as a POST parameter once the user submits the form, which we’ll get into shortly. The last bit for our form is the actual submission, which will be a button:
Where we provide attributes specifying the bootstrap styling class btn btn-lg btn-primary btn-block
, as well as the type of action to perform when this button is clicked (in this case, a submit
action.) Once this button is clicked, the form will be submitted and the values from it’s form fields (here we only have one form field) will be sent as a POST request to the corresponding URL set earlier.
Putting it all together:
Next, we’ll learn how to capture these POST parameters in our views and use them.
Step 7: Capturing POST parameters
As mentioned, performing a POST request will send parameters that can be accessed programmatically. Let’s modify our profile
method within app/views.py to access the user
value that was passed through our form submission:
Most of the code is exactly the same, but we’ll break down the new additions in pieces:
If our profile
method was accessed through a POST
request, this condition will be true. Likewise, we could write additional logic to handle cases for GET
, UPDATE
, and DELETE
requests here based on the type of request we specified in our form.
Here we actually access our POST parameters. From our form, we know that our single field had an attribute of name
with a corresponding value user
, which was passed upon form submission. We’ll use this value to build a request url:
And the rest is the same as before. Using the new parameterized url, it will grab the Github profile information for a given username as passed through our form. Go ahead and try putting in various usernames of your friends on Github!
I hope this guide has been helpful for beginners (and possibly non-beginners). I’ll be exploring more complicated tech stacks using Django + ReactJS in the near future, so stay tuned for more tutorials.
Thanks for reading.