Tutorial 2: Form and Data Delivery
Platform-Based Programming (CSGE602022) — Organized by the Faculty of Computer Science Universitas Indonesia, Odd Semester 2025/2026
Last Updated: 28 August 2025, 01:48 PM
Learning Objectives
After completing this tutorial, students are expected to be able to:
- Understand the purpose and how to implement the skeleton of a view
- Understand
XML
andJSON
as one of the data delivery methods - Understand how is data provided by the user submitted using the
form
element inHTML
- Understand how to send data using the
XML
andJSON
format. - Understand how to retrieve data based on a specific
ID
- Understand the use of Postman as a data viewer
Introduction to Data Delivery
In the development of a platform, sometimes we need to send data from one stack to another. Data that is sent can be of many different types. Some commonly used data formats between different applications are HTML, XML, and JSON. The implementation of data delivery in the form of HTML has already been covered in the previous tutorial. In this tutorial, we will cover data delivery in the form of XML and JSON.
XML (Extensible Markup Language)
XML, or eXtensible Markup Language, is a format that is designed to be easy to understand because each element describes itself. An XML file only contains data packaged in a specific tag, and to send, receive, store, or display information from the file, we need to create a program that can process it.
XML Format Example:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<name>Haru Urara</name>
<age>29</age>
<address>
<street>Jl. PeBePe No.1</street>
<city>Depok</city>
<province>Jawa Barat</province>
<zip>16424</zip>
</address>
</person>
The XML above is highly self-descriptive:
- It contains the name (
name
) - It contains the age (
age
) - It contains the address (
address
)- It contains the street (
street
) - It contains the city (
city
) - It contains the zip code (
zip
)
- It contains the street (
An XML document forms a tree-like structure - starting from the root, branching and then ending at the leaves. An XML document must contain a root element that acts as parent of other elements. In the example above, <person>
is the root element.
The line <?xml version="1.0" encoding="UTF-8"?>
, usually called the XML Prolog, is optional, but if present, it must appear at the beginning of the XML document. In an XML document, all elements must have a closing tag. XML tags are case-sensitive, so the tag <person>
is considered different from <Person>
.
JSON (JavaScript Object Notation)
JSON, or JavaScript Object Notation, is a format that is designed to be easy to understand, as each element describes itself. JSON is commonly used in various web and mobile applications for the storage and transmission of data. While the syntax used in JSON is based on JavaScript objects, JSON itself is a text format. For this reason, many programming languages provide support for reading and creating JSON.
Example of JSON format:
{
"name": "Haru Urara",
"age": 25,
"address": {
"street": "Jl. Ganesa No.10",
"city": "Bandung",
"province": "Jawa Barat",
"zip": "40132"
}
}
Data in JSON is stored in the form of key and value. In the example above, the key is name
, age
, and address
. The value can be of primtive data type (string, number, boolean) or an object.
Pre-Tutorial Notes
Before you start, and to ensure that you follow this tutorial correctly, we expect these results from tutorial 1:
- Local directory structure
football-news
should look like this.
- Repository structure
football-news
on GitHub should look like this.
Tutorial: Implementing Skeleton as a Structure for Views
Before creating form, we need to create a skeleton that acts as a structure for the views of our website. With this structure, we can ensure consistency in the design of our website and reduce the possible of code redundancy. In this tutorial, we will create a skeleton for the website that we will build in the next tutorial.
-
Create a directory
templates
under the main directory (root folder) and create a new HTML file namedbase.html
. Thebase.html
file acts as a base template that can be used as a generic view for other web pages within the project. Add the following code to thebase.html
file:{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{% block meta %} {% endblock meta %}
</head>
<body>
{% block content %} {% endblock content %}
</body>
</html>The lines enclosed in
{% ... %}
are called template tags in Django. The lines in this example will function to dynamically load data from Django into the HTML.In the example above, the
{% block %}
tag in Django is used to define an area that can be overriden by child templates. The child template will extend the base template (in this casebase.html
) and override the content in the block as needed. -
Open the
settings.py
file that is in the project directory (football-news
) and find the line that contains theTEMPLATES
variable. Update the code to match the snippet below so that thebase.html
is recognized as a template file.
...
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'], # Tambahkan konten baris ini
'APP_DIRS': True,
...
}
]
...
In some cases, the value ofAPP_DIRS
on your TEMPLATES
configuration might be set to False
. If it is, set it to True
. The value of APP_DIRS
must be True
to ensure that your app templates
(such as main
) will be prioritized over django.contrib.admin's admin/base_site.html
. For more details, see this documentation.
-
In the
templates
subdirectory of themain
directory, modify themain.html
file you created in the previous tutorial as follows.{% extends 'base.html' %}
{% block content %}
<h1>Football News</h1>
<h5>NPM: </h5>
<p>{{ npm }}<p>
<h5>Name:</h5>
<p>{{ name }}</p>
<h5>Class:</h5>
<p>{{ class }}</p>
{% endblock content %}Note that the code above is the same as the
main.html
code from the previous tutorial, except that here we usebase.html
as the main template.
Tutorial: Creating Data Input Form and Displaying Football News Data on HTML
Up to this point, no data has ever been added and displayed in the application. Next, we will create a simple form to input Football News data, which will let us add new entries that will appear on the main page.
-
Create a new file in the
main
directory namedforms.py
to define the form structure that will receive new News data. Add the following code to the file.from django.forms import ModelForm
from main.models import News
class NewsForm(ModelForm):
class Meta:
model = News
fields = ["title", "content", "category", "thumbnail", "is_featured"]Code Explanation:
model = News
specifies the model that will be used for the form. When data from the form is saved, the form's input will be saved as an object ofNews
.fields = ["title", "content", "category", "thumbnail", "is_featured"]
specifies the fields of theNews
model that will be used in the form. Thedate_added
field is not included in the list because it is set automatically.
-
Open the views.py file in the main directory, add the following imports at the top, and then update and add the functions below.
from django.shortcuts import render, redirect, get_object_or_404
from main.forms import NewsForm
from main.models import News
def show_main(request):
news_list = News.objects.all()
context = {
'npm' : '240123456',
'name': 'Haru Urara',
'class': 'PBP A',
'news_list': news_list
}
return render(request, "main.html", context)
def create_news(request):
form = NewsForm(request.POST or None)
if form.is_valid() and request.method == "POST":
form.save()
return redirect('main:show_main')
context = {'form': form}
return render(request, "create_news.html", context)
def show_news(request, id):
news = get_object_or_404(News, pk=id)
news.increment_views()
context = {
'news': news
}
return render(request, "news_detail.html", context)Code Explanation:
- The
show_main
function is modified by addingNews.objects.all()
to fetch allNews
objects that are stored in the database. - The
create_news
function is used to generate a form that can automataically addNews
data when submitted. - The
show_news
function usesget_object_or_404(News, pk=id)
to fetch aNews
object based on its primary key (id). If no such object is found, a 404 page is returned. news.increment_views()
is used to increase the view count of the news item.
- The
-
Open the
urls.py
file in themain
directory, import the functions you created earlier, and add the URL path to theurlpatterns
variable..from main.views import show_main, create_news, show_news
app_name = 'main'
urlpatterns = [
path('', show_main, name='show_main')
path('create-news/', create_news, name='create_news'),
path('news/<str:id>/', show_news, name='show_news'),
] -
Open
main.html
and update the code inside thecontent
block to display the news data, along with an "Add News" button that redirects to the form page.<h1>Football News</h1>
<h5>NPM: </h5>
<p>{{ npm }}</p>
<h5>Name:</h5>
<p>{{ name }}</p>
<h5>Class:</h5>
<p>{{ class }}</p>
<a href="{% url 'main:create_news' %}">
<button>+ Add News</button>
</a>
<hr>
{% if not news_list %}
<p>No news data available in Football News.</p>
{% else %}
{% for news in news_list %}
<div>
<h2><a href="{% url 'main:show_news' news.id %}">{{ news.title }}</a></h2>
<p><b>{{ news.get_category_display }}</b>{% if news.is_featured %} |
<b>Featured</b>{% endif %}{% if news.is_news_hot %} |
<b>Hot</b>{% endif %} | <i>{{ news.created_at|date:"d M Y H:i" }}</i>
| Views: {{ news.news_views }}</p>
{% if news.thumbnail %}
<img src="{{ news.thumbnail }}" alt="thumbnail" width="150" height="100">
<br />
{% endif %}
<p>{{ news.content|truncatewords:25 }}...</p>
<p><a href="{% url 'main:show_news' news.id %}"><button>Read More</button></a></p>
</div>
<hr>
{% endfor %}
{% endif %} -
Create two new HTML files under the
main/templates
directory to create an input form and news details page.create_news.html:
{% extends `base.html` %}
{% block content %}
<h1>Add News</h1>
<form method="POST">
{% csrf_token %}
<table>
{{ form.as_table }}
<tr>
<td></td>
<td>
<input type="submit" value="Add NEWS" />
</td>
</tr>
</table>
</form>
{% endblock %}Code Explanation:
{% csrf_token %}
is a security token and is automatically generated by Django to prevent attacks.{{ form.as_table }}
is a template tag used to render form fields defined in theforms.py
file as an HTML table.<input type="submit" value="Add NEWS"/>
is used as a submit button to send the request to thecreate_news(request)
news_detail.html
{% extends 'base.html' %}
{% block content %}
<p><a href="{% url 'main:show_main' %}"><button>← Back to News List</button></a></p>
<h1>{{ news.title }}</h1>
<p><b>{{ news.get_category_display }}</b>{% if news.is_featured %} |
<b>Featured</b>{% endif %}{% if news.is_news_hot %} |
<b>Hot</b>{% endif %} | <i>{{ news.created_at|date:"d M Y, H:i" }}</i>
| Views: {{ news.news_views }}</p>
{% if news.thumbnail %}
<img src="{{ news.thumbnail }}" alt="News thumbnail" width="300">
<br /><br />
{% endif %}
<p>{{ news.content }}</p>
{% endblock content %} -
Open
settings.py
in the root project directory and add your PWS project URL entry toCSRF_TRUSTED_ORIGINS
right afterALLOWED_HOSTS
:...
CSRF_TRUSTED_ORIGINS = [
"<your-pws-deployment-url>"
]
...Remember that the deployment URL for CSRF_TRUSTED_ORIGINS must include the protocol, so the URL should start with
https://
, for examplehttps://isa-citra-footballnews.pbp.cs.ui.ac.id
. -
Run your Django project with the
python manage.py runserver
commmand and go to http://localhost:8000/ in your preferred browser. Try adding new news entries and clicking the title links or "Read More" buttons to view news details. You should be able to see the added data on the main page of the application and access the detail page for each news item.
Tutorial: Returning Data in XML Format
-
Open the
views.py
file in themain
directory and add theHttpResponse
andSerializer
imports at the beginning of the file.from django.http import HttpResponse
from django.core import serializersinfoHttpResponse
is a class used to construct the response returned by the server to the user. For more details aboutHttpRequest
andHttpResponse
, see the official documentation. -
Create a new function called
show_xml
that takes arequest
as a parameter, and define a variable inside the function to store the query result of all data inNews
.def show_xml(request):
news_list = News.objects.all() -
Add a return statement using
HttpResponse
that contains the query results serialized as XML, along with the parametercontent_type="application/xml"
.def show_xml(request):
news_list = News.objects.all()
xml_data = serializers.serialize("xml", news_list)
return HttpResponse(xml_data, content_type="application/xml")Code Explanation:
serializers
are used to convert model objects into other formats - in this case, XML. -
Open the
urls.py
file in themain
directory and import the function that you just created.from main.views import show_main, create_news, show_xml
-
Add a URL path to
urlpatterns
to access the function imported earlier....
path('xml/', show_xml, name='show_xml'),
... -
Run the Django project by running
python manage.py runserver
and visit http://localhost:8000/xml/ in your preferred browser.
Tutorial: Returning Data in JSON Format
-
Open the
views.py
file in themain
directory and create a new function calledshow_json
that takes arequest
as parameter, and define a variable inside the function to store the query result of all data inNews
.def show_json(request):
news_list = News.objects.all() -
Add a return statement using
HttpResponse
that contains the query results serialized as JSON, along with the parametercontent_type="application/JSON"
.def show_json(request):
news_list = News.objects.all()
json_data = serializers.serialize("json", news_list)
return HttpResponse(json_data, content_type="application/json") -
Open the
urls.py
file in themain
directory and import the function that you just created.from main.views import show_main, create_news, show_xml, show_json
-
Add a URL path to
urlpatterns
to access the function imported earlier....
path('json/', show_json, name='show_json'),
... -
Run the Django project by running
python manage.py runserver
and visit http://localhost:8000/xml/ in your preferred browser.
Tutorial: Returning Data Based on an ID in XML and JSON Format
-
Open the
views.py
file in themain
directory and create two new functions, show_xml_by_id and show_json_by_id, each taking arequest
andnews_id
as parameters. -
Define a variable inside the function to store the query result of the
News
object with the specified ID.data = News.objects.filter(pk=news_id)
-
Add a return statement using
HttpResponse
that contains the query results serialized as XML or JSON, along with thecontent_type
parameter set to"application/xml"
(for XML) or"application/json"
(for JSON).-
XML
def show_xml_by_id(request, news_id):
data = News.objects.filter(pk=news_id)
return HttpResponse(serializers.seralize("xml", data), content_type="application/xml") -
JSON
def show_json_by_id(request, news_id):
data = News.objects.filter(pk=news_id)
return HttpResponse(serializers.serialize("json", data), content_type="application/json")infoTo retrieve data by ID, Django provides several methods, with two of which are
filter()
andget()
. These two methods differ significantly:filter
can be used to retrieve one or more objects that meet the specified condition, whileget()
is used to retrieve exactly one object. For more details, see the official documentation.
-
-
Add a
try-except
block inside the function to handle the case where no data is found for the specifiednews_id
. If the data does not exist, return anHttpResponse
with 404 status code to indicate that the data was not found.- XML
def show_xml_by_id(request, news_id):
try:
news_item = News.objects.filter(pk=news_id)
xml_data = serializers.serialize("xml", news_item)
return HttpResponse(xml_data, content_type="application/xml")
except News.DoesNotExist:
return HttpResponse(status=404)- JSON
def show_json_by_id(request, news_id):
try:
news_item = News.objects.get(pk=news_id)
json_data = serializers.serialize("json", [news_item])
return HttpResponse(json_data, content_type="application/json")
except News.DoesNotExist:
return HttpResponse(status=404) -
Open the
urls.py
file in the main directory and import the functions that you just created.from main.views import show_main, create_news, show_xml, show_json, show_xml_by_id, show_json_by_id
-
Add a URL path to
urlpatterns
to access the function imported earlier....
path('xml/<str:id>/', show_xml_by_id, name='show_xml_by_id'),
path('json/<str:id>/', show_json_by_id, name='show_json_by_id'),
... -
Run the Django project by running
python manage.py runserver
and visit http://localhost:8000/xml/[id] or http://localhost:8000/json/[id]/ in your preferred browserwarningAdjust the
[id]
aboved with the ID of the object thata you want to see. You can take an ID of an object that is displayed when accessing the/xml/
and/json/
endpoints.
Tutorial: Using Postman as a Data Viewer
-
Ensure that the server is running with the
python manage.py runserver
command. -
Open Postman and create a new request with the method
GET
and URL http://localhost:8000/xml/ or http://localhost:8000/json/ to test whether the data is sent correctly.Postman Installation Guide can be found on the Postman official website
Example:
-
XML
-
JSON
-
-
Click the
Send
button to send the request. -
You will see the response result from the request at the bottom of Postman.
-
XML
-
JSON
-
-
You can also change the URL to http://localhost:8000/xml/[news_id] or http://localhost:8000/json/[news_id] to test retrieving News data by ID.
-
XML
-
JSON
-
Conclusion
-
After completing this tutorial, your web page should look like this.
-
At the end of this tutorial, the local directory should look like this.
-
Before performing this step, make sure that the local directory structure is correct. Then run
git add
,git commit
, andgit push
to update the GitHub repository. -
Run the following command to perform
add
,commit
, andpush
to GitHub and PWS.git add .
git commit -m "<commit_message>"
git push -u origin master
git push -u pws master- Change
<commit_message>
according to your needs. Example:git commit -m "finished tutorial 2"
.
- Change
Additional Reference
- Installing and updating Postman
- Retrieving a single object with get()
- Request and Response objects
- Django Request and Response cycle
Contributors
- Fiona Ratu Maheswari (FIO)
- Anthony Edbert Feriyanto (ANT)
- Meutia Fajriyah (MEW)
- Yeshua Marco Gracia (ACO)
- Alexander William Lim (LEG) (EN Translation)
Credits
This tutorial was developed based on PBP Odd 2025 and PBP Odd 2024 written by the 2025 Platform-Based Programming Teaching Team. All tutorials and instructions included in this repository are designed so that students who are taking Platform-Based Programming courses can complete the tutorials during lab sessions.