From b1fd68eccbd2869d1e1e7c75e9802c81907223f8 Mon Sep 17 00:00:00 2001 From: Saras355 Date: Fri, 13 Oct 2023 08:20:26 +0700 Subject: [PATCH] tugas 6 --- README.md | 32 ++ main/templates/coba.html | 0 main/templates/create_product.html | 49 ++- main/templates/edit_product.html | 64 ++++ main/templates/main.html | 535 +++++++++++++++++++++++------ main/urls.py | 15 +- main/views.py | 141 +++++--- templates/base.html | 13 +- 8 files changed, 685 insertions(+), 164 deletions(-) create mode 100644 main/templates/coba.html create mode 100644 main/templates/edit_product.html diff --git a/README.md b/README.md index 270770b..a333e84 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,35 @@ +# TUGAS 6 +## 1. Perbedaan antara Asynchronous Programming dengan Synchronous Programming +Dalam asynchronous programming, tugas - tugas dieksekusi secara paralel atau nonblok. Tugas - tugas dapat berjalan secara bersamaan tanpa harus menunggu satu sama lain. Program asinkron berguna ketika terdapat tugas-tugas yang memerlukan waktu lama, seperti permintaan data dari server atau operasi I/O, sehingga program dapat melanjutkan menjalankan tugas lain tanpa harus menunggu tugas yang memakan waktu lama selesai. +Sedangkan dalam synchronous programming, tugas - tugas dieksekusi secara berurutan atau satu persatu. Setiap tugas harus menunggu tugas sebelumnya selesai sebelum dapat berjalan. Mekanisme seperti ini cocok untuk tugas - tugas yang tidak memerlukan waktu lama. Namun, hal ini bisa mengakibatkan program menjadi lambat jika ada tugas yang memakan waktu lama. +## 2.Penjelasan Paradigma Event-Driven Programming +Paradigma Event-Driven Programming merupakan pendekatan yang mana program merespon peristiwa atau event yang terjadi secara asinkron. Program akan menunggu peristiwa tertentu terjadi, seperti pemain data dari server, klik tombol atau peristiwa lainnya. Setelah mendapatkan peristiwa tersebut kemudian program akan merespon peristiwa tersebut dengan menjalankan kode yang sesuai. Contoh penggunaanya dalam tugas ini adalah ketika saya mengklik tombol add product, maka program akan menunggu peristiwa klik tersebut dan kemudian menjalankan permintaan AJAX untuk mengambil data dari server atau menambahkan produk ke dalam sistem. +## 3.Penerapan Asynchronous Programming pada AJAX +Penerapan asynchronous programming pada AJAX memungkinkan permintaan seperti HTTP (misalnya mengambil data dari server) untuk dieksekusi secara asinkron. Ini berarti aplikasi website tidak akan terhenti atau terblokir saat menunggu respon dari server. Contohnya adalah ‘XMLHttpRequest’ atau Fetch API untuk membuat permintaan AJAX asinkron. Penerapan AJAX, antara lain: +- Penggunaan Fetch API: Digunakan untuk mengirim permintaan HTTP asinkron ke server. +- Fungsi Callback: Dibuat untuk mengelola respons dari server. +- Mengirim Permintaan: Menggunakan Fetch API untuk mengirim permintaan ke server dengan pilihan metode (GET atau POST) dan header yang sesuai. +- Menangani Respons: Respons dari server berupa data yang bisa diolah dalam fungsi callback. +- Penanganan Kesalahan: Kesalahan selama permintaan ditangani dengan .catch. +- Integrasi dengan Aplikasi: Logika aplikasi diterapkan dalam fungsi callback untuk memproses data respons sesuai kebutuhan aplikasi. +## 4. Perbandingan FETCH API dengan jQuery untuk AJAX +Fetch API adalah bawaan dari JavaScript modern untuk mengirim permintaan HTTP. FETCH API lebih modern, lebih ringan daripada jQuery dan berfungsi dengan baik dengan Promise yang mendukung pemrograman asinkron. Penggunaan FETCH API tepat jika kita ingin menghindari beban berat jQuery.dan hanya memerlukan fitur - fitur AJAX. Selain itu, Fetch API memungkinkan kita untuk memutuskan koneksi atau mencoba ulang permintaan dengan lebih mudah. Dengan skenario pemutusan konektivitas tersebut , kita dapat mengendalikan timeout da kita dapat mencoba ulang permintaan yang diperlukan FETCH API dapat dengan mudah menambahkan header khusus ke permintaan kita dengan menggunakan opsi dalam fetch() yang sangat berguna jika kita mau mengirim otorisasi atau header lainnya. Objek ‘Response’ seperti fitur pada Fetch API memungkinkan untuk memproses response dengan berbagai cara, seperti mengambil data dalam format JSON atau mengambil informasi header. +jQuery merupakan perpustakaan JavaScript yang lebih tua dan lebih berat daripada Fetch API. Fitur - fitur nya melampaui AJAX, seperti animasi, manipulasi DOM, dan lainnya. Kedua, jQuery menggunakan pendekatan berbasis callback untuk mengelola tugas asinkron. Pendetekaatna ini menyebabkan kode yang lebih sulit dibaca jika kita memiliki banyak permintaan bersarang. Dari segi kapabilitas, jQuery memiliki dukungan yang lebih luas untuk browser yang lebih lama, yang bisa bermanfaat jika kita perlu mendukung peramban yang lebih tua. Selanjutnya, wrapper untuk XMLHTTPRequest, jQuery menggunakan XMLHttpRequest atau ActiveXobject (untuk IE lama) untuk melakukan permintaan AJAX. Ini berarti kita sebenarnya menggunakan teknologi yang sama tetapi dengan antarmuka yang lebih tingkat tinggi. +# 5. Cara mengimplementasikan checklist secara step-by-step +Langkah 1: Mengubah AJAX GET + Di dalam direktori "main/templates," saya membuka berkas "main.html." Pertama, saya menghapus kode tabel yang telah saya buat sebelumnya dan menambahkan elemen
untuk menyiapkan wadah tabel data produk. Selanjutnya, saya membuat fungsi baru dalam berkas "views.py" yang saya beri nama get_product_json. Fungsi ini bertugas untuk merespons permintaan dengan data dalam format JSON. Dengan fungsi ini, saya dapat menampilkan data produk pada halaman HTML yang bergantung pada pengguna yang sedang masuk. c. Saya pastikan fungsi get_product_json dapat diakses melalui URL dengan membuka berkas "urls.py" dalam folder "main," mengimpor fungsi tersebut, dan menambahkan path URL yang mengarahkan ke fungsi tersebut. Contohnya: path('get-product/', get_product_json, name='get_product_json'). +Langkah 2: Implementasi AJAX POST + Selanjutnya, saya menambahkan kode yang diperlukan untuk mengaktifkan modal menggunakan komponen Bootstrap di dalam aplikasi. Saya sisipkan tombol dengan atribut data-bs-toggle dan data-bs-target untuk memungkinkan pengguna membuka modal dengan mudah. Saya membuat fungsi view baru dalam berkas "views.py" yang saya beri nama add_product_ajax. Fungsi ini akan menambahkan produk baru ke basis data. Fungsi ini menerima parameter request untuk menangani permintaan dari pengguna. Dalam fungsi ini, saya akan mengekstrak nilai dari permintaan POST yang dikirimkan melalui AJAX, seperti "name," "amount," "description," dan "user." Nilai-nilai ini kemudian saya gunakan untuk menambahkan produk baru ke basis data. c. Saya pastikan untuk mendefinisikan path URL yang mengarahkan ke fungsi add_product_ajax dalam berkas "urls.py." Ini akan memungkinkan aplikasi untuk mengakses fungsi tersebut melalui URL. Contohnya: path('create-product-ajax/', add_product_ajax, name='add_product_ajax'). +Langkah 3: Menghubungkan Form Modal dengan Path /create-ajax + Saya membuat fungsi JavaScript baru dengan nama addProduct. Fungsi ini bertujuan untuk menghubungkan form dalam modal dengan path "/create-ajax." Dalam implementasi addProduct(), saya menggunakan objek FormData untuk mengumpulkan data dari form modal dan mengirimkannya ke server melalui AJAX. Setelah pengiriman berhasil, saya mengosongkan isi form modal.Untuk memastikan bahwa fungsi addProduct() dijalankan saat pengguna mengklik tombol "Add Product" dalam modal, saya tambahkan atribut onclick pada tombol tersebut dengan kode document.getElementById("button_add").onclick = addProduct. +Langkah 4: Memperbarui Halaman Utama secara Asinkron + Saya membuat fungsi JavaScript baru yang saya beri nama refreshProducts. Fungsi ini bertugas untuk memperbarui data produk secara asinkron. Dalam implementasinya, saya mengosongkan isi tabel produk dan mengambil data produk terbaru dengan menggunakan get(). Setiap produk saya olah dan tambahkan ke dalam tabel. +Langkah 5: Menjalankan Perintah collectstatic Terakhir, saya menjalankan perintah collectstatic. + Perintah ini berguna untuk mengumpulkan file statis dari berbagai aplikasi dalam proyek ke dalam satu folder yang siap digunakan di lingkungan produksi. Saya pastikan untuk menjalankan perintah ini melalui terminal setelah saya berpindah ke direktori proyek saya. + + + + # TUGAS 5 ## 1. Jelaskan manfaat dari setiap element selector dan kapan waktu yang tepat untuk menggunakannya Element selectors dalam CSS berguna untuk menentukan gaya atau tampilan elemen HTML tertentu pada halaman website. Jenis - jenis element selector beserta manfaat dan penggunaan yang tepat, atnara lain: diff --git a/main/templates/coba.html b/main/templates/coba.html new file mode 100644 index 0000000..e69de29 diff --git a/main/templates/create_product.html b/main/templates/create_product.html index a59beac..8567d53 100644 --- a/main/templates/create_product.html +++ b/main/templates/create_product.html @@ -1,5 +1,4 @@ {% extends 'base.html' %} - {% block meta %} Add New Product {% endblock meta %} - {% block content %} -
-
-

Add New Product

-
- {% csrf_token %} -
- {{ form.as_table }} -
-
- +
+
+
+
+
+

Add New Item

+
+
+ + {% csrf_token %} +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ +
- +
-{% endblock content %} +{% endblock %} diff --git a/main/templates/edit_product.html b/main/templates/edit_product.html new file mode 100644 index 0000000..e3dfe91 --- /dev/null +++ b/main/templates/edit_product.html @@ -0,0 +1,64 @@ +{% extends 'base.html' %} + +{% load static %} + +{% block content %} +
+ +
+ +

Edit Product

+ +
+ {% csrf_token %} + + {{ form.as_table }} + + + + +
+ +
+
+
+ +
+ + +{% endblock %} diff --git a/main/templates/main.html b/main/templates/main.html index 261bef2..0275fa3 100644 --- a/main/templates/main.html +++ b/main/templates/main.html @@ -1,127 +1,470 @@ -{% extends 'base.html' %} + +{% extends 'base.html' %} {% block content %} + Toko Saras + -

List Barang Toko Saras

- -
Name: {{name}}
- - -
Class: {{class}}
- -

Kamu menyimpan {{ total_items }} item pada toko ini.

- -{% comment %} Berikut cara memperlihatkan data produk di bawah baris ini {% endcomment %} - -{% for product in products %} -
-

{{ product.name }}

-

Price: {{ product.price }}

-

Amount: {{ product.amount }}

-
- {% csrf_token %} - -
-
- {% csrf_token %} - -
-

Description: {{ product.description }}

-

Date Added: {{ product.date_added }}

-
- {% csrf_token %} - -
+ + + +
+ +
+
Name:
+

{{ name }}

+ +
Class:
+

{{ class }}


+
+ + +
+

Anda telah menyimpan {{ total_products }} produk.

+
+ + + +
+ + +
+ + +
Sesi terakhir login: {{ last_login }}
+ + + + + + + +
-{% endfor %} -
Sesi terakhir login: {{ last_login }}
+ {% endblock content %} + + + + + + + + + + + diff --git a/main/urls.py b/main/urls.py index 6f77003..c85bc3a 100644 --- a/main/urls.py +++ b/main/urls.py @@ -1,5 +1,5 @@ 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, register, login_user, logout_user, add_product, subtract_product, delete_product +from main.views import show_main, create_product, show_xml ,edit_product, show_json, show_xml_by_id, show_json_by_id, register, login_user, logout_user, add_product, subtract_product, delete_product, get_product_json, add_product_ajax @@ -16,7 +16,12 @@ path('register/', register, name='register'), path('login/', login_user, name='login'), path('logout/', logout_user, name='logout'), - path('add_stock//', add_product, name='add_product'), - path('subtract_product//', subtract_product, name='subtract_product'), - path('delete_product//', delete_product, name='delete_product'), -] \ No newline at end of file + path('edit-product/', edit_product, name='edit_product'), + + path('delete_product/', delete_product, name='delete_product'), + path('get-product/', get_product_json, name='get_product_json'), + path('create-product-ajax/', add_product_ajax, name='add_product_ajax'), + path('add_product/', add_product, name='add_product'), + path('subtract_product/', subtract_product, name='subtract_product'), +] + diff --git a/main/views.py b/main/views.py index c591f40..1c2ebae 100644 --- a/main/views.py +++ b/main/views.py @@ -1,33 +1,47 @@ - import datetime -from django.shortcuts import render, redirect, get_object_or_404 -from django.contrib.auth.forms import UserCreationForm -from django.contrib import messages -from django.http import HttpResponseRedirect from main.forms import ProductForm +from main.models import Product from django.urls import reverse -from django.http import HttpResponse +from django.http import HttpResponseRedirect, HttpResponse, HttpResponseNotFound, JsonResponse; from django.core import serializers -from main.models import Product #cek -from django.contrib.auth.decorators import login_required -# Create your views here. +from django.shortcuts import get_object_or_404, redirect, render +from django.contrib import messages from django.contrib.auth import authenticate, login, logout - +from django.contrib.auth.forms import UserCreationForm +from django.contrib.auth.decorators import login_required +from django.views.decorators.csrf import csrf_exempt @login_required(login_url='/login') +# Create your views here. def show_main(request): products = Product.objects.filter(user=request.user) - total_items = products.count() + total_products = products.count() + context = { 'name': request.user.username, - 'class': 'PBP E', - 'products': products, - 'total_items' : total_items, + 'class' : 'PBP E', + 'products' : products, + 'total_products' : total_products, 'last_login': request.COOKIES['last_login'], } - return render(request, "main.html", context) + +def edit_product(request, id): + + product = Product.objects.get(pk = id) + + + form = ProductForm(request.POST or None, instance=product) + + if form.is_valid() and request.method == "POST": + + form.save() + return HttpResponseRedirect(reverse('main:show_main')) + + context = {'form': form} + return render(request, "edit_product.html", context) + def create_product(request): form = ProductForm(request.POST or None) @@ -36,32 +50,31 @@ def create_product(request): product.user = request.user product.save() return HttpResponseRedirect(reverse('main:show_main')) - + context = {'form': form} return render(request, "create_product.html", context) -def show_xml(request): - data = Product.objects.all() + + def show_xml(request): data = Product.objects.all() return HttpResponse(serializers.serialize("xml", data), content_type="application/xml") -def show_json(request): - data = Product.objects.all() def show_json(request): data = Product.objects.all() return HttpResponse(serializers.serialize("json", data), content_type="application/json") - def show_xml_by_id(request, id): - data = Product.objects.filter(pk=id) + data =Product.objects.filter(pk=id) return HttpResponse(serializers.serialize("xml", data), content_type="application/xml") + def show_json_by_id(request, id): - data = Product.objects.filter(pk=id) + data =Product.objects.filter(pk=id) return HttpResponse(serializers.serialize("json", data), content_type="application/json") + def register(request): form = UserCreationForm() @@ -74,6 +87,7 @@ def register(request): context = {'form':form} return render(request, 'register.html', context) + def login_user(request): if request.method == 'POST': username = request.POST.get('username') @@ -89,6 +103,7 @@ def login_user(request): context = {} return render(request, 'login.html', context) + def logout_user(request): logout(request) response = HttpResponseRedirect(reverse('main:login')) @@ -96,28 +111,70 @@ def logout_user(request): return response @login_required(login_url='/login') -def add_product(request, product_id): +def add_product(request): if request.method == 'POST': - product = Product.objects.get(pk=product_id) - quantity = 1 - product.amount += quantity - product.save() - return redirect('main:show_main') + product_id = request.POST.get('product_id') + try: + product = Product.objects.get(id=product_id) + product.amount += 1 + product.save() + return JsonResponse({'message': 'Stock added successfully'}) + except Product.DoesNotExist: + return JsonResponse({'message': 'Product not found'}, status=404) + return JsonResponse({'message': 'Invalid request method'}, status=405) + @login_required(login_url='/login') -def subtract_product(request, product_id): + +def subtract_product(request): if request.method == 'POST': - product = Product.objects.get(pk=product_id) - quantity = 1 - if product.amount >= quantity: - product.amount -= quantity - product.save() - return redirect('main:show_main') + product_id = request.POST.get('product_id') + try: + product = Product.objects.get(id=product_id) + if product.amount > 0: + product.amount -= 1 + product.save() + return JsonResponse({'message': 'Stock reduced successfully'}) + else: + return JsonResponse({'message': 'Stock cannot be reduced below 0'}) + except Product.DoesNotExist: + return JsonResponse({'message': 'Product not found'}, status=404) + return JsonResponse({'message': 'Invalid request method'}, status=405) + + @login_required(login_url='/login') -def delete_product(request, product_id): - product = get_object_or_404(Product, id=product_id) - # Memastikan hanya pemilik produk yang dapat menghapusnya - if product.user == request.user: - product.delete() - return redirect('main:show_main') +def delete_product(request): + if request.method == 'POST': + product_id = request.POST.get('product_id') + try: + product = Product.objects.get(id=product_id) + product.delete() + return JsonResponse({'message': 'Product deleted successfully'}) + except Product.DoesNotExist: + return JsonResponse({'message': 'Product not found'}, status=404) + + return JsonResponse({'message': 'Invalid request method'}, status = 405) + + +def get_product_json(request): + product = Product.objects.filter(user=request.user) + return HttpResponse(serializers.serialize('json', product)) + + + +@csrf_exempt +def add_product_ajax(request): + if request.method == 'POST': + name = request.POST.get("name") + amount = request.POST.get("amount") + price = request.POST.get("price") + description = request.POST.get("description") + user = request.user + + new_item = Product(name=name, price=price, amount=amount, description=description, user=user) + new_item.save() + + return HttpResponse(status=201) + + return HttpResponse(status=404) \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index f6727a3..3cf505e 100644 --- a/templates/base.html +++ b/templates/base.html @@ -2,16 +2,17 @@ - - {% block meta %} + + {% endblock meta %} + + + + - + {% block content %} {% endblock content %}