In this way, which people call development with Django templates (Django Template Engine) or Server-Side Rendering, the front-end and the backend are not separated. Django takes the data directly from the database and puts it inside HTML files that are written with its own special syntax (like {{ variable }} and {% tag %}). The final result is a complete HTML page that is sent to the browser of the user. In this architecture we do not need a separate API or a front-end framework, and everything is done in one single project. In this way, the logic of showing the data and reaching the data is fully handled on the server side, and the user only sees the final result.
In this part, with the way that we explained and with the html/css/js knowledge from the parts before, we finish the front-end of a real project. For this we follow the steps below.
- First we get to know the existing project and what it can do.
- Then I explain the features that we must build.
- And at the end we start writing code.
Setting up the project
First download the backend of the project by clicking on the button below.

Then, with cmd or Terminal, go into the folder where the manage.py file is. Then make a virtual environment with the command below.
python3 -m venv env
py -m venv env
Then activate it with the command below.
source env/bin/activate
envScriptsactivate
Then install the packages that you need with the command below.
pip install -r requirements.txt
Then make the database with the command below.
python manage.py migrate
py manage.py migrate
Then put some fake news into the database with the command below.
python manage.py import_news
py manage.py import_news
Then run the project with the command below.
python manage.py runserver
py manage.py runserver
If you need to go into the Django admin dashboard, use the command below to make a user. After that you can log in at localhost:8000/admin with the username and the password that you chose.
python manage.py createsuperuser
py manage.py createsuperuser
Getting to know the project
This project is a news site and its backend is built with Django. This part is easier for people who know the basics of Django, but if you know nothing about Django do not worry, because the parts that talk to Django are very simple.
This project has 5 main parts. Some of them are finished and some of them need to be finished.
1. News list page (home page)
A page that shows the list of all the news with pagination buttons to see more news. This page is at the address below.
2. News detail page
A page to see the details of a news item, with edit and delete buttons. If the id of a news item is 350, you can go to this page with the address below.
3. Add news page
A page with a form for adding news. It is not finished yet and right now it is empty. This page is at the address below.
4. Edit news page
A page with a form for editing news. It is not finished yet and right now it is empty. If the id of a news item is 350, you can go to this page with the address below.
5. Delete news
There is no page for deleting news, but if the id of a news item is for example 350 and we send a POST request to the address below, that news item is deleted.
localhost:8000/news/delete/350
Task one – adding a search and filter form to the home page
Task one description
Build a search and filter form like the picture below.

For the search action send the word search, and for the filter action send the word category, with the GET method to the address of the same page. The values that category accepts are below.
- Cultural
- Political
- Sports
- Scientific
Doing task one
Open the index.html page and put the code below on line 14 of it.
<form class="toolbar" method="get">
<input type="text" name="search" class="search-input" placeholder="Search by title...">
<select name="category" class="filter-select">
<option value="">All Categories</option>
<option value="cultural">Cultural</option>
<option value="political">Political</option>
<option value="sports">Sports</option>
<option value="scientific">Scientific</option>
</select>
<button type="submit" class="apply-btn">🔍 Apply Filters</button>
</form>In the code above:
- Line 14
- Because the task says that the information must go to the backend with the GET method, we did not set the method attribute for this form, because by default this attribute is
method="get". - Because the task says that the form must be sent to the address of the same page, we did not set the action attribute for this form, because its default value is
action=""and this means that the form information goes to the page where we are right now.
- Because the task says that the information must go to the backend with the GET method, we did not set the method attribute for this form, because by default this attribute is
- Line 15: the field has
name="search", so when the form is submitted, the value of this field goes to the backend with the key search. - Lines 16 to 22: for the select field we set the attribute
name="category", so when the form is submitted, the value of the chosen option goes to the backend with the key category. - Line 23: by putting
type="submit"on this field, we made it send the form information to the backend when somebody clicks on it.
Task two – building the delete news feature
Task two description
There is a delete button on the news detail page. Make it work, so when the user clicks on it, the news item is deleted.
Doing task two
Open the news-detail.html page and put the code below in the place of the code on lines 33 to 36.
<div style="margin-top: 1.5rem; display: flex; gap: 0.5rem; align-items: center;">
<!-- Delete form (POST) -->
<form action="http://localhost:8000/news/delete/{{ article.id }}/" method="post" style="display: inline;">
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
<button type="submit" class="btn btn-danger">🗑 Delete This Article</button>
</form>
<!-- Edit link -->
<a href="{% url 'edit_news' article.id %}" class="btn detail-btn">Edit</a>
</div>In this code:
- Line 35
- We set the action attribute to say the address where the form information must go.
- By putting
method="post"we said that the information must go to the backend with the POST method.
- Line 36: for more security, Django expects that every form that is submitted with the POST method has a hidden field like the one on this line. What this field is and how it helps the security is not the subject of this course, so I do not explain it. To make it easier, Django gives us a way to replace this line with
{% csrf_token %}. - Line 37: there is a button for submitting the form.
With the note about csrf_token, we can make the code above better like below.
<div style="margin-top: 1.5rem; display: flex; gap: 0.5rem; align-items: center;">
<!-- Delete form (POST) -->
<form action="http://localhost:8000/news/delete/{{ article.id }}/" method="post" style="display: inline;">
{% csrf_token %}
<button type="submit" class="btn btn-danger">🗑 Delete This Article</button>
</form>
<!-- Edit link -->
<a href="{% url 'edit_news' article.id %}" class="btn detail-btn">Edit</a>
</div>Task three – building the add news page
Task three description
Build a form for adding news in add-edit-news.html, so the final result looks like the picture below. For this, use the information that comes after this.

The information that must go to the backend from this page with the POST method is below.
| Field name | Expected value | Required | Description |
|---|---|---|---|
title | String | Yes | The title of the news |
description | String (long) | Yes | The full text of the news |
publish_date | String with the format YYYY-MM-DD | Yes | The publish date |
category | One of the category keys | Yes | The chosen category (cultural, political, sports, scientific) |
saveAsDraft | The string ‘on’ when the box is ticked | No | If the checkbox is on, the news is saved as a draft. |
image | File (optional) | No | The image of the news; when editing, if you send nothing, the old image stays. |
Doing task three
Open the add-edit-news.html file and replace its line 11 with the code below.
<h2>📝 Add New Article</h2>
<form method="post" enctype="multipart/form-data">
<div class="form-grid">
<div class="form-group full-width">
<label for="title">Title *</label>
<input type="text" id="title" name="title" placeholder="Enter news title" required>
</div>
<div class="form-group full-width">
<label for="desc">Description *</label>
<textarea id="desc" name="description" placeholder="Full article text..." required></textarea>
</div>
<div class="form-group full-width">
<label for="img">Image</label>
<input type="file" id="img" name="image" accept="image/*">
</div>
<div class="form-group">
<label for="date">Publish Date *</label>
<input type="date" id="date" name="publish_date" required>
</div>
<div class="form-group">
<label for="category">Category *</label>
<select id="category" name="category" required>
<option value="">-- Select --</option>
<option value="cultural">Cultural</option>
<option value="political">Political</option>
<option value="sports">Sports</option>
<option value="scientific">Scientific</option>
</select>
</div>
<div class="form-group full-width">
<label class="checkbox-wrap">
<input type="checkbox" id="draft" name="saveAsDraft">
Save as Draft
</label>
</div>
</div>
{% csrf_token %}
<div class="form-actions">
<button type="submit" class="btn btn-primary">💾 Save Article</button>
<a href="/" class="btn btn-outline">Cancel</a>
</div>
</form>In the code above:
- Line 12
- By putting
method="post"we made it possible to send the information with the POST method. - By putting
enctype="multipart/form-data"we made it possible to send a file.
- By putting
- Line 16: by putting
name="title"we send the title of the news to the backend with the key name. - Line 20: by putting
name="description"we send the description of the news to the backend with the key description. - Line 24
- By putting
type="file"we made a file upload field. - By putting
name="image"we send the file to the backend with the key image. - By putting
accept="image/*"we let the user choose only images.
- By putting
- Line 28
- By putting
type="date"we turned on the date picker widget (a HTML5 feature) for this field. - By putting name=”publish_date”, we send the date to the backend with the key publish_date.
- By putting
- Line 32: in this part we used select to make a menu for choosing the news category, and we made the items of this menu with option.
- By putting
name="category"we send the chosen value to the backend with the key category. - The value of the option that is chosen when the form is submitted goes to the backend with the key category.
- By putting
- Line 42: by putting
type="checkbox"we made an input of the checkbox type. If it is ticked, it sends the value on to the backend. - Line 47: we put a hidden field for sending the security token to the backend.
- Line 49: By putting
type="submit"we made a button for submitting the form and sending the information to the backend.
Task four – building the edit news form
Task four description
Add the edit feature to the form that you built before for adding news. For this, use the information below, which the backend gives you on this page.
| Variable | Type | Description |
|---|---|---|
article | A NewsArticle object or None | In edit mode it holds the news information; in the other case it is None. |
categories | A list of tuples (key, label) | The category options; for example: [(‘cultural’,’cultural’), (‘political’,’political’), …] |
Doing task four
Open the add-edit-news.html page and put the code below in it.
<h2>📝 {% if article.title %}{{ article.title }}{% else %}Add New Article{% endif %}</h2>
<form method="post" enctype="multipart/form-data">
<div class="form-grid">
<div class="form-group full-width">
<label for="title">Title *</label>
<input type="text" id="title" name="title" placeholder="Enter news title" required value="{{ article.title }}">
</div>
<div class="form-group full-width">
<label for="desc">Description *</label>
<textarea id="desc" name="description" placeholder="Full article text..." required>{{ article.description }}</textarea>
</div>
<div class="form-group full-width">
<label for="img">Image</label>
<input type="file" id="img" name="image" accept="image/*">
</div>
<div class="form-group">
<label for="date">Publish Date *</label>
<input type="date" id="date" name="publish_date" required value="{{ article.publish_date|date:'Y-m-d' }}">
</div>
<div class="form-group">
<label for="category">Category *</label>
<select id="category" name="category" required>
<option value="">-- Select --</option>
<option value="cultural" {% if article.category == "cultural" %}selected{% endif %}>Cultural</option>
<option value="political" {% if article.category == "political" %}selected{% endif %}>Political</option>
<option value="sports" {% if article.category == "sports" %}selected{% endif %}>Sports</option>
<option value="scientific" {% if article.category == "scientific" %}selected{% endif %}>Scientific</option>
</select>
</div>
<div class="form-group full-width">
<label class="checkbox-wrap">
<input type="checkbox" id="draft" name="saveAsDraft" {% if article.is_draft %}checked{% endif %}>
Save as Draft
</label>
</div>
</div>
{% csrf_token %}
<div class="form-actions">
<button type="submit" class="btn btn-primary">💾 Save Article</button>
<a href="/" class="btn btn-outline">Cancel</a>
</div>
</form>In the code above:
- Line 11: in this part we added a condition, so the correct title of this part is shown. In add mode the user sees the words Add New Article, and in edit mode he sees the title of the news.
- Line 16: with
value="{{ article.title }}"we set the first value of this field. - Line 20: by putting
{{ article.description }}between the textarea we set the first value of this field. - Line 28: in this part, by putting
value="{{ article.publish_date|date:'Y-m-d' }}"we give the date of the news to the browser with the format YYYY-MM-DD and we set the first value of this field. - Lines 34 to 37: in this part we put the value selected on the category that was chosen before.
- Line 42: in this part, if this field was ticked before, the value checked is set for it.
In this part we did not put a default value for the File Upload Field, because for security reasons the browser does not allow this.
To stay away from complex things that take us far from the goal of this course, we do not build the image editing feature in this form.
The problems of this method
Building the front-end with the old Django templates is really not an interesting job for a front-end developer. He must learn a big part of Django, and this gives him no work or technical benefit, so it is normal that he does not like it. The most important thing is that this way takes away the modern and advanced tools from him (like components, state management, Hot Reload and optimizing bundlers) and makes the development harder for him.
For a backend developer this way is also not logical. No backend developer wants to work this much with HTML, CSS and the details of the user interface. Instead of fighting with the view layer, they prefer to design a clean and standard API and leave the rest to the special front-end frameworks.
In the next part we will see how we can finish this project without touching the Django template layer, only with html/css/js. This way is much more interesting for a front-end developer than the way that we used in this part.