Django First Steps for Total Beginners: A Quick Tutorial

Learn how to embed Plotly graphs in Django apps, among other subjects

Fabrício Barbacena
Towards Data Science

--

Photo by Faisal on Unsplash

If you love programming with Python and want to move to the web development area for the first time, I think Django might be the perfect fit for you. Django is one of the most popular Python frameworks, and it comes with great built-in solutions for very common tasks in web development, making it possible to implement projects and write code fast and efficiently. In addition, Django is also used in production by big companies, such as Instagram and Spotify. So, there is a very good chance that this wonderful Python framework can fulfill your project needs too.

I recently graduated from Coursera’s Django for Everybody Specialization, and I was amazed at how fast and simple it is to build a whole CRUD application with user authentication and login functionalities using Django built-in View Classes. I will always be thankful to Professor Charles Severance, from Michigan University, for putting together such an amazing and mind-blowing course that elevated my Django skills to a whole different level.

So, I decided to practice what I learned from this course by creating a simple CRUD application to manage and display data from movies I like. However, before presenting the code for this CRUD in a future article, I would like to put together some introductory information about getting started with Django. Hence this tutorial.

I hope this material can help someone out there. At least, it helped me since it was an opportunity to review some basic concepts and practices in Django.

I developed this tutorial using Python 3.10.2 and Django 4.0.2. I also used Git Bash as my terminal, which is a great way to run Linux commands in a Windows OS.

PART 1: FIRST STEPS

  1. Create a project folder named films_project and go inside it.
mkdir films_project
cd films_project

If not mentioned otherwise, all the terminal commands from this tutorial should be run inside the films_project directory.

2. Create a new virtual environment using the venv Python module. I’m naming my virtual environment .myenv , but you can use another name if you prefer.

python -m venv .myenv

3. Activate the virtual environment by running the correct command for your chosen terminal and OS. The command below works in my Git Bash for Windows. If you have doubts about activating virtual environments with venv, please consult the Python documentation.

source .myenv/Scripts/activate

After activating it, you should see your virtual environment name shown in the terminal, as in my example below:

Image by Author

From now on, all the commands must be run with your virtual environment activated.

4. Install Django with PIP:

pip install django

5. Start a Django project called project itself.

IMPORTANT NOTE: don’t forget the dot at the end of this command.

django-admin startproject project .

Running this command will create a manage.py file and a folder called project with five files in it (counting the __init__.py one). Thus, your films_project directory tree should look like this now:

Image by Author

Remember that .myenv is how I chose to name my virtual environment folder, which is collapsed in the image above (there are a bunch of folders and files inside it, which are not relevant for our tutorial).

6. Start a Django application named films:

python manage.py startapp films

A Django project can have one or more apps. You can think of apps in Django as a way of reusing code between different projects.

This command python manage.py will be frequently used in your Django project, so get used to it. Also, running just python manage.py in the terminal, without any other argument, will show you the list of all its available options.

The startapp command above created a new folder called films with some files and a folder inside it. Check them out:

Image by Author

The only file inside films_project/films/migrations is a __init__.py one, showing that this migrations directory should be used as a module in the future.

7. Every time we create a new app, we must add it to the list of installed apps inside the settings.py file. Let’s do this now. Open project/settings.py and add a string with the films app at the end of the list saved in the INSTALLED_APPS variable. Don’t remove or change any other string already in this list:

# inside project/settings.pyINSTALLED_APPS = [    'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
#new value below:
'films.apps.FilmsConfig',
]

While settings.py is still open, you can change the default language and timezone for the whole application in the LANGUAGE_CODE and TIME_ZONE variables.

8. Run the code below to check for errors:

python manage.py check

If you received the message ‘System check identified no issues (0 silenced)’, that means that your application is ok. We are now ready to start the local server and check our Django website for the first time.

9. Run the command below to start the local server in the default port (8000)

python manage.py runserver

Change the port if the 8000 one is already taken by another application in your computer. Just add the new port number (8050, for example) in the command:

python manage.py runserver 8050

10. Open your browser and go to one of the following address:

http://127.0.0.1:8000/

or

http://localhost:8000/

Exchange 8000 by your new port number, if necessary.

By accessing this server, which is running on your local machine, you will see the Django default homepage for a new project.

Image by Author

11. Notice that a new file called db.sqlite3 was created inside the films_project folder. That happened because sqlite3 is the default database configured inside the project/settings.py file. However, Django allows connections with many other databases; you just need to make the correct configurations. We won’t talk more about that now since such a topic is beyond the scope of our current basic tutorial.

12. There is already another route created by Django for you. First, be sure that your local server is running (that is, you executed python manage.py runserver in the terminal and there are no error messages there). Then go to the admin page and check it out:

http://localhost:8000/admin/

When you tried to access the link below, you probably saw a very ugly error message, with the information ‘no such table: django_session’ in the Exception Value field. I wanted you to see that page because we can learn a lot from the error messages that come on our way while programming. There is a very easy fix to this: we only need to run the command to create in the database the tables that the admin application uses. So:

13. Run the following command to create the database tables.

python manage.py migrate

About a dozen messages will be shown in the terminal console, saying that the migrations were applied. That means that Django created the necessary tables for the default applications in the database, such as admin. Actually, if you use a sqlite3 service to connect to the database and list all its tables, you would see these new tables created by the migrate command you have just run.

14. You will also need to create a superuser to log in to the admin area. Do that with the following terminal command:

python manage.py createsuperuser

Inform the user name, email, and password. Then, restart the server with the python manage.py runserver , and use your information to log in to the admin area. You’ll see the following page:

Image by Author

This is one of the many built-in resources that Django makes available to the developer from the very start, and I wanted to let you know that it exists, even though we won’t explore it now in this tutorial. The admin area is one of Django’s powerful features, so it is worth taking the time to learn how to use it.

PART 2: OUR FIRST ROUTES AND VIEWS.

15. Let’s create our first new route, which will replace the Django default page we have just accessed. We will do that by modifying the project/urls.py file. Notice that we are also adding a new import statement to it.

# inside project/urls.pyfrom django.contrib import admin
from django.urls import path
from films import views # added

urlpatterns = [
path('', views.home, name='home'), # added
path('admin/', admin.site.urls),
]

16. If we run python manage.py check now, it will return an error because your films/views.py is empty. Let’s correct that by adding the following function to this file:

# inside films/views.pyfrom django.shortcuts import render
from django.http import HttpResponse # added

def home(request):
return HttpResponse('This is the home page.')

Now access http://localhost:8000 again to check how the new modified page is displayed with the information we set in the home view function:

Image by Author

Well done! It doesn’t look fancy at all, but we need to appreciate what we have achieved here: we created our first webpage using Django and Python, and all that writing just a few lines of code and running a few commands in the terminal. Besides, all this knowledge will help us to create much more complex and exciting websites in the future, be sure of that. If we build our basis well enough now, we can become very skilled Django developers in the future, making great and helpful web applications and having fun programming with Python at the same time.

At this point, it is interesting to make some brief considerations about what Django considers as views. Unlike most MVC (Model-View-Controller) frameworks, where the view refers to the front-end part of the application, Django calls views the code where the application logic and rules are configurated. The interface part in Django is called template, which makes Django a MVT (Model-View-Template) framework.

I will say it again: the views in Django are where we will create our controllers, the application logic; it is not the front-end part (these are called templates in Django). I mention it here because that point confounds many people, especially those coming from the classical MVC pattern.

As we can see from what we have done so far, the home function in films/views.py is concise and straightforward; it just accepts a Request object as its argument and returns a Response object that writes a phrase in the DOM and displays it in the chosen URL. But we could also pass HTML elements to the Response object in a view function so that the browser would display them with different font sizes and formats.

17. Let’s then modify the home function in films/views.py as follows:

# inside films/views.pyfrom django.shortcuts import render
from django.http import HttpResponse

def home(request):
# remove these print statements later
print('\n\nRequest object:', request)
print('Request object type:', type(request), '\n\n')

html_tags = '''
<h1>This is the Home Page</h1>
<h3>Thanks for visiting us</h3>
<p>MVT means:</p>
<ul>
<li>Model</li>
<li>View</li>
<li>Template</li>
</ul>'''

response = HttpResponse(html_tags)
# remove these print statements later
print('Response object:', response)
print('Response object type:', type(response))
print('\n\nUser-agent info :', end='')
print(request.META['HTTP_USER_AGENT'], '\n\n')

return response

If your Django local server is running, stop it with CTRL + C, run python manage.py check to see if there is any error, and then start the server again with python manage.py runserver. Next, go to http://localhost:8000 and check the new webpage. Every time you refresh this page, a GET request is sent to the Django server, and the home function view is executed. You can check some information about the Request and Response objects, which we asked to be printed in the terminal console.

An important warning here: we will NEVER use strings with HTML tags in our Django production code. Otherwise, we will submit our application to XSS malicious attacks. So, we will just use HTML inside Django views in these first examples. Later I will show you how to use templates in Django to render HTML pages.

We will now create new routes to solidify what we have learned so far.

18. Create the file films/urls.py.

touch films/urls.py

19. Add a new route in project/urls.py. It will serve as an entry point for the routes we will create later for the films app.

# inside projects/urls.pyfrom django.contrib import admin
from django.urls import path, include
from films import views

urlpatterns = [
path('', views.home, name='home'),
path('admin/', admin.site.urls),
path('films/', include('films.urls')), # added
]

20. Fill the films/urls.py file with the new routes information.

# films/urls.pyfrom django.urls import path
from . import views

app_name = 'films'
urlpatterns = [
path('', views.main, name='main'),
path('user_info/', views.user_info, name='user_info'),
]

21. Add the new view functions at the end of films/views.py :

# films/views.py(...)def main(request):
message = '<h1>This is the films MAIN page.</h1>'
return HttpResponse(message)
def user_info(request):
message = '<h1>This is the films USER_INFO page.</h1>'
return HttpResponse(message)

22. Now visit the created routes and check if they are displaying the correct messages:

http://localhost:8000/films/
http://localhost:8000/films/user_info

PART 3: MAKING THE VIEWS RENDER HTML TEMPLATE FILES

It is now time to start using Django templates. For now, they will be simple HTML files rendered by the view functions.

23. Create the necessary folders where the HTML files will be saved.

IMPORTANT: note that two of these new folders are named templates: one is inside films, and the other one is directly in the project root at films_project, at the same hierarchical level of films.

mkdir templates
mkdir films/templates
mkdir films/templates/films

24. Create the following HTML files:

touch templates/home.html
touch films/templates/films/main.html
touch films/templates/films/user_info.html

25. Open project/settings.py , import the os module and, in the variable TEMPLATES, fill the empty list in the TEMPLATES['DIR'] key, with the following information (change just this one line and keep the other ones):

TEMPLATES = [
{
(...) 'DIRS': [os.path.join(BASE_DIR, 'templates')],(...)}
]

26. Put the following information inside the respective HTML files:

  • templates/home.html:
<h1>This is the Home Page</h1>
<h3>Thanks for visiting us</h3>
<p>MVT means:</p>
<ul>
<li>Model</li>
<li>View</li>
<li>Template</li>
</ul>
<h3>Link to the website pages:</h3>
<ul>
<li><a href="{% url 'home' %}">Home Page</a></li>
<li><a href="{% url 'films:main' %}">Films Main Page</a></li>
<li><a href="{% url 'films:user_info' %}">Films User_Info Page</a></li>
</ul>
  • films/templates/films/main.html
<h1>This is the films MAIN page.</h1>
<h3>Link to the website pages:</h3>
<ul>
<li><a href="{% url 'home' %}">Home Page</a></li>
<li><a href="{% url 'films:main' %}">Films Main Page</a></li>
<li><a href="{% url 'films:user_info' %}">Films User_Info Page</a></li>
</ul>
  • films/templates/films/user_info.html
<h1>This is the films USER_INFO page.</h1>
<p>Username: Fabrício</p>
<h3>Link to the website pages:</h3>
<ul>
<li><a href="{% url 'home' %}">Home Page</a></li>
<li><a href="{% url 'films:main' %}">Films Main Page</a></li>
<li><a href="{% url 'films:user_info' %}">Films User_Info Page</a></li>
</ul>

An important note here: if you visit the pages right now, you will notice that nothing has changed. That happens because we haven’t made any updates in our views. We need to make that each one of views renders the correct template.

27. So, replace all content in films/views.py for the new code below:

from django.shortcuts import render
def home(request):
return render(request, 'home.html')
def main(request):
return render(request, 'films/main.html')
def user_info(request):
return render(request, 'films/user_info.html')

Now visit the URLs and note the differences. Navigate through the links to move quickly between pages.

PART 4: AVOID CODE REPETITION BY USING A BASE TEMPLATE

I don’t know if you noticed it, but the code inside the HTML files has many repeated lines. That is not desirable at all since it violates the DRY (don’t repeat yourself) principle, and we need to fix that. Django allows HTML code that should appear in multiple pages to be written just in one HTML file, in a very easy way, using template tags.

28. Create a templates/base.html file.

touch templates/base.html 

We will now use some code from the Bootstrap web design framework in our project. Unfortunately, I can’t explain here how basic HTML, CSS, and Bootstrap code work. Otherwise, this tutorial would be even more extensive than it already is. However, those are really nice skills to learn if you want to work with web development, even on the back-end side. New knowledge never hurts, in my opinion.

So, if you want to know more about how to create nice webpages interfaces, I suggest that you check out the great course called Responsive Web Design Essentials — HTML5 CSS3 Bootstrap, by Daniel Walter Scott. The videos are very informative, the exercises are great, and Daniel manages to transmit his knowledge in a very effective and fun way.

29. Fill the templates/base.html file with the code below. This will be the code that will be extended in the other HTML pages:

Please notice here the following new structures presented in base.html:

  • {% block head %} and {% endblock %};
  • {% block content %} and {% endblock %};
  • {% if title %} and {% else %} and {% endif %};
  • {{title}}.

The notation {% %} is extensively used in Django templates language. The {% block BLOCKNAME %} and {% endblock %} tags are used to mark the points where the specific code blocks for each page in our application will be inserted, using the base template.

The Django template language uses a lot of filters, which allow it to execute functions and methods inside the templates. For example, we have already seen the {% url %} filter in use in early stages of our code: it receives a string as its argument, in the form 'app_name:route_name', and it returns an absolute path for a web resource. For example: {% url 'films:user_info %} will get the route named user_info, inside the films app, and it will return its path as a string and render it on the HTML page.

We can also notice that Django allows conditional statements inside templates. As we will see later, for loops are also a possibility here, which helps create more maintainable code.

Finally, notice the double curly brackets in {{title}}. This is the way Django has to render Python variables passed by the views to the templates. We haven’t done that yet, but we will later.

30. Replace the content for the HTML files as follows:

  • templates/home.html:
{% extends 'base.html' %}{% block content %}<h1>This is the Home Page</h1>
<br>
<h3>Thanks for visiting us</h3>
<br>
<p>MVT means:</p>
<ul>
<li>Model</li>
<li>View</li>
<li>Template</li>
</ul>
{% endblock %}
  • films/templates/films/main.html:
{% extends 'base.html' %}{% block content %}<h1>This is the films MAIN page</h1>
<br>
<h4>Some Pixar Movies:</h4>
<ul>
{% for number in '012'|make_list %}
<li>Toy Story {{forloop.counter}}</li>
{% endfor %}
</ul>
{% endblock %}
  • films/templates/films/user_info.html:
{% extends 'base.html' %}{% block content %}<h1>This is the films USER_INFO page</h1>
<br>
{% if userinfo %}
<h4>username: {{userinfo.username}}</h4>
<h4>country: {{userinfo.country}}</h4>
{% else %}
<h4>username: not informed</h4>
<h4>country: not informed</h4>
{% endif %}
{% endblock %}

Notice how each of these three last HTML files starts with {% extends 'base.html' %}, indicating that we are extending the template information that comes from the base.html file. Moreover, the HTML that we want to be displayed by each page is between the {% block content %}{% endblock %} tags, showing that we want it to be inserted in the place from base.html where these tags are located.

Now look for errors with python manage.py check and then run the server with python manage.py runserver. Check how more presentable our pages are now.

Image by Author

PART 5: PASSING PYTHON VARIABLES TO THE TEMPLATES

31. Now open films/views.py and replace the old code for this new version. Then run the server and notice how that change impacted the information displayed in the page’s title (the text meta information presented in the browser tab) and in the user information presented in the user_info page.

As we can see, the render() function can receive a dictionary (usually named context or ctx) as its third argument. We can then access these dictionary values by using just its keys without quotes.

Note, for example, how the title variable and its values appear both in the views and in the base.html template conditional structure. The home view function passes no title information, so the title value will be None, and the else clause will be executed, showing the default title on the home page. On the other hand, both the main and the user_info views functions have a key 'title' in the context dictionary, so its value will be ‘truthy’, and the if clause will be executed, showing the title value in the tag browser when the template is rendered.

Something similar happens with the userinfo variable, passed by the user_info view function to the user_info.html template. Note also that we will use a dot notation to access nested values, similar to what is used in Javascript objects. If you try accessing values in nested dictionaries with the context[key] structure from Python, it will not work and an error will be raised.

PART 6: USE DJANGO MODELS TO CREATE YOUR OWN DATABASE TABLES

32. Open films/models.py and insert the code below. We will create our first Django models.

Notice that Django models are created as classes that inherit from the models.Model Django class. We are creating here two tables: genre and film, with actually 2 and 4 columns respectively. We didn’t have to add the id column for each model in our code because, in the project/settings.py file, the variable DEFAULT_AUTO_FIELD is configured to create for every model table an id column with auto-increment integer values.

Notice also that the Film model has a foreign key column called genre, with a one-to-many relationship. That is not the perfect relation between these two tables. Still, we are using here a more simplified model for didactic purposes, since many-to-many models are more complicated and should be learned in a second moment.

32. Run the python manage.py makemigrations to create the migrations files that will set how these new two tables film and genre have to be created by Django.

33. Now run the python manage.py migrate command to actually create the two tables in the db.sqlite3 database, following the instructions created in the last migrations. Their names in the database will have the app name prepended to them, so the actual tables names will be films_film and films_genre, if you want to run some SQL code to check them out.

Now we are ready to populate these new tables we created. I will show here two different approaches:

  • using the admin area
  • using the Django shell

34. Open films/admin.py and add the following code:

from django.contrib import admin
from .models import Film, Genre

admin.site.register(Film)
admin.site.register(Genre)

By doing that, we are making the Film and Genre models accessible to the admin application.

35. Now go to http://localhost:8000/admin/, put the login information from the superuser you created, and check how the two new models appear on the screen:

Image by Author

36. Click on the Films link, find the Add Film button, fill in the fields and save the information. You can add a new genre right on this page by clicking on the green plus sign next to it. That will insert a new row in the genre table. Save at least three new movies. I saved the four Matrix movies, and you can see how their names are listed nicely in the admin area. I can click on any of them, make changes to their data and then press the save button. All these changes are automatically persisted in the sqlite3 database for the Django application.

Image by Author

37. Now stop the server and run python manage.py shell in the terminal. The Django interpreter will then be open. This is another really cool feature: it not only allows you to run Python code with the interpreter, but it also has all your project files loaded. So, you can run Django commands here using your project files, such as the models we have just created.

I will use a few commands here from Django ORM. It allows us to write Python code that runs queries in the database. The advantage of using an ORM is that, if we ever want to change our database connection to a MySQL or a PostgreSQL one, for example, we just need to set the correct database configurations in project/settings.py. All the queries using Django ORM (with Python code) will remain the same, which is fantastic, in my opinion.

38. Type the following commands in the Django shell we have just initialized. That will create new Film and Genre objects, save them to the respective tables and show a quick example of a SELECT query for all films in the films_film table.

Image by Author

Now, we will use these new models we created and connect them to our views so that the database data might be shown on our main web page from the films app.

39. Inside films/views.py, import the Film model and change the main view function. Keep the other views unaltered:

40. Open films/main.html and change its content to the code below. Note how we use a for loop to show all films info saved in our database.

{% extends 'base.html' %}{% block content %}<h1>This is the films MAIN page</h1>
<br>
<h4>Films saved in our database:</h4>
<ul>
{% for film in films_list %}

<li>{{film.title}} ({{film.year}}, genre: "{{film.genre}}")</li>
{% endfor %}
</ul>
{% endblock %}

Below is my screen after accessing http://localhost:8000/films. It shows all the five movies I saved in my database (the four Matrix movies and Finding Nemo).

Image by Author

This was just a brief example of how we can display information from our database and send it to one of our pages. Actually, Django has some customized views, built as classes, that we can use for some of these most common tasks, such as listing all observations (or part of them) on a webpage. This is done by the django.views.generic.list.ListView class.

We will not discuss more about view classes in this introductory tutorial. If you want more information about them, check this Django documentation page.

PART 7: QUERY PARAMETERS

Up to now, we have only dealt with GET requests. When we have a request with the GET method, we can pass parameters directly appended to the URL, called query parameters. We will modify the user_info view function to use these parameters as input to our templates.

41. Make the following modifications in the user_info function from films/views.py, keeping the other lines in the file.

In this new version, we have an if / elif structure where we check the request method. We will not access the elif part yet, but I chose to write it in the code already so that you can see how we could make a view function run code depending on whether the request method is either GET or POST. If we were using a class-based view, for example, we would have two class methods ( .get() and .post()), each one dealing with its respective request type.

I also want to call your attention to the important request.GET attribute, which accesses a dictionary with all the query parameters used in the URL.

42. Now, access the user_info URL and add the necessary query parameters, as the example below:

http://localhost:8000/films/user_info/?username=Neo&country=USA

Note how a question mark is used to start writing query paraments. Here we have two (username and country), with ‘Neo’ and ‘USA’ as values, respectively. Furthermore, we can observe that the pair query parameter name/value is separated by an equal sign, and the ampersand (&) sign is used to separate the different parameters.

Go ahead and change the parameters’ values, hit enter, and see how the values will change on the page. Check also the console to see how the query parameters dictionary is structured. You can get any of its values using the request.GET.get(KEY) code.

PART 8: HTML FORMS AND POST REQUESTS

Now let’s build an HTML form with a POST method.

43. Create the films/templates/films/user_form.html file and put following HTML code inside it:

44. Make a minor change in the templates/base.html navbar by adding a link to the new user_form page. I will not reproduce all the base.html code here again; I will just present the extra <li> tag to be added right before the closing </ul> tag:

<li class="nav-item active">
<a class="nav-link active" href="{% url 'films:user_form' %}">UserForm</a>
</li>

45. Add a new route to films/urls.py.

from django.urls import path
from . import views
app_name = 'films'urlpatterns = [
path('', views.main, name='main'),
path('user_info/', views.user_info, name='user_info'),

## new route below ##
path('user_form/', views.user_form, name= 'user_form'),
]

46. in films/views.py, modify the imports and the user_info view, on the one hand, and create the user_form view on the other. Since much has been changed here, I present all the file code with its modifications:

Let’s comment about this new films/views.py code in more detail. When we access http://localhost:8000/films/user_form for the first time, it will be a GET request, so the if clause in the view will be executed, just loading the respective template. But when we fill in the form fields and press the submit button, the POST method is activated, and the code in the elif clause is run.

As I learned in Professor Charles Severance’s course, it is good practice to send the data from a POST request to a different URL than the one where the form is located. When we do that, a GET request will be called to the new URL, and the POST data will be lost.

So, before we move to the next page, we need to save the data passed in the form. We do that by using request.POST.get(KEY) for every input field, where KEY is the value from the name attribute from the respective <input> HTML tag, so we cannot forget to set those. Then we can pass these values to another dictionary located in request.session, which is extremely helpful. It allows data to be stored in the current browser session and be retrieved in different moments by our code. That is why we can use, inside the user_info view, the information saved in the session dictionary and display them.

PART 9: ROUTE PARAMETERS AND DETAIL PAGES

47. Create a new route in films/urls.py. We will only show this line below, but you already know how to insert it in the file.

(...)path('<int:id>/details', views.details, name='details')(...)

Notice the new notation <int:id>. the < > signs here show we are dealing with a new parameter type called route parameter. int shows that it is an object from the int class and id tells Django that a primary key is expected here.

48. Create the films/templates/films/details.html template with the following content. We will use an HTML table structure with some Bootstrap classes now.

{% extends 'base.html' %}{% block content %}<h1>Film details:</h1>
<br>
<table class="table" style="width: 30%">
<thead>
<tr>
<th scope="col">Attribute</th>
<th scope="col">Value</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">Title:</td>
<td class="text-dark">{{film.title}}</td>
</tr>
<tr>
<td scope="row">Year:</td>
<td>{{film.year}}</td>
</tr>
<tr>
<td>Genre:</td>
<td>{{film.genre}}</td>
</tr>
</tbody>
</table>
{% endblock %}

49. Add the new details view in films/views.py. I commented out a line of code that can also be used to query for just a single element by id. Notice how the film id is passed as an extra argument to the view.

def details(request, id):
film = Film.objects.get(id=id)
# other query option:
# film = Film.objects.filter(id=id)[0]
context = {'film': film}
return render(request, 'films/details.html', context)

50. Now choose a route like http://localhost:8000/films/1/details and check this film info details. Change the id number manually so you can see other films details. If an unexisting id number is selected, an error will be raised by the view since it does not have an error-handling code for this kind of situation. So, if you find it interesting, search for ways to deal with this kind of problem.

PART 10: USING PLOTLY GRAPHS WITH DJANGO

This part will be potentially useful for people who want to put together these two amazing resources: Plotly graphs and Django. The most important things to note here are the following:

  • Use the .to_html() method from a Plotly Figure object and save it in a context dictionary with a name such as fig.
  • In the Django template, use the tag {{fig | safe}} to render the graph.

I will use the Gapminder dataset here to speed things up. Since it has nothing to do with films, it would be the proper procedure to create another Django app. But I won’t do that. Instead, I will put a new route outside the films one and borrow films/views.py to store the view and auxiliary functions necessary to display the graph. I will also use route parameters to filter the graph by year.

51. Open project/urls.py and add the new Gapminder route:

from django.contrib import admin
from django.urls import path, include
from films import views

urlpatterns = [
path('', views.home, name='home'),
path('admin/', admin.site.urls),
path('films/', include('films.urls')),
# new route:
path('gapminder/<int:year>', views.gapminder, name='gapminder'),
]

Inside films/views.py, we will add two functions that are not Django views since they will not process an HTTP request. The function get_data() only gets the Gapminder dataset from plotly.express as a Pandas DataFrame. And create_plot() will generate the famous Gapminder bubble chart. These functions are called inside the gapminder function view, and the year route parameter is used here to filter the dataset before generating the graph.

52. Install Pandas and Plotly with PIP:

pip install pandas plotly

53. Open films/views.py, import Plotly Express and, right after the last import, define the get_data() and create_plot() functions:

import plotly.express as px# keep the other imports(...)def get_data():
df = px.data.gapminder()
return df
def create_plot(df, year):
fig = px.scatter(
data_frame = df.query(f'year=={year}'),
x = 'gdpPercap',
y = 'lifeExp',
color = 'continent',
size = 'pop',
height = 500,
log_x=True,
size_max=60,
hover_name="country")

fig = fig.to_html()
return fig

54. At the end of films/views.py, create the gapminder view:

def gapminder(request, year):
df = get_data()
fig = create_plot(df, year)
context = {"plot": fig, "year": year}
template = 'gapminder.html'
return render(request, template, context)

55. create the file templates/gapminder.html and write the following code in it:

{% extends 'base.html' %}{% block content %}<h1 class="text-center">GAPMINDER (YEAR {{year}})</h1>
<div class="container-fluid d-flex justify-content-center">
{{plot | safe}}
</div>
{% endblock %}

56. Access an URL with a year present in the Gapminder dataset (such as http://localhost:8000/gapminder/2007) and play along with your web page and its nice interactive graph.

Image by Author

FINAL WORDS

If you arrived here and conquered this tutorial, you are a true warrior. Congratulations! Django is a whole world, and there is much more to learn about it; just keep studying and practicing then success will follow.

Thank you so much, dear reader, for having honored my text with your time and attention.

Happy coding!

--

--

Python and Django Developer • Data Analyst • BI Consultant • Data Science • Data Engineering • https://linktr.ee/fabriciobarbacena