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
ListViewgeneric 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
querysetattribute (which is shorthand for theget_querysetmethod) allows us to filter the list of objects returned byListViewthe way we need (here, we order them from most to least recent), while the default would be to simply specifymodel = Articleand getArticle.objects.all() - the
context_object_nameattribute 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 thestaticfolder {% block title %}and{% block content %}areblocktags 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
iftemplate tag and thelength_istemplate filter we check that ourarticlesvariable (which we have named withcontext_object_name = "articles"in theHomeview, remember?) has at least 1 article: - if there are no articles, we show a message
- otherwise, we iterate through the articles with a
fortemplate tag (the syntax is the same as for a normal Pythonforloop) 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).