1. Jelaskan bagaimana cara kamu mengimplementasikan checklist di atas secara step-by-step (bukan hanya sekadar mengikuti tutorial).
-
Membuat sebuah proyek Django baru.
- Membuat directory baru bernama
arto_moro_pbp
yang akan dijadikan local directory/repository dari github repository - Membuka CMD pada directory
arto_moro_pbp
dan menjalankangit init
,git config user.name <user_name>
, dangit config user.email <user_email
untuk konfigurasi github - Membuat reporitory github baru bernama
arto-moro-pbp
- Membuat file
README.md
dan mengeditnya melalui VSCODE - Menjalankan
git branch -M main
,git remote add origin https://github.com/rakbidb/arto-moro-pbp.git
, dangit push -u origin main
untuk membuat main branch dengan namamain
, menghubungkan local directory/repository dengan repository github, dan push/update semua perubahan ke github - Menjalankan
python -m venv env
untuk membuat virtual environment untuk directory agar dapat maintain versi-versi django dan lain sebagainya yang dipakai di device - Menjalankan
env\Scripts\activate.bat
untuk mengaktifkan virtual environment - Membuat file baru bernama
requirements.txt
dan mengisinya dengan hal-hal yang ingin diinstall agar tidak terlalu banyak menjalankan commandpip install ...
, saya mengisinya dengan:
django gunicorn whitenoise psycopg2-binary requests urllib3
- Menjalankan
pip install -r requirements.txt
untuk install hal-hal yang telah ditambahkan padarequirements.txt
tadi - Menjalankan
django-admin startproject arto_moro_pbp .
- Membuka file
settings.py
dan ubahALLOWED_HOSTS = []
menjadiALLOWED_HOSTS = ["*"]
karena akan diperlukan untuk proses deployment - Membuat file baru bernama
.gitignore
untuk memberikan informasi mengenai berkas yang perubahannya tidak perlu ditrack oleh Git, saya mengisinya dengan:
# Django *.log *.pot *.pyc __pycache__ db.sqlite3 media # Backup files *.bak # If you are using PyCharm # User-specific stuff .idea/**/workspace.xml .idea/**/tasks.xml .idea/**/usage.statistics.xml .idea/**/dictionaries .idea/**/shelf # AWS User-specific .idea/**/aws.xml # Generated files .idea/**/contentModel.xml # Sensitive or high-churn files .idea/**/dataSources/ .idea/**/dataSources.ids .idea/**/dataSources.local.xml .idea/**/sqlDataSources.xml .idea/**/dynamic.xml .idea/**/uiDesigner.xml .idea/**/dbnavigator.xml # Gradle .idea/**/gradle.xml .idea/**/libraries # File-based project format *.iws # IntelliJ out/ # JIRA plugin atlassian-ide-plugin.xml # Python *.py[cod] *$py.class # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache .pytest_cache/ nosetests.xml coverage.xml *.cover .hypothesis/ # Jupyter Notebook .ipynb_checkpoints # pyenv .python-version # celery celerybeat-schedule.* # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # mkdocs documentation /site # mypy .mypy_cache/ # Sublime Text *.tmlanguage.cache *.tmPreferences.cache *.stTheme.cache *.sublime-workspace *.sublime-project # sftp configuration file sftp-config.json # Package control specific files Package Control.last-run Control.ca-list Control.ca-bundle Control.system-ca-bundle GitHub.sublime-settings # Visual Studio Code .vscode/* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json .history
- Membuat directory baru bernama
-
Membuat aplikasi dengan nama
main
pada proyek tersebut.- Masih pada CMD yang sama, jalankan
python manage.py startapp main
untuk membuat django app baru bernamamain
pada django project bernamaarto_moro_pbp
- Membuka file
settings.py
dan tambahkan'main'
pada variabelINSTALLED_APPS
- Membuka directory
main
dan buat directory baru bernamatemplates
untuk menyimpan file.html
yang akan digunakan karena django menggunakan Model-View-Template (MVT) - Membuat file baru bernama
main.html
pada directorytemplates
dan mengisinya dengan konten-konten yang diperlukan. Untuk Tugas 2, yang wajib muncul adalah nama aplikasi, nama, dan kelas.
- Masih pada CMD yang sama, jalankan
-
Melakukan routing pada proyek agar dapat menjalankan aplikasi
main
.- Membuka file
urls.py
pada directoryarto_moro_pbp
- Menambahkan
from django.urls import path, include
- Mengubah
urlpatterns
menjadi:
urlpatterns = [ path('admin/', admin.site.urls), path('main/', include('main.urls')), ]
Note:
path('main/', include('main.urls')),
digunakan untuk menambahkan routing dariurls.py
pada directorymain
dan url yang ada padaurls.py
dimain
akan menjadi.../main/...
- Membuka file
-
Membuat model pada aplikasi
main
dengan namaItem
dan memiliki atribut wajib sebagai berikut.name
sebagai nama item dengan tipeCharField
.amount
sebagai jumlah item dengan tipeIntegerField
.description
sebagai deskripsi item dengan tipeTextField
. Namun, saya juga menambahkan beberapa atribut sehingga atribut yang saya miliki sebagai berikut.name
sebagai nama item dengan tipeCharField
.date_added
sebagai waktu tanggal dibuatnya item dengan tipeDateField
.price
sebagai harga item dengan tipeIntegerField
.description
sebagai deskripsi item dengan tipeTextField
.amount
sebagai jumlah item dengan tipeIntegerField
.category
sebagai kategori item dengan tipeTextField
.
- Membuka
models.py
dan mengisinya dengan attributes/fields yang diperlukan. Pada kasus ini, saya menggunakan 6 attributes, yakniname
(CharField),date_added
(DateField),price
(IntegerField),description
(TextField),amount
(IntegerField), dancategory
(TextField). Isi filemodels.py
adalah sebagai berikut:
from django.db import models class Product(models.Model): name = models.CharField(max_length=255) date_added = models.DateField(auto_now_add=True) price = models.IntegerField() description = models.TextField() amount = models.IntegerField() category = models.TextField()
-
Membuat sebuah fungsi pada
views.py
untuk dikembalikan ke dalam sebuah template HTML yang menampilkan nama aplikasi serta nama dan kelas kamu.- Membuka
views.py
dan menambahkan potongan kode di bawah ini untuk menghubungkan Views dan Templates (e.g.: substitute{{ <desired_variable> }}
pada file-file di directorytemplates
). Saya memerlukan variablesname
,class
,app_name
. Jadi, isiviews.py
sebagai berikut:
from django.shortcuts import render from .models import Product def show_main(request): context = { 'name': 'Rakha Abid Bangsawan', 'class': 'PBP A', 'app_name': 'Arto Moro PBP', } return render(request, "main.html", context)
- Membuka
-
Membuat sebuah routing pada
urls.py
aplikasimain
untuk memetakan fungsi yang telah dibuat padaviews.py
.- ubah
urlpatterns
menjadi seperti ini:
app_name = 'main' urlpatterns = [ path('', show_main, name='show_main'), ]
- ubah
-
Melakukan deployment ke Adaptable terhadap aplikasi yang sudah dibuat sehingga nantinya dapat diakses oleh teman-temanmu melalui Internet.
- belum sempat di-deploy
2. Buatlah bagan yang berisi request client ke web aplikasi berbasis Django beserta responnya dan jelaskan pada bagan tersebut kaitan antara urls.py, views.py, models.py, dan berkas html
- Client mengirim request ke Internet -> forward ke Python/Django -> forward ke urls.py -> forward ke views.py untuk memproses url -> read/write data dari/ke models.py dan database -> input/display data dari/ke templates -> return html file yang telah dimerge dengan value-value yang diinginkan -> proses ke internet -> display ke client's device
3. Jelaskan mengapa kita menggunakan virtual environment? Apakah kita tetap dapat membuat aplikasi web berbasis Django tanpa menggunakan virtual environment?
Virtual Environment adalah suatu alat yang digunakan sebagai wadah untuk mengenkapsulasi serta menampung package atau library agar tetap terisolasi. Virtual Environment dibutuhkan dan berperan penting dalam pembuatan aplikasi web untuk mencegah adanya issues dependency yang dapat terjadi akibat adanya pembaruan perbedaan versi pada external library dari project yang satu dengan yang lainnya. Jika kita tidak menggunakan virtual environment, maka kita tidak dapat bekerja menggunakan dua library dengan versi yang berbeda. Akan tetapi, kita dapat membuat aplikasi web berbasis Django tanpa virtual environment ketika sedang mengerjakan project secara individu bukan secara tim karena jika mengerjakan secara tim tanpa environment akan sulit apabila masing-masing anggota memiliki versi modul yang berbeda-beda
- MVC (Model-View-Controller)
- Model: untuk mencari dan mengolah data yang diminta oleh Database
- View: menampilkan data dengan design yang dibuat di sini (kurang lebih seperti Template pada MVT dan View pada MVVM)
- Controller: mengatur bagaimana data akan ditampilkan di View (kurang lebih seperti View pada MVT)
- Input diterima oleh Controller
- Kurang cocok untuk aplikasi berskala kecil
- MVT/MTV (Model-View-Template)
- Model: untuk mencari dan mengolah data yang diminta oleh database
- View: mengatur bagaimana data akan ditampilkan di Template (kurang lebih seperti Controller pada MVC)
- Template: menampilkan data dengan design yang dibuat di sini (kurang lebih seperti View pada MVC dan MVVM)
- Input diterima oleh View
- Cocok digunakan baik untuk aplikasi berskala besar maupun kecil
- Mudah melakukan modifikasi
- MVVM (Model-View-ViewModel)
- Model: tempat untuk menyimpan informasi
- View: menampilkan data dengan design yang dibuat di sini (kurang lebih seperti View pada MVC dan Template pada MVVM)
- ViewModel: menghubungkan Model dan View
- Input diterima oleh View
- Kurang cocok untuk palikasi berskala kecil
- Memiliki kelebihan dalam proses binding data
- Tutorial 0 dan Tutorial 1
- Definition Model-View-ViewModel (MVVM)
- MVC Framework - Introduction
- Slide 3 SCeLE "MTV Django Architecture"
- Alasan Menggunakan Virtual Environment
- POST
- Digunakan untuk mengirimkan data ke server (membuat, mengganti, menghapus, etc.), return HTTP status code 201 jika berhasil
- Values tidak visible pada URL (data dikirimkan saat HTML request)
- Tidak memiliki limitasi panjang karakter
- Dapat menggunakan berbagai tipe data (contoh: string, integer)
- Lebih secured karena data tidak terekspos pada URL
- Dapat digunakan untuk mengirimkan data penting (contoh: password)
- Parameter tidak disimpan pada history browser
- Non-idempotent
- GET
- Digunakan untuk membaca/mengakses data dari web server, retrun HTTP status code 200 jika berhasil
- Values visible pada URL --> user dapat input nilai variabel baru dengan lebih mudah
- Panjang karakter terbatas (umumnya maksimal 255 karakter)
- Hanya dapat menggunakan tipe data string
- Kurang aman karena data terekspos pada URL
- Dapat digunakan untuk mengirimkan data yang tidak terlalu penting
- Parameter disimpan pada history browser
- Idempotent (request selanjutnya akan diabaikan hingga request yang sedang dijalankan selesai mengirimkan respon)
- HTML
- Menurut saya, kurang human-readable apabila merepresentasikan data menggunakan HTML (apabila dilihat melalui Postman)
- Secara umum, HTML digunakan untuk membuat struktur, layout, dan konten dari web page yang akan ditampilkan. Untuk data yang bersifat dinamis dapat memanfaatkan tools, seperti XML, JSON, dsb
- XML
- Menurut saya, human-readable karena strukturnya jelas untuk dibaca. Namun, proses delivery datanya memerlukan waktu lebih lama jika dibandingkan dengan JSON
- Secara umum, XML digunakan untuk menyimpan dan melakukan transfer/pertukaran data melalui internet, banyak digunakan pada web dan mobile app
- XML lebih secure jika dibandingkan dengan JSON (JSON lebih vulnerable)
- Waktu eksekusi tidak secepat JSON
- Struktur data dapat terlihat dengan sangat jelas karena tag nya dapat di-custom (berbeda dengan HTML). Namun, waktu eksekusi program menjadi lebih lama karena banyak tag
- JSON
- Menurut saya, human-readable karena JSON menggunakan list dan dictionary python. Proses delivery dengan JSON jauh lebih cepat jika dibandingkan dengan menggunakan XML
- Secara umum, JSON digunakan untuk menyimpan dan melakukan transfer/pertukaran data antara server dan aplikasi web, banyak digunakan juga pada web dan mobile app
- JSON lebih compatible terhadap teknologi-teknologi web dan lebih mudah untuk di-maintain oleh web developers jika dibandingkan dengan XML
- Waktu eksekusi lebih cepat dibandingkan XML
- Tidak menggunakan tag sehingga lebih ringkas dan bisa merepresentasikan dengan ukuran file yang kecil
- Tingkat simplicity dan readability yang tinggi karena karena syntax dan indentasinya yang ringkas
- Memiliki banyak method yang dapat mempercepat proses penyusunan program (contoh: JSON.parse() untuk mengubah JSON string menjadi Object dengan atribut-atributnya)
- Dapat merepresentasikan data dengan ukuran file yang kecil karena syntaxnya ringkas (seperti tidak menggunakan tag, etc.)
- JDapat melakukan transfer/pertukaran data dengan sangat cepat (tidak perlu banyak parse karena syntaxnya juga singkat)
- Sangat compatible dengan berbagai teknologi web, seperti JavaScript dan lain-lain.
- Mendukung tipe data native, seperti numbers, booleans, null, etc.
4. Jelaskan bagaimana cara kamu mengimplementasikan checklist di atas secara step-by-step (bukan hanya sekadar mengikuti tutorial)!
- Membuat input
form
untuk menambahkan objek model pada app sebelumnya.- Membuat
base.html
pada root/templates dan mengisinya dengan:
Note:{% 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>
{% something %}
dapat diisi dari file lain (seperti semacam placeholder)
- Membuat
forms.py
padaarto_moro_pbp/main
dan mengisinya dengan:
Notes:from django.forms import ModelForm from main.models import Product class ProductForm(ModelForm): class Meta: model = Product fields = ["name", "price", "description", "amount", "category"]
model = Product
menandakan bahwa isian form akan disimpan sebagai object Productfields
menandakan bahwa object Product memiliki 5 atribut yang dapat diisi melalui form (name, price, description, amount, category)
- Ubah function
show_main
padaarto_moro_pbp/main/views.py
menjadi sebagai berikut:
Notes:def show_main(request): products = Product.objects.all() context = { 'name': 'Rakha Abid Bangsawan', # Nama kamu 'class': 'PBP A', # Kelas PBP kamu 'app_name': 'Arto Moro PBP', 'products': products, 'total_products': products.__len__(), } return render(request, "main.html", context)
'products
akan menyimpan seluruh product yang ada pada project saat initotal_products
akan menyimpan banyak product yang ada pada project saat ini
- Buat
create_product.html
padaarto_moro_pbp/main/templates/
dan isi sebagai berikut:
Notes:{% extends 'base.html' %} {% block content %} <h1>Add New Product</h1> <form method="POST"> {% csrf_token %} <table> {{ form.as_table }} <tr> <td></td> <td> <input type="submit" value="Add Product"/> </td> </tr> </table> </form> {% endblock %}
{% block content %} ... {% endblock %}
adalah konten yang akan mengisi placeholder block content padabase.html
.<form method="POST>
karena user akan memberikan beberapa input.
- Membuat
- Tambahkan 5 fungsi
views
untuk melihat objek yang sudah ditambahkan dalam format HTML, XML, JSON, XML by ID, dan JSON by ID.create_product
untuk menerima input user, dapat diakses ketika user klik button "Add New Product" atau ketika user mengakses(url)/create-product
def create_product(request): form = ProductForm(request.POST or None) if form.is_valid() and request.method == "POST": form.save() return HttpResponseRedirect(reverse('main:show_main')) context = {'form': form} return render(request, "create_product.html", context)
show_xml
untuk menampilkan representasi seluruh products dalam format XML, dapat diakses pada(url)/xml
def show_xml(request): data = Product.objects.all() return HttpResponse(serializers.serialize("xml", data), content_type="application/xml")
show_json
untuk menampilkan representasi seluruh products dalam format JSON, dapat diakses pada(url)/json
def show_json(request): data = Product.objects.all() return HttpResponse(serializers.serialize("json", data), content_type="application/json")
show_xml_by_id
untuk menampilkan representasi product dengan id yang diinginkan dalam format XML, dapat diakses pada(url)/xml/(desired_id)
def show_xml_by_id(request, id): data = Product.objects.filter(pk=id) return HttpResponse(serializers.serialize("xml", data), content_type="application/xml")
show_json_by_id
untuk menampilkan representasi product dengan id yang diinginkan dalam format JSON, dapat diakses pada(url)/json/(desired_id)
def show_json_by_id(request, id): data = Product.objects.filter(pk=id) return HttpResponse(serializers.serialize("json", data), content_type="application/json")
- Membuat routing URL untuk masing-masing
views
yang telah ditambahkan pada poin 2.- Isi
arto_moro_pbp/main/urls.py
dengan:
from django.urls import path from main.views import show_main, create_product, show_xml, show_json, show_xml_by_id, show_json_by_id # , show_products app_name = 'main' urlpatterns = [ path('', show_main, name='show_main'), path('create-product', create_product, name='create_product'), path('xml/', show_xml, name='show_xml'), path('json/', show_json, name='show_json'), path('xml/<int:id>/', show_xml_by_id, name='show_xml_by_id'), path('json/<int:id>/', show_json_by_id, name='show_json_by_id'), ]
urlpatterns
digunakan agar function-function yang telah dicantumkan padaviews.py
dapat diakses dengan url yang diinginkan, untuk project ini detailnya sebagai berikut:(url)/create-product
: Untuk user input product baru(url)/xml
: Untuk menampilkan representasi seluruh products dalam format XML(url)/json
: Untuk menampilkan representasi seluruh products dalam format JSON(url)/xml/(desired_id)
: Untuk menampilkan representasi product dengan id yang diinginkan dalam format XML(url)/xml/(desired_id)
: Untuk menampilkan representasi product dengan id yang diinginkan dalam format JSON
- Isi
- Tambahkan
'total_products': products.__len__(),
padaarto_moro_pbp/main/views.py
untuk menyimpan bannyaknya jumlah product saat ini. - Tambahkan
<h3>Kamu menyimpan {{total_products}} product pada aplikasi Arto Moro PBP!</h3>
padaarto_moro_pbp/main/templates/main.html
karena banyaknya product saat ini disimpan padatotal_products
.
5. Mengakses kelima URL di poin 2 menggunakan Postman, membuat screenshot dari hasil akses URL pada Postman, dan menambahkannya ke dalam README.md
- HTML:
(url)/create-product
: Untuk user input product baru - XML:
(url)/xml
: Untuk menampilkan representasi seluruh products dalam format XML - JSON:
(url)/json
: Untuk menampilkan representasi seluruh products dalam format JSON - XML by ID:
(url)/xml/(desired_id)
: Untuk menampilkan representasi product dengan id yang diinginkan dalam format XML - JSON by ID:
(url)/json/(desired_id)
: Untuk menampilkan representasi product dengan id yang diinginkan dalam format JSON
- Tutorial 2
- Get vs Post
- Handling an HTML Form – GET and POST Methods, and Data Encoding [Dev Concepts #38]
- Slide 4 - SCeLE "Data Delivery"
- What’s the Relationship Between XML, JSON, HTML and the Internet?
- What are the advantages and disadvantages of using JSON vs XML?
UserCreationForm
merupakan form yang disediakan oleh Django dan dapat digunakan untuk membuat (register) user baru dan user tersebut kemudian dapat login.- By default, terdiri atas 3 fields, yaitu
username
,passowrd1
, danpassword2
. - Kelebihan:
- Telah disediakan/diimplementasikan oleh Django sehingga kita dapat langsung menggunakannya (tidak perlu membuat from scratch), baik cukup dengan default yang disediakan maupun ingin menambahkan fields custom lain
- By default, telah memvalidasi input dari user, e.g.
password must be at least 8 characters
,password can't be entirely numeric
, dll. sehingga kita tidak perlu mengimplementasikan secara manual.
- Kekurangan:
- Kurang customizable jika perlu menambahkan kustomisasi (e.g. menambahkan fields baru) perlu mengedit beberapa file dan mengimplementasikannya secara manual.
- Untuk fitur seperti login, logout, dll., tetap ada beberapa hal yang harus diimplementasikan secara manual (tidak disediakan oleh Django UserCreationForm).
- Ketentuan passwordnya agak strict sehingga agak merepotkan pengguna.
2. Apa perbedaan antara autentikasi dan otorisasi dalam konteks Django, dan mengapa keduanya penting?
- Autentikasi
- Autentikasi merupakan mekanisme verifikasi terkait siapakah yang ingin mengakses web page, apakah user tersebut terdaftar pada sistem?
- Autentikasi penting karena semacam langkah awal dari user untuk dapat mengakses web page yang menerapkan authorization. Apabila user tidak terdaftar pada sistem, user tidak akan dapat mengakses web page tersebut. Hal ini penting untuk segi keamanan web. Selain itu, juga penting untuk memastikan hanya user yang terdaftar yang dapat mengakses.
- Contoh: Login page pada SCELE, user akan diminta input berupa username dan password yang kemudian akan diperiksa apakah benar ada user dengan username dan password tersebut, jika iya maka user tersebut dapat mengakses page SCELE, jika tidak maka akan diminta input ulang.
- Otorisasi
- Otorisasi merupakan mekanisme verifikasi apakah user yang telah terautentikasi dapat mengakses suatu web, fitur, resources, dll.
- Otorisasi penting karena digunakan untuk mengelola dan membatasi apa saja hal-hal yang dapat dilakukan dan tidak dapat dilakukan oleh seorang user. Hal ini penting untuk pengelolaan pengguna juga agar tidak ada user yang dapat mengakses/mengubah suatu hal yang seharusnya hanya dapat diakses oleh beberapa user.
- Contoh: Pada Spotify terdapat regular user dan premium user, user premium memiliki akses berbeda dengan user biasa (e.g. tidak ada ads, dapat play secara shuffle maupun berurut, etc.). Maka dari itu, kita dapat menggunakan otorisasi untuk membedakan terkait resources apa saja yang dapat diakses oleh regular user dan premium user.
- Contoh lain: Pada SCELE terdapat beberapa jenis role (e.g. Dosen, Mahasiswa, dll.) di mana role Dosen dapat memberikan dan melihat nilai banyak mahasiswa, sedangkan role Mahasiswa hanya dapat melihat nilai masing-masing (jika sudah dipublish).
3. Apa itu cookies dalam konteks aplikasi web, dan bagaimana Django menggunakan cookies untuk mengelola data sesi pengguna?
Cookies merupakan informasi/data kecil yang disimpan saat user berinteraksi dengan aplikasi web. Cookies sering digunakan untuk mengelola data sesi pengguna (dapat memanfaatkan holding state karena HTTP bersifat stateless), track preferensi user, mengumpulkan data analitis, hingga personalisasi konten untuk masing-masing pengguna. Cookies memiliki tanggal dan waktu kedaluwarsa dan akan dihapus secara otomatis ketika waktu kedaluwarsanya tiba.
Contoh implementasi cookie di Django:
response.set_cookie('last_login', str(datetime.datetime.now()))
dapat digunakan untuk menambahkan cookie dengan namalast_login
yang akan menyimpan kapan waktu user terakhir kali login.- Kemudian kita dapat menambahkan
'last_login': request.COOKIES['last_login'],
pada function diviews.py
untuk mengakses cookielast_login
yang telah dibuat dan disimpan tadi.
4. Apakah penggunaan cookies aman secara default dalam pengembangan web, atau apakah ada risiko potensial yang harus diwaspadai?
Sebenarnya cookies tidak berbahaya karena cookie hanyalah sebuah data dan bersifat pasif. Walaupun cookies bersifat pasif (hanya merupakan data dan tidak bisa mengakses data, membaca data, maupun mengganti data yang ada di sistem), penggunaan cookies dalam pengembangan web tetap memiliki sejumlah risiko potensial yang perlu diwaspadai. Perlu dicatat bahwa yang berbahaya bukan cookies, tetapi bagaimana cara cookies digunakan dalam konteks aplikasi web yang ternyata dapat disalahgunakan. Dalam penggunaan cookies, harus waspada terkait CSRF, XSS, Cookie theft, dan lain-lain. Oleh karena itu, sebaiknya tidak menyimpan data yang tergolong sensitif di cookies.
5. Jelaskan bagaimana cara kamu mengimplementasikan checklist di atas secara step-by-step (bukan hanya sekadar mengikuti tutorial).
-
Mengimplementasikan fungsi registrasi, login, dan logout untuk memungkinkan pengguna untuk mengakses aplikasi sebelumnya dengan lancar.
- Tambahkan kode berikut ke
main/views.py
def register(request): form = UserCreationForm() if request.method == "POST": form = UserCreationForm(request.POST) if form.is_valid(): form.save() messages.success(request, 'Your account has been successfully created!') return redirect('main:login') context = {'form':form} return render(request, 'register.html', context) def login_user(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') user = authenticate(request, username=username, password=password) if user is not None: login(request, user) response = HttpResponseRedirect(reverse("main:show_main")) response.set_cookie('last_login', str(datetime.datetime.now())) return response else: messages.info(request, 'Sorry, incorrect username or password. Please try again.') context = {} return render(request, 'login.html', context) def logout_user(request): logout(request) response = HttpResponseRedirect(reverse('main:login')) response.delete_cookie('last_login') return response
response.setcookie('last_login', str(datetime.datetime.now()))
digunakan untuk menyimpan waktu terakhir user yang bersangkutan login pada cookie.- Tambahkan
'last_login': request.COOKIES['last_login'],
pada context di views.py untuk mengakses cookie last_login. - Tambahkan
@login_required(login_url='/login')
di atas function show_main pada views.py untuk memastikan hanya logged in user yang dapat akses. - Tambahkan potongan kode berikut pada urls.py untuk handle routing:
path('register/', register, name='register'), path('login/', login_user, name='login'), path('logout/', logout_user, name='logout'),
- Membuat template yang akan digunakan untuk masing-masing routing dari views.py (klik untuk mengakses):
- Tambahkan kode berikut ke
-
Membuat dua akun pengguna dengan masing-masing tiga dummy data menggunakan model yang telah dibuat pada aplikasi sebelumnya untuk setiap akun di lokal.
- Buka
localhost:8000
dan register untuk 2 username dengan username yang berbeda dan password. - Login untuk ketiga user tersebut. Kemudian, membuat 3 product/item baru dengan klik tombol
Add New Product
dan isi seluruh detail product yang diinginkan. - Setelah selesai, cek apakah product yang ditambahkan sudah ada di tabel atau belum.
- Apabila sudah benar, seharusnya setiap user memiliki tabel dengan isi product yang berbeda-beda.
- Buka
-
Menghubungkan model Item dengan User.
- Tambahkan
user = models.ForeignKey(User, on_delete=models.CASCADE)
pada class Product dimodels.py
untuk initiate Many-to-One relationship (karena menggunakan ForeignKey) pada User dengan Product/Item. - Ubah views.py pada bagian:
def create_product(request): form = ProductForm(request.POST or None) if form.is_valid() and request.method == "POST": product = form.save(commit=False) product.user = request.user product.save() return HttpResponseRedirect(reverse('main:show_main'))
- Tambahkan
products = Product.objects.filter(user=request.user)
dan ubah context untuk key 'name'
def show_main(request): products = Product.objects.filter(user=request.user) context = { 'name': request.user.username, ... }
- Lakukan migration untuk menyimpan perubahan
- Tambahkan
-
Menampilkan detail informasi pengguna yang sedang logged in seperti username dan menerapkan cookies seperti last login pada halaman utama aplikasi.
- Untuk menampilkan username dan class user dapat menggunakan potongan kode berikut pada main.html:
<p>Name: {{name}}</p> <p>Class: {{class}}</p>
- Untuk menampilkan data last login user dapat memanfaatkan Cookies dengan menggunakan potongan kode berikut pada main.html:
<p>Sesi terakhir login: {{ last_login }}</p>
- Untuk mengimplementasikan cookiesnya sebagai berikut:
response.set_cookie('last_login', str(datetime.datetime.now()))
pada function login_user diviews.py
untuk set cookie kapan user login terakhir kali.response.delete_cookie('last_login')
pada function logout_user diviews.py
untuk menghapus cookie.'last_login': request.COOKIES['last_login'],
pada context function show_main diviews.py
.
- Menambahkan potongan kode berikut pada
main/templates/main.html
:... <a href="edit-amount/{{product.id}}/0"> <button type="button"> Tambah Product </button> </a> <a href="edit-amount/{{product.id}}/1"> <button type="button"> Kurang Product </button> </a> <a href="edit-amount/{{product.id}}/2"> <button type="button"> Delete Product </button> </a> ...
- Parameter yang saya gunakan adalah
0=increment
,1=decrement
, dan2=delete
- Parameter yang saya gunakan adalah
- Menambahkan potongan kode berikut ke
main/urls.py
untuk menyesuaikan href yang ada pada anchor tag dimain.html
urlpatterns = [ ... path('edit-amount/<int:id>/<int:amount_change>/', edit_amount, name='edit_amount'), ... ]
- Menambahkan function berikut ke
views.py
pada appmain
@login_required(login_url='login/') def edit_amount(request, id, amount_change): product = Product.objects.get(id=id) # "+1" Button clicked --> Increment amount by 1 if (amount_change == 0): product.amount = product.amount + 1 product.save() # "-1" Button clicked --> Decrement amount by 1 elif (amount_change == 1): if (product.amount > 0): product.amount = product.amount - 1 product.save() if (product.amount == 0): # jika produk sudah habis = delete product.delete() # "Delete Product" Button clicked --> Delete the product else: product.delete() return HttpResponseRedirect(reverse('main:show_main'))
- Jika
amount_change=0
increment,amount_change=1
decrement, danamount_change=2
delete
- Jika
- Tutorial 3
- Slide 5 "Form, Authentication, Session, and Cookie"
- Django Cookie
- Django UserCreationForm | Creating New User
- Element Selector
- Digunakan untuk select seluruh elemen HTML dengan suatu tag tertentu
- Mengurangi redundancy karena dengan styling satu kali, semua elemen HTML dengan suatu tag yang sama akan berubah stylingnya secara global (misal kita styling seluruh elemen dengan tag
<p>
dengan font Times New Roman) - Waktu yang tepat untuk menggunakannya adalah ketika kita ingin memastikan konsistensi suatu elemen serta menerapkan styling default untuk suatu tag tertentu (dapat dikatakan default karena masih dapat diubah dengan inline styling) contoh:
element { ... }
- ID Selector
- Digunakan untuk select suatu elemen HTML secara unik
- Sesuai dengan namanya (ID), hanya akan ada satu elemen dengan id tetrtentu pada suatu web page
- Waktu yang tepat untuk menggunakan ID selector adalah ketika kita ingin memastikan yang akan kita styling, akses, dan lain sebagainya adalah suatu elemen yang unik dan sangat spesifik. Contohnya kita dapat memberikan id untuk suatu tombol agar ketika tombol tersebut diklik, kita dapat langsung mengakses tombol tersebut berdasarkan id unik yang telah kita berikan. contoh:
#id { ... }
- Class Selector
- Berbeda dengan ID selector (harus unik) dan element selector (sangat general), class selector digunakan untuk mengelompokkan beberapa elemen (bisa saja berbeda jenis) sebagai satu class
- Pegelompokkan tersebut akan memudahkan kita untuk mengubah styling dan lain sebagainya terkait class tersebut
- Waktu yang tepat untuk menggunakan class selector adalah ketika kita ingin mengelompokkan beberapa elemen berbeda karena ada suatu kesamaan, dengan mengelompokkan elemen-elemen tersebut, kita hanya perlu mengedit satu kali dan akan berlaku untuk seluruh class tersebut (mengurangi redundancy serta meningkatkan efisiensi waktu)
.class { ... }
<html>
untuk menandai berkas html<head>
untuk hal-hal penting yang tidak akan ditampilkan pada web page, seperti<meta>
,<title>
, dll.<title>
untuk title web page yang akan ditampilkan pada tab browser<style>
untuk styling html element dengan CSS<body>
untuk menandai seluruh konten yang akan ditampilkan pada web page karena semua konten yang ada pada bagian ini akan ditampilkan kepada user<p>
untuk paragraf dan akan ignore white space<span>
untuk menandai elemen kecil HTML, biasanya digunakan untuk mempermudah proses styling elemen HTML<pre>
untuk paragraf yang pre-formatted<a>
untuk<form>
untuk membuat formulir pada web page yang memungkinkan user untuk mengirim data ke server<ul>
dan<ol>
untuk menampilkan berbagai hal dalam bentuk list (unordered list dan ordered list)<div>
untuk mengelompokkan dan mengatur berbagai elemen HTML untuk mempermudah proses styling dan lain sebagainya Note: Ada banyak tag lainnya yang belum saya explore
- Margin
- Merupakan space antara suatu elemen (bagian luarnya) dengan elemen-elemen lain (di luar elemen itu sendiri)
- Digunakan untuk mengatur spacing di luar elemen (dari sisi luar elemen itu sendiri)
- Berpengaruh terhadap elemen-elemen lain di sekitar elemen yang bersangkutan
- Padding
- Merupakan space antara batas suatu elemen dengan konten yang ada di dalam elemen itu sendiri
- Digunakan untuk mengatur spacing di dalam elemen (dari sisi dalam elemen itu sendiri)
- Hanya memengaruhi elemen itu sendiri
4. Jelaskan perbedaan antara framework CSS Tailwind dan Bootstrap. Kapan sebaiknya kita menggunakan Bootstrap daripada Tailwind, dan sebaliknya?
- Bootstrap
- Menyediakan berbagai komponen "siap pakai", sehingga akan meningkatkan efisiensi waktu ketika membangun web page
- Bootstrap tidak sefleksibel Tailwind karena memang telah menyediakan berbagai komponen jadi
- Menggunakan kelas CSS yang telah ditentukan di awal, sehingga kita langsung dapat menggunakannya pada elemen HTML yang ada
- Sebaiknya digunakan apabila memiliki keterbatasan waktu dan perlu membangun aplikasi dengan cepat dan tidak masalah dengan style yang tidak sefleksibel Tailwind untuk designnya karena telah disediakan oleb Bootstrap sendiri
- Tailwind
- Menyediakan "komponen dasar", sehingga tampilannya perlu diimplementasi oleh masing-masing user
- Tailwind jauh lebih fleksibel untuk dicustom oleh user karena memang hanya menyediakan komponen dasar tadi
- Memanfaatkan kelas CSS sebagai utilitas HTML, sehingga kita akan banyak kelas untuk mengatur style dan lain sebagainya dari elemen HTML yang ada
- Sebaiknya digunakan apabila ingin memiliki kendali yang lebih besar terkait design, tema, kustomisasi agar dapat menjadi lebih unik dan tidak masalah dengan menghabiskan waktu lebih lama
5. Jelaskan bagaimana cara kamu mengimplementasikan checklist di atas secara step-by-step (bukan hanya sekadar mengikuti tutorial).
- Cara implementasi:
- Memahami template HTML yang sudah ada dengan membagi ke beberapa bagian div
- Gunakan CSS untuk kustomisasi sederhana dan gunakan bootstrap untuk membuat navbar dan card
- Kustomisasi halaman login dan register dengan elemen-elemen bootstrap, seperti form dan tombol
- Kustomisasi halaman daftar barang dengan Cards dari bootstrap agar tampilan lebih menarik
- Sesuaikan warna, gaya, dan respon desain yang diinginkan
- Cek hasil pada localhost
- Synchronous:
- Request dijalankan secara sinkronus (berurutan)
- Program akan menunggu request saat ini selesai dieksekusi sebelum melanjutkan eksekusi request selanjutnya
- Implementasinya lebih mudah karena requestnya idlakukan secara berurutan
- Asynchronous:
- Request dijalankan secara asinkronus (paralel)
- Program tidak perlu menunggu request saat ini selesai dieksekusi sebelum melanjutkan eksekusi request selanjutnya, dapat dilakukan secara paralel
- Implementasinya lebih sulit karena dapat terjadi beberapa request secara beramaan
2. Dalam penerapan JavaScript dan AJAX, terdapat penerapan paradigma event-driven programming. Jelaskan maksud dari paradigma tersebut dan sebutkan salah satu contoh penerapannya pada tugas ini.
- Event-driven proogramming adalah paradigma di mana aplikasi akan memberikan respon terhadap suatu event tertentu sesuai yang telah didefinsikan
- Event-handler dapat didefinisikan sebagai function pada section script ataupun implementasi-implementasi lainnya
- Contohnya, jika kita memiliki tombol yang dapat membuka sebuah modal dengan form untuk menambahkan item dalam suatu html, kita dapat menambahkan event listener untuk mengirimkan data ke server ketika tombol tersebut diklik.
- Request dijalankan secara asinkronus (paralel)
- Program tidak perlu menunggu request saat ini selesai dieksekusi sebelum melanjutkan eksekusi request selanjutnya, dapat dilakukan secara paralel
- Dengan menerpakan asynchronous programming pada AJAX, user tidak harus menunggu respon dari server, sehingga browser user akan tetap responsif
- Event-handler dapat didefinisikan sebagai function pada section script ataupun implementasi-implementasi lainnya
4. Pada PBP kali ini, penerapan AJAX dilakukan dengan menggunakan Fetch API daripada library jQuery. Bandingkanlah kedua teknologi tersebut dan tuliskan pendapat kamu teknologi manakah yang lebih baik untuk digunakan.
- Fetch API:
- Menggunakan promise, sehingga syntax yang digunakan lebih mudah dipahami
- Memberikan tingkat fleksibilitas dan kontrol yang tinggi dengan berbagai ospi
- jQuery:
- Syntax yang digunakan pada jQuery relatif singkat dan sederhana
- Mungkin perlu menyertakan beberapa settings tambahan jika ingin memiliki tingkat kontrol dan fleksibilitas yang lebih tinggi
Menurut saya, teknologi Fetch API lebih baik untuk digunakan. Hal ini dikarenakan tingkal fleksibilitas dan ktonrol yang tinggi. Selain itu, Fetch API juga lebih modern, sehingga akan lebih compatible.
5. Jelaskan bagaimana cara kamu mengimplementasikan checklist di atas secara step-by-step (bukan hanya sekadar mengikuti tutorial).
-
Membuat fungsi untuk mengembalikan data JSON
def get_product_json(request): product_item = Product.objects.all() return HttpResponse(serializers.serialize('json', product_item))
-
Membuat fungsi menambahkan produk dengan AJAX
-
Menambahkan routing untuk fungsi get_product_json dan add_product_ajax
-
Menampilkan data product dengan Fetch API
<div id="product_table"></div> <script> async function getProducts() { return fetch("{% url 'main:get_product_json' %}").then((res) => res.json()) } </script>
-
Membuat fungsi pada AJAX product dan menambahkan modal sebagai card dilengkapi dengan ajax add product, increment product, decrement, dan remove
<script> async function getProducts() { return fetch("{% url 'main:get_product_json' %}").then((res) => res.json()) } async function refreshProducts() { document.getElementById("product_table").innerHTML = "" const products = await getProducts() let htmlString = `<div class="card-container">` products.forEach((item, index) => { htmlString += `\n <div class="card" style="width: 22rem; padding:1%;margin-left: 30px; padding-left:10 px padding-bottom:10px; padding-right: 10px ;"> <div class="card-body "> <h5 class="card-title">${ item.fields.name }</h5> <p class="card-text"> <table> <tr class="add-colortext"> <td>Price</td> <td>${ item.fields.price }</td> </tr> <tr class="add-colortext"> <td>Amount</td> <td>${ item.fields.amount }</td> </tr> <tr class="add-colortext"> <td>Description</td> <td>${ item.fields.description }</td> </tr> <tr class="add-colortext"> <td>Date Added</td> <td>${ item.fields.date_added }</td> </tr> </table> <table> <tr class="add-colortext"> <td> <form action="add_product/${item.pk}/" method="post"> {% csrf_token %} <button class="font-bold py-1 px-4 rounded edit-button border-0" style="color: rgb(0, 0, 0); font-weight: bolder; align-items: center" type="submit" name="Tambah" style="padding: 10px 20px;" onclick="incrementAmount(${item.pk})"> + </button> </form> </td> <td> <form action="decrement_product/${item.pk}/" method="post"> {% csrf_token %} <button class="font-bold py-1 px-4 rounded edit-button border-0" style="color: rgb(0, 0, 0); font-weight: bolder; align-items: center" type="submit" name="Kurang" style="padding: 10px 20px;" onclick="decrementAmount(${item.pk})"> - </button> </form> </td> <td> <form action="remove_product/${item.pk}/" method="post"> {% csrf_token %} <button class="font-bold py-1 px-4 rounded edit-button border-0" style="color: red; align-items: center" type="submit" name="Hapus" class="edit-button" style="padding: 10px 20px;" onclick="deleteProduct(${item.pk})"> delete </button> </form> </td> <td> <a href="edit-product/${item.pk}"> <button class="font-bold py-1 px-4 rounded edit-button border-0" style="padding: 10px 20px;"> Edit </button> </a> </td> </tr> </table> </p> </div> </div>` }) document.getElementById("product_table").innerHTML = htmlString } async function incrementAmount(id) { const response = await fetch(`/increment-amount/${id}`); refreshProducts(); } async function decrementAmount(id) { const response = await fetch(`/decrement-amount/${id}`); refreshProducts(); } async function deleteProduct(id) { const response = await fetch(`/delete-amount/${id}`); refreshProducts(); } refreshProducts() function addProduct() { fetch("{% url 'main:add_product_ajax' %}", { method: "POST", body: new FormData(document.querySelector('#form')) }).then(refreshProducts) document.getElementById("form").reset() return false } document.getElementById("button_add").onclick = addProduct </script>
-
Melakukan git add , commit , push
-
Melakukan deployment
link deployment https://artomoroweb.35.209.250.177.sslip.io/