Home page#
Introduction#
In this chapter, we'll bring an MVP of our app online: it'll have a landing page, some articles, and even a navbar! To achieve this, we will need to write our first view, templates, and URLs.
Home view#
Up to now, http://127.0.0.1:8000/ still shows the rocket celebrating a successful install, but what we want is to see our own app.
In Conduit, the default view that the unauthenticated user sees on the home page is the “global feed”, or the list of all articles. That's what we need to implement.
In articles/views.py
, we add the following:
1 2 3 4 5 6 7 8 9 10 |
|
Step by step:
- The
ListView
generic display view displays list of objects: the Django Girls tutorial only presents Function-Based Views, which are arguably a more intuitive option, but Class-Based Views (or CBVs) are considered to be best practice, at least according to Two Scoops of Django, and simplify a lot of work - the
queryset
attribute (which is shorthand for theget_queryset
method) allows us to filter the list of objects returned byListView
the way we need (here, we order them from most to least recent), while the default would be to simply specifymodel = Article
and getArticle.objects.all()
- the
context_object_name
attribute provides a human-friendly name for the context for us to use in the template (by default, the context would be stored in a variable namedobject_list
).
Home URL#
If you followed any previous tutorial, you will remember that, in order to display a view, we need to specify what URL it corresponds to.
To keep our app logic clear, we will be keeping everything segregated across our apps: since we want to implement a view of the list of all articles, we will specify the URLs in our articles
folder.
Let's create a articles/urls.py
, and add the following:
1 2 3 4 5 6 7 |
|
We're telling our Articles
app that the root URL (http://127.0.0.1:8000/) should return the view Home
that we created in the previous section. The as_view()
method for class-based views returns a callable instance of the view, same as if we were calling a function-based view.
However, Django doesn't know to look into articles/urls.py
: it is only aware of the default urls.py
file created earlier in the previous chapter. We add the following line in config/urls.py
, so that the project-level urls.py
is aware of the app-level URLs defined in articles/urls.py
:
1 2 3 4 5 6 7 |
|
Templates and static files#
We have a Home view and URL: we need a template now. In keeping with our commitment to keeping the structure of our project clear and logical, we will create a single project-wide folder for all templates, and we'll do the same for static files (icons, CSS, etc.): this kind of code is going to be heavily shared by both articles
and users
apps, so it's better to have a folder for the whole project than one for each app (all the more so that our apps are not expected to be plugged into other projects).
Let's create the templates
and static
folders:
1 2 |
|
We need to modify config/settings.py
so Django is aware of our project's architecture.
Let's define the APPS_DIR
below BASE_DIR
first: it will point to our conduit
folder and will make the next modifications a bit shorter.
1 2 3 |
|
The TEMPLATES
section of config/settings.py
holds the template-related settings: that's where we need to notify Django about where our templates are.
The DIRS
setting, which indicates the location of template source files should point to our new conduit/templates
folder:
1 2 3 4 5 6 7 |
|
We will also change the STATICFILES_DIRS
setting in the static files section of config/settings.py
so that it points to our new conduit/static
folder:
1 2 3 |
|
Base template#
Before we start writing the templates, a few words. As stated in the introduction, the HTML is adapted from other RealWorld projects: mostly the Svelte implementation (because Svelte is unexpectedly close to Django's templating language), but we also picked and chose from other projects, both in situations where the code or the file structure were more in line with what we needed here, or when the UI of one implementation was better in some way. However, because we're building the app from scratch (adding features, changing the UI, etc.), our file structure and code will be affected. The HTML of the finished Conduit app should be almost identical to any other implementation's HTML (take or leave some specificities of our chosen frameworks). Because this is not an HTML or UI tutorial, we won't be explaining the HTML files' structure, the classes, the CSS, etc. Onwards!
The groundwork is completed: Django knows where to find our templates. Let's create the base template then.
1 |
|
The templates/base.html
template, copied from Svelte's app.html file, will contain the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Step by step:
- the
{% load static %}
tag allows to make available the static files located in thestatic
folder {% block title %}
and{% block content %}
areblock
tags and define the parts of the template that will be overridden by child templates through Django's template inheritance, which will be illustrated in the very next section
We also need to download the favicon referenced in our template: download the file located at the URL below to static/icons/favicon.ico
:
https://github.com/gothinkster/react-redux-realworld-example-app/blob/master/public/favicon.ico
Home template#
Time to make the home.html
template: for now it only needs to display our “global feed”.
Let's create the templates/home.html
template (based on Svelte's index.svelte and ArticleList templates) and add the following to it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
|
A quick explanation:
- we show the classic Conduit banner
- with an
if
template tag and thelength_is
template filter we check that ourarticles
variable (which we have named withcontext_object_name = "articles"
in theHome
view, remember?) has at least 1 article: - if there are no articles, we show a message
- otherwise, we iterate through the articles with a
for
template tag (the syntax is the same as for a normal Pythonfor
loop) and show a preview:- the preview contains the article's author's username, creation date, title, and description
- the preview redirects to nothing for now (even though we don't have any links to show yet, we need to have a link there for CSS reasons)
Let's go to our server and reload the page: surely we can finally contemplate our glorious creation? No. If you've been following, you should see the error below:
TemplateDoesNotExist at /
articles/article_list.html
Request Method: GET Request URL: http://127.0.0.1:8000/ Django Version: 4.0.4 Exception Type: TemplateDoesNotExist Exception Value:
articles/article_list.html
What the error says is that the template is missing, even though we know that it definitely is there. The issue is that Django expects a template named article_list.html, which is the default template expected by our Home
view, which is a ListView
for the Article
model. To fix that, we need to go to articles/views.py
and add the following:
1 2 3 4 5 6 |
|
Try reloading again and this is what you should see:
It's starting to look like something! However we can improve the template a bit.
Breaking templates into subtemplates#
We want to keep our templates as modular as possible, to simplify the structure of our project and make it easier to think about.
The structure of the Svelte implementation makes a lot of sense and avoids us having to reinvent the wheel, so we'll take advantage of it.
Specifically, we will copy the Svelte implementation's ArticleList structure by moving the whole {% if articles|length_is:"0" %}...{% endif %}
clause HTML out of templates/home.html
and into two separate files.
In templates/home.html
, we remove the if
clause and replace it with an include
tag:
1 2 3 4 5 6 7 8 9 |
|
We create templates/article_list.html
and add the code that we removed earlier, except the contents of the for
clause:
1 2 3 4 5 6 7 8 9 10 11 |
|
The templates/article_preview.html
template will contain the remaining code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Reload the Conduit app to check that everything's still working.
Navbar#
Let's create a simple navigation bar now. Because we have yet to implement authentication and profiles, the navbar will just contain a link to Home
, the page we just finished building.
Let's add the following lines to templates/base.html
:
1 2 3 4 5 6 7 |
|
Let's create templates/nav.html
and add the following to it (copying Svelte's Nav.svelte template):
1 2 3 4 5 6 7 8 9 10 11 12 |
|
The url
tag is new to us: it enables us to specify URLs by name, instead of writing them every time we need to make a link in our HTML.
In this case, we want our navbar to redirect users to the Home
view, which is matched by the URL named home
(as specified in articles/urls.py
).
Try clicking on the link: your page should reload (because you're redirected to it).