# **TRY DJANGO 1.11 | Start Project** ![django-logo-negative.1d528e2cb5fb](https://hackmd.io/_uploads/HkKG-sJJ0.png) ## **Django Overview** Salah satu permasalahan yang saat ini sering kita jumpai ialah bagaimana cara membangun web dengan cepat dan efektif? Maka, Django menawarkan pengalaman yang dibutuhkan ini. Django sendiri menggunakan bahasa pemrograman Python yang ramah untuk pemula tapi juga dapat dikembangkan lebih bagi pengguna expert. Beberapa aplikasi yang sering kita gunakan sangat mungkin bahwa dalam pengembangannya menggunakan django. Seperti instagram, pinterest, dropbox, dsb. Cara kerja Django yang sebenarnya secara spesifik ialah, ketika kita mengunjungi sebuah domain, system akan menangani **url** yang diberikan baik itu url singkat maupun versi yang lebih panjang. Kemudian, akan **dikembalikan** berdasarkan informasi yang tersimpan pada server. Bahkan, django akan **mengingat** pengguna saat masuk ke dalam web tersebut, sebgaiamana pengguna terakhir yang mengakses. Sekalipun, saat berada pada jangka waktu yang lama tidak mengunjungi website tersebut. Dalam lingkup yang sama, django juga mengingat **preferensi** penggunanya, yang tersimpan pada back end system yang mereka miliki. Beberapa layanan yang dapat dimiliki dan dikelola oleh Django ialah seperti akun, video, content, analytics, menu listing, bahkan mungkin untuk memuat informasi promosi, dsb. --- ## **Django Framework** ![Screenshot 2024-03-29 170230](https://hackmd.io/_uploads/BJhA-f4JR.png) image source: https://www.biznetgio.com/news/django - Model, data yang ingin ditampilkan atau penghubung antara interface pengguna dan database, biasanya dari database. Model biasanya memiliki kode models.py. - View, berisi logika UI dan menjadi penanganan permintaan yang mengembalikan template dan konten yang relevan berdasarkan permintaan dari pengguna. Mencakup elemen HTML, CSS, dan front-end lainnya. View biasanya memiliki kode views.py. - Template, sebuah file teks (layaknya file HTML) yang berisi letak halaman web. Template biasanya memiliki kode templates. Semua aktivitas **back-end**, seperti logika dan query dikerjakan pada Model. Sementara, semua hal yang menyangkut tampilan **front-end** dikelola oleh Template. Dengan demikian, developer tidak perlu menggunakan dua **framework** terpisah untuk back-end dan front-end saat membangun website dan aplikasi dengan framework **Django**. --- :::success :bulb: **Attention** When you finish read this section, you can accsess my next documentation, that's talk about about create database and logic UI in Django1.11, click this link: [TRY DJANGO 1.11 (Database & Logic UI)](https://hackmd.io/@syafaa/TryDjango2) Hope you enjoy it!!! ::: --- ## **Start Django Project** ### **1. Django Environtment** Untuk menjalankan django. diperlukan beberapa software pendukung ialah: 1. Python (Phyton3) dan depedencynya 2. Pip 3. Virtualenv 4. Sublime Text Berikut merupakan langkah untuk menyiapkan blank django project: 1. Melakukan update vm yang digunakan ``` sudo apt-get update ``` 2. Melakukan instalasi sublime text ``` wget -qO - https://download.sublimetext.com/sublimehq-pub.gpg | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/sublimehq-archive.gpg > /dev/null echo "deb https://download.sublimetext.com/ apt/stable/" | sudo tee /etc/apt/sources.list.d/sublime-text.list sudo apt-get update sudo apt-get install sublime-text ``` ![Screenshot 2024-03-25 085001](https://hackmd.io/_uploads/Syyt2ICCa.png) 3. Melakukan instalasi Phyton3 dan pip ``` sudo apt install python3 python3-pip ``` ![Screenshot 2024-03-25 084221](https://hackmd.io/_uploads/SyW238RR6.png) 4. Memastikan python dan pip telah terinstal ``` python3 --version pip3 --version ``` ![Screenshot 2024-03-25 085339](https://hackmd.io/_uploads/SJZT2IRAT.png) 5. Melakukan instalasi development package ``` sudo apt libreadline-gplv2-dev libncursesw5-dev libpq-dev python3-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev ``` ![Screenshot 2024-03-25 084358](https://hackmd.io/_uploads/rynlTI0Ca.png) 6. Membuat direktori baru Dev sekaligus trydjango1-11 di dalamnya ``` mkdir Dev && cd Dev mkdir trydjango1-11 && cd trydjango1-11 ``` 7. Melakukan instalasi virtualenv python ``` sudo apt install python3-virtualenv virtualenv -p python3 . ``` ![Screenshot 2024-03-25 085158](https://hackmd.io/_uploads/rJ4wTUC0T.png) ![Screenshot 2024-03-25 085243](https://hackmd.io/_uploads/H1vDTU0RT.png) 8. Menginstal django 1.11 di dalam virtualenv ``` source /bin/activate pip install django==1.11.* ``` ![Screenshot 2024-03-25 085530](https://hackmd.io/_uploads/rkMop8AAa.png) ### **2. Start Django Project** 1. Membuat project django bernama muypicky pada direktori src ``` mkdir src && cd src django-admin.py startproject muypicky . ``` ![Screenshot 2024-03-25 085612](https://hackmd.io/_uploads/BkwApLACT.png) 2. Membuat file yang dibutuhkan dalam direktori setting ``` cd muypicky/ mkdir settings && cd settings touch _init_.py touch base.py touch local.py touch production.py ``` 3. Mengisi file base.py dengan isi file settings.py ``` cp settings.py settings/base.py ``` mengubah BASE_DIR pada base.py menjadi ``` BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) ``` ![Screenshot 2024-03-25 092020](https://hackmd.io/_uploads/BJiOJwCAp.png) 4. Mengisi file _init_.py sebagai berikut: ``` from .base import * from .production import * try: from .local import * except: pass ``` 5. Menginstal beberapa pustaka tambahan ``` pip install psycopg2 pip install gunicorn pip install django-crispy-forms==1.7.2 pip install dj-database-url==0.5.0 pip install pillow ``` dan melihat version setiap instalasi yang dilakukan ``` pip freeze > requirements.txt ``` ![Screenshot 2024-03-25 092252](https://hackmd.io/_uploads/rJlfew00T.png) 6. Menjalankan migration ``` python manage.py migrate ``` ![Screenshot 2024-03-25 090307](https://hackmd.io/_uploads/rktVevCCa.png) 7. Membuat superuser ``` python manage.py createsuperuser ``` ![Screenshot 2024-03-25 090312](https://hackmd.io/_uploads/Hyem8ewCCp.png) 8. Menjalankan server ``` python manage.py runserver ``` dan mengakses web melalui http://127.0.0.1:8000/ ![Djangoo [Running] - Oracle VM VirtualBox 25_03_2024 09_06_35](https://hackmd.io/_uploads/B1ICgwR0T.png) ![127.0.0.1 - Google Chrome 25_03_2024 09_24_45](https://hackmd.io/_uploads/Sy90ew00a.png) 9. Melengkapi file local.py dan production.py ``` cp base.py local.py cp base.py production.py ``` dengan perubahan pada production.py sebagai berikut: ``` DEBUG = False SECRET_KEY = "random letter or number" ``` ### **3. Mengkonfigurasi Website** 1. Membuat menu listing ``` python manage.py startapp restaurants . ``` 2. Mengatur tampilan page dalam file views.py ``` from django.http import HttpResponse from django.shortcuts import render def home(request): return HttpResponse("hello") ``` 3. Mengatur url pada file urls.py ``` from django.conf.urls import url from django.contrib import admin from restaurants.views import home urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', home), ] ``` ## **HTML and Django** ### **1. Rendering HTML** HTML merupakan bahasa yang dimengerti oleh browser, kemudian diterjemahkan hingga menjadi tampilan yang dilihat langsung oleh penggunanya. - Python string ``` from django.http import HttpResponse from django.shortcuts import render def home(request): html_ = """<!DOCTYPE html> <html lang=en> <head> <head/> <body> <h1>Hello world</h1> <p>This is html coming trough</p> </body> </html> """ return HttpResponse(html_) ``` ![Screenshot 2024-03-25 100308](https://hackmd.io/_uploads/r1ugmc0Ca.png) - Python string subtitution ``` from django.http import HttpResponse from django.shortcuts import render def home(request): html_var = 'trial' html_ = f"""<!DOCTYPE html> <html lang=en> <head> <head/> <body> <h1>Hello world</h1> <p>This is trial coming trough</p> </body> </html> """ return HttpResponse(html_) ``` ![Screenshot 2024-03-25 100929](https://hackmd.io/_uploads/HJJWX90RT.png) ### **2. Render a Django Template** #### **a. String html** 1. Membuat file base.html ``` touch /home/ubuntu//Dev/trydjango1-11/lib/python3.8/site-palates/base.html ``` 2. Mengisi file base.html sebagaimana berikut: ``` <!DOCTYPE html> <html lang=en> <head> <head/> <body> <h1> Hello World! </h1> <p> This is trial coming trough </p> </body> </html> ``` 3. Mengubah isi file base.py pada bagian TEMPLATES, sebagai berikut: ``` 'DIRS': [os.path.join(BASE_DIR, 'templates')], ``` 4. Mengisi file views.py, sebagaimaan berikut: ``` from django.http import HttpResponse from django.shortcuts import render def home(request): return render(request, "base.html", {}) ``` 5. Mengubah isi file _init_.py dalam direktori settings, sebagaimana berikut: ``` from .base import * #from .production import * #try: # from .local import * #except: # pass ``` 6. Akses pada url http://172.0.0.1:8000/ ![Screenshot 2024-03-25 210325](https://hackmd.io/_uploads/HkctBZJ1A.png) #### **b. Context variable** 1. Untuk menggunakan variable pada file html. Maka ubah file base.html sebagaimana berikut: ``` <!DOCTYPE html> <html lang=en> <head> </head> <body> <h1> Hello world </h1> <p> This is {{ html_var }} coming trough </p> <p> Your random number is {{ num }}! </p> </body> </html> ``` 2. Mengubah isi file views.py menjadi sebagaimana berikut: ``` from django.http import HttpResponse from django.shortcuts import render def home(request): num = random.randint(0, 100000000) return render(request, "base.html", {"html_var": True, "num": num}) ``` 3. Akses pada url http://172.0.0.1:8000/ ![Screenshot 2024-03-25 210759](https://hackmd.io/_uploads/Bkz9HbyJR.png) ### 3. Context in Django Templates Memahami bagaimana kerja sesungguhnya dari context di dalam template. Ketika pengguna mengubah apa yang dibutuhkan pada file views.py (manage url), maka tampilan pada web yang di render akan menyesuaikan kondisi yang dicantumkan pada file template base.html (html). Untuk menerapkannya, ikuti langkah berikut: 1. Mengisi file base.html dengan sebagaimana berikut: ``` <!DOCTYPE html> <html lang=en> <head> </head> <body> <h1> Hello World! </h1> <p> This is <code>{% verbatim %}{{ html_var }}{% endverbatim %}</code> coming trough </p> <p> {^ if bool_item %} Your random number is {{ num }}! {% endfor %} </p> <p> {% for some_item in some_list %} {{ some_item }}<br/> {% endfor %} </p> <p> Some item is {{ some_item }} </p> </body> </html> ``` 2. Mengubah isi file pada views.py, sebagaimana berikut: ``` import random from django.http import HttpResponse from django.shortcuts import render def home(request): num = None some_list = [ random.randint(0, 100000000), random.randint(0, 100000000), random.randint(0, 100000000) ] condition_bool_item = False if condition_bool_item: num = random.randint(0, 100000000) context = { "num": num, "some_list": some_list } return render(request, "base.html", context) ``` 3. Mengakses web pada url http://172.0.0.1:8000/ ![Screenshot 2024-03-25 214035](https://hackmd.io/_uploads/Hycgp4x1C.png) ### **4. Template In Heritance** Template in heritance meungkinkan pengguna untuk mengubah layout content di dalam web yang sebenarnya berada pada template yang berbeda-beda, sekaligus memanggil extends untuk template yang dimaksud. Disini saya menjalankan template in heritance sebagai berikut: 1. Membuat file base.html dan mengisinya sebagaimana berikut: ``` <!DOCTYPE html> <html lang=en> <head> <title>{% block head_tittle %}EXO-l.com{% endblock head_tittle %}</title> <head> <body> <h1>EXO-l.com</h1> <a href="/">Home</a> <a href="/about/">About</a> <a href="/content/">Our Content</a> <div class="container"> {% block content %}{% endblock content %} </div> </body> </html> ``` 2. Membuat file home.html dan mengisinya sebagaimana berikut: ``` {% extends "base.html" %} {% block content %} <h1> Wellcome! </h1> <h3> {{ block.super }} </h3> <p> This is <code>{% verbatim %}{{ html_var }}{% endverbatim %}</code> coming trough </p> <p> {% if num is not None %} Random number is {{ num }} {% endif %} </p> <p> {% for some_item in some_list %} {% if some_item|divisibleby:"2" %} Even number {% endif %} {{ some_item }} <br/> {% endfor %} </p> <p> Some item is {{ some_item }} </p> {% endblock content %} ``` 3. Membuat file about.html dan mengisinya sebagaimana berikut: ``` {% extends "base.html" %} {% block head_tittle %}About || {{ block.super }}{% endblock head_tittle %} {% block content %} <p>About</p> {% endblock %} ``` 4. Membuat file content.html dan mengisinya sebagaimana berikut: ``` {% extends "base.html" %} {% block head_tittle %}Our Content || {{ block.super }}{% endblock head_tittle %} {% block content %} <p>Our Content</p> {% endblock %} ``` 5. Mengubah file urls.py sebagaimana berikut: ``` from django.conf.urls import url from django.contrib import admin from restaurants.views import home, about, content urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', home), url(r'^about/$', about), url(r'^content/$', content), ] ``` 6. Mengakses web pada url http://172.0.0.1:8000/ ![Screenshot 2024-03-25 225339](https://hackmd.io/_uploads/Sy0EAz11C.png) ![Screenshot 2024-03-25 225355](https://hackmd.io/_uploads/HkyrRG1k0.png) ![Screenshot 2024-03-25 225407](https://hackmd.io/_uploads/ry-rRG11C.png) ### **5. Template Tag** 1. Membuat file nav.html, css.html, js.html, dan sidebar.html di dalam direktori templates/snippets/ ``` touch /home/ubuntu/Dev/trydjango1-11/lib/python3.8/site-packages/django/contrib/admin/templates/snippets/nav.html touch /home/ubuntu/Dev/trydjango1-11/lib/python3.8/site-packages/django/contrib/admin/templates/snippets/css.html touch /home/ubuntu/Dev/trydjango1-11/lib/python3.8/site-packages/django/contrib/admin/templates/snippets/js.html touch /home/ubuntu/Dev/trydjango1-11/lib/python3.8/site-packages/django/contrib/admin/templates/snippets/sidebar.html ``` 2. Mengubah file nav.html, sebagaimana berikut: ``` <div class='container'> <h1>EXO-l.com</h1> <a href="/">Home</a> <a href="/about/">About</a> <a href="/content/">Our Content</a> </div> ``` 3. Mengubah file css.html dengan Bootstrap CDN CSS , sebagaimana berikut: ``` <!-- Latest compiled and minified CSS --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <!-- Optional theme --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"> ``` 4. Mengubah file js.html dengan Bootstrap CDN JavaScript, sebagaimana berikut: ``` <script src='https://code.jquery.com/jquery-3.7.1.min.js'></script> <!-- Latest compiled and minified JavaScript --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> ``` 5. Mengubah file sidebar.html, sebagaimana berikut: ``` <ul> <li>Suho</li> <li>D.O.</li> <li>Xiumin</li> <li>Chen</li> <li>Baekhyun</li> <li>Chanyeol</li> <li>lay</li> <li>Kai</li> <li>Sehun</li> </ul> ``` 6. Mengubah file base.html, sebagaimana berikut: ``` <!DOCTYPE html> <html lang=en> <head> <title>{% block head_tittle %}EXO-l.com{% endblock head_tittle %}</title> {% include 'snippets/css.html' %} <head> <body> {% include 'snippets/nav.html' %} <div class='container'> {% block content %}{% endblock content %} </div> {% include 'snippets/js.html' %} </body> </html> ``` 7. Mengubah file about.html menjadi sebagaimana berikut: ``` {% extends "base.html" %} {% block head_tittle %}About || {{ block.super }}{% endblock head_tittle %} {% block content %} <p>About</p> {% include 'snippets/sidebar.html' %} {% endblock %} ``` 8. Mengubah file content.html menjadi sebagaimana berikut: ``` {% extends "base.html" %} {% block head_tittle %}Our Content || {{ block.super }}{% endblock head_tittle %} {% block content %} <p>Our Content</p> {% include 'snippets/sidebar.html' %} {% endblock %} ``` 9. Mengakses web pada url http://172.0.0.1:8000/ ![Screenshot 2024-03-25 233304](https://hackmd.io/_uploads/HJl1VskkA.png) ![Screenshot 2024-03-25 233314](https://hackmd.io/_uploads/SJVk4jJy0.png) ![Screenshot 2024-03-25 233325](https://hackmd.io/_uploads/S181NjyJC.png) ### **6. Class Based View** Class based view ialah pendekatan yang memungkinkan untuk mengorganisasi logika tampilan yang mengimplementasikan metode-metode khusus yang dipanggil berdasarkan jenis permintaan HTTP yang diterima (seperti GET, POST, PUT, DELETE, dll.). Get methode 1. Mengubah file views.py, sebagaimana berikut: ``` import random from django.http import HttpResponse from django.shortcuts import render from django.views import View def home(request): num = None some_list = [ random.randint(0, 100000000), random.randint(0, 100000000), random.randint(0, 100000000) ] condition_bool_item = False if condition_bool_item: num = random.randint(0, 100000000) context = { "num": num, "some_list": some_list } return render(request, "home.html", context) def about(request): context = { } return render(request, "about.html", context) def content(request): context = { } return render(request, "content.html", context) class ContentView(View): def get(self, request, *args, **kwargs): print(kwargs) context = { } return render(request, "content.html", context) ``` 2. Mengubah file urls.py sebagaimana berikut: ``` from django.conf.urls import url from django.contrib import admin from restaurants.views import home, about, content, ContentView urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', home), url(r'^about/$', about), url(r'^content/(?P<id>\d+)/$', ContentView.as_view()), ] ``` 3. Mengakses web pada url http://172.0.0.1:8000/ ![Screenshot 2024-03-25 235134](https://hackmd.io/_uploads/Hk1lNiyyR.png) halaman baru bisa diakses setelah menambahkan angka pada url http://172.0.0.1:8000/365/, sebagaimana berikut: ![Screenshot 2024-03-25 235146](https://hackmd.io/_uploads/SyfGViyJR.png) ![Screenshot 2024-03-25 235926](https://hackmd.io/_uploads/H1jQVi11C.png) ### **7. Template View** Template view ini merupakan penggabungan antara template yang digunakan dengan menyertakan template lain saat proses rendering. Berikut langkah yang saya lakukan ketika menggunakan template view: 1. Mengubah isi file views.py menjadi sebagimana berikut: ``` import random from django.http import HttpResponse from django.shortcuts import render from django.views import View from django.views.generic import TemplateView class HomeView(TemplateView): template_name = 'home.html' def get_context_data(self, *args, **kwargs): context = super(HomeView, self).get_context_data(*args, **kwargs) num = None some_list = [ random.randint(0, 100000000), random.randint(0, 100000000), random.randint(0, 100000000) ] condition_bool_item = False if condition_bool_item: num = random.randint(0, 100000000) context = { "num": num, "some_list": some_list } return context class AboutView(TemplateView): template_name = 'about.html' class ContentView(TemplateView): template_name = 'content.html' ``` 2. Mengubah isi file urls.py menjadi sebagimana berikut: ``` from django.conf.urls import url from django.contrib import admin from restaurants.views import HomeView, AboutView, ContentView urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', HomeView.as_view()), url(r'^about/$', AboutView.as_view()), url(r'^content/$', ContentView.as_view()), ] ``` 3. Mengakses web dengan url http://172.0.0.1:8000/ ![Screenshot 2024-03-25 233304](https://hackmd.io/_uploads/HJl1VskkA.png) ![Screenshot 2024-03-25 233314](https://hackmd.io/_uploads/SJVk4jJy0.png) ![Screenshot 2024-03-25 233325](https://hackmd.io/_uploads/S181NjyJC.png) ## **Remember Things** ### **1. Remembering things with Models** Dengan menggunakan model, Django memungkinkan pengembang untuk menyimpan data dalam database secara terstruktur dan terorganisir menggunakan model-model yang didefinisikan. 1. Membuat superuser baru ``` python manage.py createsuperuser ``` 2. Akses 127.0.0.1:8000/admin/ dan masuk ke superuser yang dibuat. ![Screenshot 2024-03-26 084508](https://hackmd.io/_uploads/HkocVVlJC.png) ![Screenshot 2024-03-26 084541](https://hackmd.io/_uploads/BkvoN4gJ0.png) File yang ada pada halaman admin, users, auth , dsb tersimpan pada database di file db.sqlite3. Yang kemudian di import melalui settings/base.py. Untuk itu, ketika hendak melakukan perubahan pada halaman, harus dijalankan perintah migration. 3. Mengubah isi file models.py di dalam direktori restaurants, sebagaimana berikut: ``` from django.db import models class RestaurantLocation(models.Model): name = models.CharField(max_length=120) location = models.CharField(max_length=120, null=True, blank=True) ``` 4. Mengubah isi file admin.py di dalam direktori restaurants sebagaimana berikut: ``` from django.contrib import admin from .models import RestaurantLocation admin.site.register(RestaurantLocation) ``` 5. Mengubah isi file base.py, menambahkan direktori restaurant pada bagian INSTALLED_APP, sebagaimana berikut: ``` INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'restaurants', ] ``` 6. Mengirim perubahan dan melakukan migration ``` python manage.py makemigrations python manage.py migrate ``` 7. Check melalui browser ![Screenshot 2024-03-27 214913](https://hackmd.io/_uploads/Sk6QsW4yC.png) menambahkan object: ![Screenshot 2024-03-27 215100](https://hackmd.io/_uploads/H1F4obVJ0.png) ![Screenshot 2024-03-27 220555](https://hackmd.io/_uploads/SJ24sZVkR.png) ### **2. More on Models Field** 1. Membuat aplikasi tambahan yaitu Event ``` python manage.py startapp events ``` 2. Mengisi file models.py di dalam direktori events, sebagaimana berikut: ``` from django.db import models class Event(models.Model): name = models.CharField(max_length=120) artist = models.CharField(max_length=120, null=True, blank=True) location = models.CharField(max_length=120, null=True, blank=True) Event_date = models.DateField(auto_now=False, auto_now_add=False) timestamp = models.DateTimeField(auto_now=True) update = models.DateTimeField(auto_now_add=True) ``` 3. Mengisi file admin.py direktori events sebagaimana berikut: ``` from django.contrib import admin from .models import Event admin.site.register(Event) ``` 4. Menambahkan direktori events ke dalam instalation app pada file base.py, sebagimana berikut: ``` INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'restaurants', 'events', ] ``` 5. Menjalankan migration ``` python manage.py makemigrations python manage.py migrate ``` ![Screenshot 2024-03-27 221018](https://hackmd.io/_uploads/By28o-E1A.png) 6. Mengakses melalui browser ![Screenshot 2024-03-27 221041](https://hackmd.io/_uploads/BJzPi-410.png) menambahkan object: ![Screenshot 2024-03-27 222544](https://hackmd.io/_uploads/SJxFsbEJ0.png) 7. Mengubah file models.py menjadi sebagaimana berikut: ``` from django.db import models class Event(models.Model): name = models.CharField(max_length=120) artist = models.CharField(max_length=120) category = models.CharField(max_length=120) location = models.CharField(max_length=120, null=True, blank=True) Event_date = models.DateField(auto_now=False, auto_now_add=False) timestamp = models.DateTimeField(auto_now=True) update = models.DateTimeField(auto_now_add=True) ``` 8. Menjalankan migration ``` python manage.py makemigrations python manage.py migrate ``` ![Screenshot 2024-03-27 224447](https://hackmd.io/_uploads/HkE9iZN10.png) 9. Akses melalui browser dan lakukan perubahan ![Screenshot 2024-03-27 224656](https://hackmd.io/_uploads/BkT9sZV10.png) ![Screenshot 2024-03-27 224713](https://hackmd.io/_uploads/rJGjob4JC.png) --- ### **3. Displaying Saved Data** 1. Membuat file events.html ``` touch events/templates/events/event_list.html ``` 2. Mengubah isi file views.py ``` from django.http import HttpResponse from django.shortcuts import render from django.views import View from django.views.generic import TemplateView from .models import Event def events_listview(request): template_name = 'events/events_list.html' queryset = Event.objects.all() context = { "object_list": queryset } return render(request, template_name, context) ``` 2. Mengubah file urls.py ``` from django.conf.urls import url from django.contrib import admin from django.views.generic import TemplateView from events.views import events_listview urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', TemplateView.as_view(template_name='home.html')), url(r'^events/$', events_listview), url(r'^about/$', TemplateView.as_view(template_name='about.html')), url(r'^content/$', TemplateView.as_view(template_name='content.html')), ] ``` 4. Mengisi file event_list.html ``` {% extends "base.html" %} {% block head_tittle %}Events || {{ block.super }}{% endblock head_tittle %} {% block content %} <h1>Events List</h1> <ul> {% for obj in object_list %} <li>{{ obj }} <br/> {{ obj.name }} by {{ obj.artist }} as a {{ obj.category }} at {{ obj.location }} held on {{ obj.Event_date }}; added on: {{ obj.timestamp }}; editted on:{{ obj.update }}.</li> {% endfor %} </ul> {% endblock %} ``` 5. Mengubah file models.py ``` from django.db import models class Event(models.Model): name = models.CharField(max_length=120) artist = models.CharField(max_length=120) category = models.CharField(max_length=120) location = models.CharField(max_length=120, null=True, blank=True) Event_date = models.DateField(auto_now=False, auto_now_add=False) timestamp = models.DateTimeField(auto_now=True) update = models.DateTimeField(auto_now_add=True) def __str__(self): return self.name ``` 6. Akses melalui browser ![Screenshot 2024-03-27 230449](https://hackmd.io/_uploads/BJU2j-N10.png) ### **4. Understanding QuerySets** Queryset digunakan untuk berinteraksi dengan data dalam database. Dengan ini, pengguna dapat membuat, memfilter, dan memanipulasi queryset untuk mendapatkan data yang diinginkan dari database. 1. Menjalankan shell python ``` python manage.py shell ``` 2. Melihat database ``` >>> from events.models import Event >>> Event.objects.all() <QuerySet [<Event: BLOOM>, <Event: SU:HOME>, <Event: LONSDALEITE>]> >>> for obj in Event.objects.all(): ... print(obj.name) ... BLOOM SU:HOME LONSDALEITE ``` ![Screenshot 2024-03-27 231525](https://hackmd.io/_uploads/S19aibVk0.png) 3. Melihat database dengan filter ``` >>> qs = Event.objects.all() >>> qs.filter(category__iexact='Fancon') <QuerySet [<Event: BLOOM>]> >>> qs.filter(category__iexact='Concert') <QuerySet [<Event: SU:HOME>, <Event: LONSDALEITE>]> ``` ![Screenshot 2024-03-27 232127](https://hackmd.io/_uploads/BJ9CobNyC.png) 4. Mengupdate database ``` >>> qs.update(category='Fancon') 3 >>> qs.filter(category__iexact='Concert') <QuerySet []> >>> qs.filter(category__iexact='Fancon') <QuerySet [<Event: BLOOM>, <Event: SU:HOME>, <Event: LONSDALEITE>]> ``` ![Screenshot 2024-03-27 232135](https://hackmd.io/_uploads/SkQk2Z4kA.png) 5. Menambahkan objek ``` >>> obj = Event() >>> obj.name = "Saranghaeyo Indonesia" >>> obj.artist = "Xiumin, Chen" >>> obj.category = "Event" >>> obj.location = "Jakarta Utara" >>> obj.Event_date = "2024-05-04" >>> obj.save() >>> qs <QuerySet [<Event: BLOOM>, <Event: SU:HOME>, <Event: LONSDALEITE>, <Event: Saranghaeyo Indonesia>]> ``` ![Screenshot 2024-03-27 232850](https://hackmd.io/_uploads/BkFyh-E1R.png) lihat melaui ListView: ![Screenshot 2024-03-27 232909](https://hackmd.io/_uploads/HJ-e3-EkC.png) 6. Membuat queryset2 dengan filter ``` >>> qs = Event.objects.all() >>> qs <QuerySet [<Event: BLOOM>, <Event: SU:HOME>, <Event: LONSDALEITE>, <Event: Saranghaeyo Indonesia>]> >>> qs2 = Event.objects.filter(category__iexact='Fancon') >>> qs2 <QuerySet [<Event: BLOOM>, <Event: SU:HOME>, <Event: LONSDALEITE>]> >>> qs.exist() Traceback (most recent call last): File "<console>", line 1, in <module> AttributeError: 'QuerySet' object has no attribute 'exist' >>> qs.exists() True >>> qs <QuerySet [<Event: BLOOM>, <Event: SU:HOME>, <Event: LONSDALEITE>, <Event: Saranghaeyo Indonesia>]> ``` ![Screenshot 2024-03-27 233455](https://hackmd.io/_uploads/rJOX3bE10.png) 7. membuat objek tambahan dalam satu line ``` >>> obj = Event.objects.create(name='The Eternity', artist= 'Chanyeol', category='Fancon', location='Jakarta', Event_date='2024-03-09') >>> qs = Event.objects.all() >>> qs <QuerySet [<Event: BLOOM>, <Event: SU:HOME>, <Event: LONSDALEITE>, <Event: Saranghaeyo Indonesia>, <Event: The Eternity>]> ``` ![Screenshot 2024-03-27 233928](https://hackmd.io/_uploads/Hk1V2-N1R.png) 8. Filter data dengan exclude ``` >>> qs = Event.objects.filter(category__iexact='Fancon').exclude(name__icontains='BLOOM') >>> qs <QuerySet [<Event: SU:HOME>, <Event: LONSDALEITE>, <Event: The Eternity>]> >>> qs = Event.objects.all() >>> qs <QuerySet [<Event: BLOOM>, <Event: SU:HOME>, <Event: LONSDALEITE>, <Event: Saranghaeyo Indonesia>, <Event: The Eternity>]> >>> qs = Event.objects.filter(category__iexact='Fancon') >>> qs <QuerySet [<Event: BLOOM>, <Event: SU:HOME>, <Event: LONSDALEITE>, <Event: The Eternity>]> ``` ![Screenshot 2024-03-27 234156](https://hackmd.io/_uploads/rkTH2WVJ0.png) ### **5. Generic List View** Dalam hal ini, ialah menampilkan daftar objek dari suatu model dalam bentuk daftar yang diambil dari database. - Memfilter dengan menambahkan class baru 1. Mengubah isi file views.py ``` from django.http import HttpResponse from django.shortcuts import render from django.views import View from django.views.generic import TemplateView, ListView from .models import Event def events_listview(request): template_name = 'events/events_list.html' queryset = Event.objects.all() context = { "object_list": queryset } return render(request, template_name, context) class EventListView(ListView): queryset = Event.objects.all() template_name = 'events/events_list.html' class FanconEventListView(ListView): queryset = Event.objects.filter(category__iexact='Fancon') template_name = 'events/events_list.html' class ConcertEventListView(ListView): queryset = Event.objects.filter(category__iexact='Concert') template_name = 'events/events_list.html' class EventEventListView(ListView): queryset = Event.objects.filter(category__iexact='Event') template_name = 'events/events_list.html' ``` 2. Mengubah isi file urls.py ``` from django.conf.urls import url from django.contrib import admin from django.views.generic import TemplateView from events.views import ( events_listview, EventListView, FanconEventListView, ConcertEventListView, EventEventListView, ) urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', TemplateView.as_view(template_name='home.html')), url(r'^events/$', EventListView.as_view()), url(r'^events/fancon$', FanconEventListView.as_view()), url(r'^events/concert$', ConcertEventListView.as_view()), url(r'^events/event$', EventEventListView.as_view()), url(r'^about/$', TemplateView.as_view(template_name='about.html')), url(r'^content/$', TemplateView.as_view(template_name='content.html')), ] ``` 3. Cek melalui browser ![Screenshot 2024-03-28 114448](https://hackmd.io/_uploads/HJD8nb4J0.png) ![Screenshot 2024-03-28 115119](https://hackmd.io/_uploads/BylO3b4yC.png) - Memfilter dengan QuerySet 1. Mengubah isi file views.py ``` from django.db.models import Q from django.http import HttpResponse from django.shortcuts import render from django.views import View from django.views.generic import TemplateView, ListView from .models import Event def events_listview(request): template_name = 'events/templates/events/events_list.html' queryset = Event.objects.all() context = { "object_list": queryset } return render(request, template_name, context) class EventListView(ListView): template_name = 'events/events_list.html' def get_queryset(self): slug = self.kwargs.get("slug") if slug: queryset = Event.objects.filter( Q(category__iexact=slug) | Q(category__icontains=slug) ) else: queryset = Event.objects.all() return queryset ``` 2. Mengubah isi file urls.py ``` from django.conf.urls import url from django.contrib import admin from django.views.generic import TemplateView from events.views import ( events_listview, EventListView, ) urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', TemplateView.as_view(template_name='home.html')), url(r'^events/$', EventListView.as_view()), url(r'^events/(?P<slug>\w+)/$', EventListView.as_view()), url(r'^about/$', TemplateView.as_view(template_name='about.html')), url(r'^content/$', TemplateView.as_view(template_name='content.html')), ] ``` 3. Cek melalui browser ![Screenshot 2024-03-28 115119](https://hackmd.io/_uploads/S1Pon-4JA.png) filter pada Fancon: ![Screenshot 2024-03-28 115139](https://hackmd.io/_uploads/HkVi2ZNJA.png) filter pada Event: ![Screenshot 2024-03-28 115158](https://hackmd.io/_uploads/Hy4TnZ4y0.png) filter pada Concert: ![Screenshot 2024-03-28 115221](https://hackmd.io/_uploads/SkykTbE1C.png) --- ### **6. Profile Detail** DetailView berfungsi untuk menampilkan detail dari satu objek model. Misalnya menampilkan detail dari satu detail produk dalam toko. 1. Mengedit file event_detail.html di dalam direktori /events/templates/events/ ``` {% extends "base.html" %} {% block head_tittle %}Event || {{ block.super }}{% endblock head_tittle %} {% block content %} <h1>{{ object.name }} <small> {{ object.artist }}</small></h1> <p>Category: {{ object.category }}</p> <p>Location: {{ object.location }}</p> <p>Held on : {{ object.Event_date }}</p> <p>Add on : {{ object.timestamp }}, Updated {{ object.update|timesince }} ago</p> {% endblock %} ``` 2. Mengedit file views.py ``` from django.db.models import Q from django.http import HttpResponse from django.shortcuts import render from django.views import View from django.views.generic import TemplateView, ListView, DetailView from .models import Event def events_listview(request): template_name = 'events/event_list.html' queryset = Event.objects.all() context = { "object_list": queryset } return render(request, template_name, context) class EventListView(ListView): def get_queryset(self): slug = self.kwargs.get("slug") if slug: queryset = Event.objects.filter( Q(category__iexact=slug) | Q(category__icontains=slug) ) else: queryset = Event.objects.all() return queryset class EventDetailView(DetailView): queryset = Event.objects.all() def get_context_data(self, *args, **kwargs): print(self.kwargs) context = super(EventDetailView, self).get_context_data(*args, **kwargs) print(context) return context ``` 3. Mengedit file urls.py ``` from django.conf.urls import url from django.contrib import admin from django.views.generic import TemplateView from events.views import ( events_listview, EventListView, EventDetailView, ) urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', TemplateView.as_view(template_name='home.html')), url(r'^events/$', EventListView.as_view()), url(r'^events/(?P<pk>\w+)/$', EventDetailView.as_view()), url(r'^about/$', TemplateView.as_view(template_name='about.html')), url(r'^content/$', TemplateView.as_view(template_name='content.html')), ] ``` 4. Cek melalui browser ![Screenshot 2024-03-29 080408](https://hackmd.io/_uploads/SJFXabNyA.png) ### **7. SlugField & Unique Slug Generator** SlugField digunakan untuk menyimpan nilai yang dihasilkan dari judul atau teks lainnya, dimodifikasi agar sesuai untuk digunakan dalam URL. misalkan dengan mengubah huruf menjadi kecil sepenuhnya, dan mengubah spasi dengan tanda (-). 1. Mengubah file models.py ``` from django.db import models class Event(models.Model): name = models.CharField(max_length=120) artist = models.CharField(max_length=120) category = models.CharField(max_length=120) location = models.CharField(max_length=120, null=True, blank=True) Event_date = models.DateField(auto_now=False, auto_now_add=False) timestamp = models.DateTimeField(auto_now=True) update = models.DateTimeField(auto_now_add=True) slug = models.SlugField(null=True, blank=True) def __str__(self): return self.name @property def title(self): return self.name ``` 2. Migrate ``` ``` ![Screenshot 2024-03-28 215152](https://hackmd.io/_uploads/By8PpWNkR.png) 4. Mengubah isi file views.py ``` from django.db.models import Q from django.http import HttpResponse from django.shortcuts import render, get_object_or_404 from django.views import View from django.views.generic import TemplateView, ListView, DetailView from .models import Event def events_listview(request): template_name = 'events/event_list.html' queryset = Event.objects.all() context = { "object_list": queryset } return render(request, template_name, context) class EventListView(ListView): def get_queryset(self): slug = self.kwargs.get("slug") if slug: queryset = Event.objects.filter( Q(category__iexact=slug) | Q(category__icontains=slug) ) else: queryset = Event.objects.all() return queryset class EventDetailView(DetailView): queryset = Event.objects.all() def get_object(self, *args, **kwargs): rest_id = self.kwargs.get('rest_id') obj = get_object_or_404(Event, id=rest_id) return obj ``` 3. Membuat file utils.py di dalam direktori events ``` import random import string from django.utils.text import slugify def random_string_generator(size=10, chars=string.ascii_lowercase + string.digits): return ''.join(random.choice(chars) for _ in range(size)) def unique_slug_generator(instance, new_slug=None): if new_slug is not None: slug = new_slug else: slug = slugify(instance.title) Klass = instance.__class__ qs_exists = Klass.objects.filter(slug=slug).exists() if qs_exists: new_slug = "{slug}-{randstr}".format(slug=slug, randstr=random_string_generator(size=4)) return unique_slug_generator(instance, new_slug=new_slug) return slug ``` 4. generate slug melalui python shell ``` python manage.py shell Python 3.8.2 (default, Mar 13 2020, 10:14:16) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> from events.models import Event >>> obj = Event.objects.get(id=1) >>> from events.utils import unique_slug_generator >>> print(unique_slug_generator(obj)) bloom ``` ![Screenshot 2024-03-29 081854](https://hackmd.io/_uploads/HyUdpZE1C.png) ### **8. Unique Slug with Signal** "Signal" digunakan untuk menanggapi peristiwa tertentu yang terjadi dalam aplikasi Django, seperti saat objek disimpan, diupdate, atau dihapus dari basis data. Signal pada objek dapat berperan untuk membuat slug, baik sebelum disimpan atau setelah disimpan. 1. Mengubah file models.py ``` from django.db import models from django.db.models.signals import pre_save, post_save from .utils import unique_slug_generator class Event(models.Model): name = models.CharField(max_length=120) artist = models.CharField(max_length=120) category = models.CharField(max_length=120) location = models.CharField(max_length=120, null=True, blank=True) Event_date = models.DateField(auto_now=False, auto_now_add=False) timestamp = models.DateTimeField(auto_now=True) update = models.DateTimeField(auto_now_add=True) slug = models.SlugField(null=True, blank=True) def __str__(self): return self.name @property def title(self): return self.name def rl_pre_save_receiver(sender, instance, *args, **kwargs): print("saving...") print(instance.timestamp) def rl_post_save_receiver(sender, instance, created, *args, **kwargs): print('saved') print(instance.timestamp) if not instance.slug: instance.slug = unique_slug_generator(instance) instance.save() pre_save.connect(rl_pre_save_receiver, sender=Event) post_save.connect(rl_post_save_receiver, sender=Event) ``` 2. Akses melalui browser ![Screenshot 2024-03-29 082626](https://hackmd.io/_uploads/Sk9tp-EyR.png) setelah diperbarui: ![Screenshot 2024-03-29 082641](https://hackmd.io/_uploads/B1Vq6-VyC.png) detail pada terminal: ![Screenshot 2024-03-29 082708](https://hackmd.io/_uploads/HkZiT-4yR.png) --- ## **Forms, Views, Models, and More** Dalam section ini, saya membuat forms, tampilan, detail, models, dan lain sebagainya yang akan menjadi database sekaligus logika UI yang menangani project yang saya buat. ### **1. Slugs as URL Params** Membuat slug, yang berfungsi sebagai parameter url dan membantu untuk mengarahkan url menuju object yang dimaksud. Yang mana, setiap object memiliki kode yang unik. 1. Ubah file views.py ``` from django.db.models import Q from django.http import HttpResponse from django.shortcuts import render, get_object_or_404 from django.views import View from django.views.generic import TemplateView, ListView, DetailView from .models import Event def events_listview(request): template_name = 'events/event_list.html' queryset = Event.objects.all() context = { "object_list": queryset } return render(request, template_name, context) class EventListView(ListView): def get_queryset(self): slug = self.kwargs.get("slug") if slug: queryset = Event.objects.filter( Q(category__iexact=slug) | Q(category__icontains=slug) ) else: queryset = Event.objects.all() return queryset class EventDetailView(DetailView): queryset = Event.objects.all() ``` 2. Ubah file urls.py ``` from django.conf.urls import url from django.contrib import admin from django.views.generic import TemplateView from events.views import ( events_listview, EventListView, EventDetailView, ) urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', TemplateView.as_view(template_name='home.html')), url(r'^events/$', EventListView.as_view()), url(r'^events/(?P<slug>[\w-]+)/$', EventDetailView.as_view()), url(r'^about/$', TemplateView.as_view(template_name='about.html')), url(r'^content/$', TemplateView.as_view(template_name='content.html')), ] ``` 3. Ubah file event_list.html ``` {% extends "base.html" %} {% block head_tittle %}Events || {{ block.super }}{% endblock head_tittle %} {% block content %} <h1>Events List</h1> <ul> {% for obj in object_list %} <li><a href="/events/{{ obj.slug }}/">{{ obj }}</a><br/> {{ obj.name }} by {{ obj.artist }} as a {{ obj.category }} at {{ obj.location }} held on {{ obj.Event_date }}; added on: {{ obj.timestamp }}; editted on:{{ obj.update }}.</li> {% endfor %} </ul> {% endblock %} ``` 4. Memastikan bahwa semua object event telah generate slug 5. Cek melalui browser ![Screenshot 2024-03-29 083848](https://hackmd.io/_uploads/S1In6WVJC.png) ![Screenshot 2024-03-29 084209](https://hackmd.io/_uploads/rkp3TbEJR.png) ### **2. Get Single Items from DB** Ialah cara untuk melihat suatu object secara spesifik yang diambil dari database dengan parameter tertentu, sesuai yang dibutuhkan. 1. Akses python shell ``` python manage.py shell ``` 2. cek items melalui qs all ``` >>> from events.models import Event >>> qs = Event.objects.all() >>> qs <QuerySet [<Event: BLOOM>, <Event: SU:HOME>, <Event: LONSDALEITE>, <Event: Saranghaeyo Indonesia>, <Event: The Eternity>]> >>> qs[1] <Event: SU:HOME> >>> qs.last() <Event: The Eternity> ``` ![Screenshot 2024-03-29 084731](https://hackmd.io/_uploads/rJppa-4kC.png) 3. Cek items melalui qs filter category ``` >>> qs = Event.objects.filter(category__iexact='Concert') >>> qs <QuerySet [<Event: LONSDALEITE>]> >>> qs.last() <Event: LONSDALEITE> ``` ![Screenshot 2024-03-29 085034](https://hackmd.io/_uploads/rkE0pZEk0.png) 3. Lakukan get items dengan pk ``` >>> Event.objects.get(pk=1) <Event: BLOOM> >>> obj = Event.objects.get(pk=1) >>> obj.pk 1 >>> obj = Event.objects.get(pk=78) Traceback (most recent call last): File "<console>", line 1, in <module> File "/home/ubuntu/Dev/trydjango-1.11/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "/home/ubuntu/Dev/trydjango-1.11/lib/python3.8/site-packages/django/db/models/query.py", line 378, in get raise self.model.DoesNotExist( events.models.DoesNotExist: Event matching query does not exist. >>> ``` ![Screenshot 2024-03-29 085347](https://hackmd.io/_uploads/Skfk0WV1R.png) 4. Ubah file views.py ``` from django.db.models import Q from django.http import HttpResponse from django.shortcuts import render, get_object_or_404 from django.views import View from django.views.generic import TemplateView, ListView, DetailView from .models import Event def events_listview(request): template_name = 'events/event_list.html' queryset = Event.objects.all() context = { "object_list": queryset } return render(request, template_name, context) def events_detailview(request, slug): template_name = 'events/event_detail.html' obj = Event.objects.get(slug=slug) context = { "object": obj } return render(request, template_name, context) class EventListView(ListView): def get_queryset(self): slug = self.kwargs.get("slug") if slug: queryset = Event.objects.filter( Q(category__iexact=slug) | Q(category__icontains=slug) ) else: queryset = Event.objects.all() return queryset class EventDetailView(DetailView): queryset = Event.objects.all() ``` 5. Mengambil item dengan get_object_or_404 melalui slug ``` >>> from django.shortcuts import render, get_object_or_404 >>> obj = get_object_or_404(Event, slug='lonsdaleite') >>> obj <Event: LONSDALEITE> >>> obj = get_object_or_404(Event, slug='lonsdaleite-') Traceback (most recent call last): File "/home/ubuntu/Dev/trydjango-1.11/lib/python3.8/site-packages/django/shortcuts.py", line 85, in get_object_or_404 return queryset.get(*args, **kwargs) File "/home/ubuntu/Dev/trydjango-1.11/lib/python3.8/site-packages/django/db/models/query.py", line 378, in get raise self.model.DoesNotExist( events.models.DoesNotExist: Event matching query does not exist. During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<console>", line 1, in <module> File "/home/ubuntu/Dev/trydjango-1.11/lib/python3.8/site-packages/django/shortcuts.py", line 93, in get_object_or_404 raise Http404('No %s matches the given query.' % queryset.model._meta.object_name) django.http.response.Http404: No Event matches the given query. ``` ![Screenshot 2024-03-29 090021](https://hackmd.io/_uploads/Bkp10bN1A.png) ### **3. Saving Data the Hard + Wrong Way** Terlalu riskan untuk memberikan akses admin kepada pengguna akhir web. Untuk itu diperlukan cara dalam mengekstrak data yang dimasukkan oleh users terdaftar. Disini, saya menggunakan POST method. 1. Membuat file forms.py di dalam direktori events dan mengubahnya ``` touch events/forms.py ... from django import forms class EventCreateForm(forms.Form): name = forms.CharField(max_length=120) artist = forms.CharField(max_length=120) category = forms.CharField(max_length=120) location = forms.CharField(max_length=120) Event_date = forms.DateField() ... ``` 2. Membuat file form.html di dalam direktori /events/templates/events/form.html dan mengubahnya ``` touch /events/templates/events/form.html ... {% extends "base.html" %} {% block head_tittle %}Add Event || {{ block.super }}{% endblock head_tittle %} {% block content %} <h1>Add Event</h1> <form method='POST'> {% csrf_token %} <input type='text' name='name' placeholder="Event Name"><br/> <input type='text' name='artist' placeholder="Artist"><br/> <input type='text' name='category' placeholder="Category"><br/> <input type='text' name='location' placeholder="Location"><br/> <input type='date' name='Event_date' placeholder="Event Date"><br/> <button type='submit'>Save</button> </form> {% endblock %} ... ``` 3. Mengubah file views.py ``` from django.db.models import Q from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render, get_object_or_404 from django.views import View from django.views.generic import TemplateView, ListView, DetailView from .forms import EventCreateForm from .models import Event def event_createview(request): if request.method == "POST": name = request.POST.get("name") artist = request.POST.get("artist") category = request.POST.get("category") location = request.POST.get("location") Event_date = request.POST.get("Event_date") obj = Event.objects.create( name = name, artist = artist, category = category, location =location, Event_date = Event_date ) return HttpResponseRedirect("/events/") template_name = 'events/form.html' context = {} return render(request, template_name, context) def events_listview(request): template_name = 'events/event_list.html' queryset = Event.objects.all() context = { "object_list": queryset } return render(request, template_name, context) def events_detailview(request, slug): template_name = 'events/event_detail.html' obj = Event.objects.get(slug=slug) context = { "object": obj } return render(request, template_name, context) class EventListView(ListView): def get_queryset(self): slug = self.kwargs.get("slug") if slug: queryset = Event.objects.filter( Q(category__iexact=slug) | Q(category__icontains=slug) ) else: queryset = Event.objects.all() return queryset class EventDetailView(DetailView): queryset = Event.objects.all() ``` atau dengan lebih singkatnya, ubah bagian event_createview menjadi sebagaimana berikut: ``` def event_createview(request): if request.method == "POST": form = EventCreateForm(request.POST) if form.is_valid(): obj = Event.objects.create( name = form.cleaned_data.get('name'), artist = form.cleaned_data.get('artist'), category = form.cleaned_data.get('category'), location =form.cleaned_data.get('location'), Event_date = form.cleaned_data.get('Event_date') ) return HttpResponseRedirect("/events/") if form.errors: print(form.errors) template_name = 'events/form.html' context = {} return render(request, template_name, context) ``` 4. Mengubah file utils.py agar slug dapat terbuat otomatis setelah submit forms ``` import random import string from django.utils.text import slugify DONT_USE = ['create'] def random_string_generator(size=10, chars=string.ascii_lowercase + string.digits): return ''.join(random.choice(chars) for _ in range(size)) def unique_slug_generator(instance, new_slug=None): if new_slug is not None: slug = new_slug else: slug = slugify(instance.title) if slug in DONT_USE: new_slug = "{slug}-{randstr}".format( slug=slug, randstr=random_string_generator(size=4) ) return unique_slug_generator(instance, new_slug=new_slug) Klass = instance.__class__ qs_exists = Klass.objects.filter(slug=slug).exists() if qs_exists: new_slug = "{slug}-{randstr}".format( slug=slug, randstr=random_string_generator(size=4) ) return unique_slug_generator(instance, new_slug=new_slug) return slug ``` 5. Mengubah file urls.py ``` from django.conf.urls import url from django.contrib import admin from django.views.generic import TemplateView from events.views import ( events_listview, EventListView, EventDetailView, event_createview ) urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', TemplateView.as_view(template_name='home.html')), url(r'^events/$', EventListView.as_view()), url(r'^events/create/$', event_createview), url(r'^events/(?P<slug>[\w-]+)/$', EventDetailView.as_view()), url(r'^about/$', TemplateView.as_view(template_name='about.html')), url(r'^content/$', TemplateView.as_view(template_name='content.html')), ] ``` 6. Cek melalui browser ![Screenshot 2024-03-29 100405](https://hackmd.io/_uploads/B1emRbV1A.png) ![Screenshot 2024-03-29 100416](https://hackmd.io/_uploads/Hk8XAZEy0.png) atau gunakan cara yang lebih simple dengan: 1. Mengubah file views.py ``` class EventCreateViewfast(CreateView): form_class = EventCreateFormfast template_name = 'events/form.html' success_url = "/events/" ``` ### **4. Validating Form** Ketika ada entri yang dilarang, maka form secara otomatis memperlihatkan kesalahan dan tidak menginput object yang dimasukkan 1. Mengubah file views.ps ``` from django.db.models import Q from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render, get_object_or_404 from django.views import View from django.views.generic import TemplateView, ListView, DetailView from .forms import EventCreateForm from .models import Event def event_createview(request): form = EventCreateForm(request.POST or None) errors = None if form.is_valid(): obj = Event.objects.create( name = form.cleaned_data.get('name'), artist = form.cleaned_data.get('artist'), category = form.cleaned_data.get('category'), location = form.cleaned_data.get('location'), Event_date = form.cleaned_data.get('Event_date') ) return HttpResponseRedirect("/events/") if form.errors: errors = form.errors template_name = 'events/form.html' context = {"form": form, "errors": errors} return render(request, template_name, context) def events_listview(request): template_name = 'events/event_list.html' queryset = Event.objects.all() context = { "object_list": queryset } return render(request, template_name, context) def events_detailview(request, slug): template_name = 'events/event_detail.html' obj = Event.objects.get(slug=slug) context = { "object": obj } return render(request, template_name, context) class EventListView(ListView): def get_queryset(self): slug = self.kwargs.get("slug") if slug: queryset = Event.objects.filter( Q(category__iexact=slug) | Q(category__icontains=slug) ) else: queryset = Event.objects.all() return queryset class EventDetailView(DetailView): queryset = Event.objects.all() ``` 2. Mengubah file forms.py ``` from django import forms class EventCreateForm(forms.Form): name = forms.CharField(max_length=120) artist = forms.CharField(max_length=120) category = forms.CharField(max_length=120) location = forms.CharField(max_length=120) Event_date = forms.DateField() def clean_name(self): name = self.cleaned_data.get("name") if name == "hate": raise forms.ValidationError("we don't need a war anymore") return name ``` 3. mengubah file form.html ``` {% extends "base.html" %} {% block head_tittle %}Add Event || {{ block.super }}{% endblock head_tittle %} {% block content %} <h1>Add Event</h1> {% if errors %} {{ errors }} {% endif %} <form method='POST'> {% csrf_token %} {{ form.as_p }} <button type='submit'>Save</button> </form> {% endblock %} ``` 4. Cek melalui browser ![Screenshot 2024-03-29 104130](https://hackmd.io/_uploads/H13gkf4y0.png) atau dengan cara yang lebih efektif 1. Mengubah file views.py ``` from django.db.models import Q from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render, get_object_or_404 from django.views import View from django.views.generic import TemplateView, ListView, DetailView from .forms import EventCreateFormfast from .models import Event def events_listview(request): template_name = 'events/event_list.html' queryset = Event.objects.all() context = { "object_list": queryset } return render(request, template_name, context) def events_detailview(request, slug): template_name = 'events/event_detail.html' obj = Event.objects.get(slug=slug) context = { "object": obj } return render(request, template_name, context) class EventListView(ListView): def get_queryset(self): slug = self.kwargs.get("slug") if slug: queryset = Event.objects.filter( Q(category__iexact=slug) | Q(category__icontains=slug) ) else: queryset = Event.objects.all() return queryset class EventDetailView(DetailView): queryset = Event.objects.all() class EventCreateViewfast(CreateView): form_class = EventCreateFormfast template_name = 'events/form.html' success_url = "/events/" ``` 2. Mengubah file forms.py ``` from django import forms from .models import Event class EventCreateFormfast(forms.ModelForm): class Meta: model = Event fields = [ 'name', 'artist', 'category', 'location', 'Event_date', ] def clean_name(self): name = self.cleaned_data.get("name") if name == "hate": raise forms.ValidationError("we don't need a war anymore") return name ``` 3. Mengubah file urls.py ``` from django.conf.urls import url from django.contrib import admin from django.views.generic import TemplateView from events.views import ( events_listview, EventListView, EventDetailView, event_createview, EventCreateViewfast ) urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', TemplateView.as_view(template_name='home.html')), url(r'^events/$', EventListView.as_view()), url(r'^events/create/$', EventCreateViewfast.as_view()), url(r'^events/(?P<slug>[\w-]+)/$', EventDetailView.as_view()), url(r'^about/$', TemplateView.as_view(template_name='about.html')), url(r'^content/$', TemplateView.as_view(template_name='content.html')), ] ``` 4. Cek melalui browser ![Screenshot 2024-03-29 111002](https://hackmd.io/_uploads/HkUWyM41R.png) ### **5. Simple + Effective Validation** 1. Membuat file validators.py di dalam direktori events ``` touch /events/validators.py ... from django.core.exceptions import ValidationError def validate_even(value): if value % 2 != 0: raise ValidationError( '%(value)s is not an even number', params={'value': value}, ) def validate_name(value): name = value if name == "hate": raise ValidationError("we don't need a war anymore") CATEGORIES = {'Fancon', 'Concert', 'Fanmeet', 'Event', 'Promotion', 'Variety'} def validate_category(value): cat = value.capitalize() if not value in CATEGORIES and not cat in CATEGORIES: raise ValidationError(f"{value} not a valid category") ... ``` 2. Mengubah file forms.py ``` from django import forms from .models import Event class EventCreateFormfast(forms.ModelForm): class Meta: model = Event fields = [ 'name', 'artist', 'category', 'location', 'Event_date', ] ``` 3. Mengubah file form.html ``` {% extends "base.html" %} {% block head_tittle %}Add Event || {{ block.super }}{% endblock head_tittle %} {% block content %} <h1>Add Event</h1> {% if form.errors.non_field_errors %} {{ form.errors.non_field_errors }} {% endif %} <form method='POST'> {% csrf_token %} {{ form.as_p }} <button type='submit'>Save</button> </form> {% endblock %} ``` 4. Mengubah file models.py ``` from django.db import models from django.db.models.signals import pre_save, post_save from .utils import unique_slug_generator from .validators import ( validate_category, validate_name, ) class Event(models.Model): name = models.CharField(max_length=120, validators=[validate_name]) artist = models.CharField(max_length=120) category = models.CharField(max_length=120, validators=[validate_category]) location = models.CharField(max_length=120, null=True, blank=True) Event_date = models.DateField(auto_now=False, auto_now_add=False) timestamp = models.DateTimeField(auto_now=True) update = models.DateTimeField(auto_now_add=True) slug = models.SlugField(null=True, blank=True) def __str__(self): return self.name @property def title(self): return self.name def rl_pre_save_receiver(sender, instance, *args, **kwargs): instance.category = instance.category.capitalize() if not instance.slug: instance.slug = unique_slug_generator(instance) pre_save.connect(rl_pre_save_receiver, sender=Event) ``` 5. Melakukan migrate ``` python manage.py makemigrations python manage.py migrate ``` ![Screenshot 2024-03-29 114749](https://hackmd.io/_uploads/SJkMJzNJA.png) 6. Cek melalui browser ![Screenshot 2024-03-29 114803](https://hackmd.io/_uploads/HkUXyfVk0.png) ![Screenshot 2024-03-29 115055](https://hackmd.io/_uploads/HyK71fVk0.png) sekaligus menjadi tidak sensitif dengan huruf kapital pada category: ![Screenshot 2024-03-29 115115](https://hackmd.io/_uploads/H1nQ1MNJC.png) ### **6. Letting Users own Data** Ialah memetakan object tertentu/ yang ditambahkan ke spesifik user. 1. Ubah file models.py ``` User = settings.AUTH_USER_MODEL class Event(models.Model): owner = models.ForeignKey(User) ``` 2. Migrate ``` python manage.py makemigrations python manage.py migrate ``` ![Screenshot 2024-03-29 122321](https://hackmd.io/_uploads/HyiHkG4yA.png) 3. Cek melalui browser ![Screenshot 2024-03-29 122418](https://hackmd.io/_uploads/r1bwJGEJA.png) 4. Akses python shell dan jalankan get_user_model ``` python manage.py shell Python 3.8.2 (default, Mar 13 2020, 10:14:16) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> from django.contrib.auth import get_user_model >>> User = get_user_model() >>> User.objects.all() <QuerySet [<User: ubuntu>, <User: syafaa>]> >>> ubuntu_user = User.objects.get(id=1) >>> ubuntu_user.username 'ubuntu' >>> ubuntu_user.event_set.all() <QuerySet [<Event: BLOOM>, <Event: SU:HOME>, <Event: LONSDALEITE>, <Event : Saranghaeyo Indonesia>, <Event: The Eternity>, <Event: Scarlett x EXO : Glow to You>, <Event: EXO Ladder Season 4>]> >>> syafaa_user = User.objects.get(id=2) >>> syafaa_user.event_set.all() <QuerySet []> ``` ![Screenshot 2024-03-29 123106](https://hackmd.io/_uploads/Hkvw1GEkA.png) a. Users in FBV 1. Ubah file views.py ``` from django.db.models import Q from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render, get_object_or_404 from django.views import View from django.views.generic import TemplateView, ListView, DetailView, CreateView from .forms import EventCreateFormfast from .models import Event def event_createview(request): form = EventCreateFormfast(request.POST or None) errors = None if form.is_valid(): if request.user.is_authenticated(): instance = form.save(commit=False) instance.owner = request.user form.save() return HttpResponseRedirect("/events/") else: return HttpResponseRedirect("/login/") if form.errors: errors = form.errors template_name = 'events/form.html' context = {"form": form, "errors": errors} return render(request, template_name, context) def events_listview(request): template_name = 'events/event_list.html' queryset = Event.objects.all() context = { "object_list": queryset } return render(request, template_name, context) def events_detailview(request, slug): template_name = 'events/event_detail.html' obj = Event.objects.get(slug=slug) context = { "object": obj } return render(request, template_name, context) class EventListView(ListView): def get_queryset(self): slug = self.kwargs.get("slug") if slug: queryset = Event.objects.filter( Q(category__iexact=slug) | Q(category__icontains=slug) ) else: queryset = Event.objects.all() return queryset class EventDetailView(DetailView): queryset = Event.objects.all() class EventCreateViewfast(CreateView): form_class = EventCreateFormfast template_name = 'events/form.html' success_url = "/events/" ``` 2. Ubah file urls.py ``` from django.conf.urls import url from django.contrib import admin from django.views.generic import TemplateView from events.views import ( events_listview, EventListView, EventDetailView, event_createview, EventCreateViewfast ) urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', TemplateView.as_view(template_name='home.html')), url(r'^events/$', EventListView.as_view()), url(r'^events/create/$', event_createview), url(r'^events/(?P<slug>[\w-]+)/$', EventDetailView.as_view()), url(r'^about/$', TemplateView.as_view(template_name='about.html')), url(r'^content/$', TemplateView.as_view(template_name='content.html')), ] ``` 3. Akses melalui web tanpa login user ![Screenshot 2024-03-29 124641](https://hackmd.io/_uploads/H1IoJfEkC.png) b. User in CBV 1. Ubah file views.py ``` from django.db.models import Q from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render, get_object_or_404 from django.views import View from django.views.generic import TemplateView, ListView, DetailView, CreateView from .forms import EventCreateFormfast from .models import Event def event_createview(request): form = EventCreateFormfast(request.POST or None) errors = None if form.is_valid(): if request.user.is_authenticated(): instance = form.save(commit=False) instance.owner = request.user form.save() return HttpResponseRedirect("/events/") else: return HttpResponseRedirect("/login/") if form.errors: errors = form.errors template_name = 'events/form.html' context = {"form": form, "errors": errors} return render(request, template_name, context) def events_listview(request): template_name = 'events/event_list.html' queryset = Event.objects.all() context = { "object_list": queryset } return render(request, template_name, context) def events_detailview(request, slug): template_name = 'events/event_detail.html' obj = Event.objects.get(slug=slug) context = { "object": obj } return render(request, template_name, context) class EventListView(ListView): def get_queryset(self): slug = self.kwargs.get("slug") if slug: queryset = Event.objects.filter( Q(category__iexact=slug) | Q(category__icontains=slug) ) else: queryset = Event.objects.all() return queryset class EventDetailView(DetailView): queryset = Event.objects.all() class EventCreateViewfast(CreateView): form_class = EventCreateFormfast template_name = 'events/form.html' success_url = "/events/" def form_valid(self, form): instance = form.save(commit=False) instance.owner = self.request.user return super(EventCreateViewfast, self).form_valid(form) ``` 2. Ubah file urls.py ``` from django.conf.urls import url from django.contrib import admin from django.views.generic import TemplateView from events.views import ( events_listview, EventListView, EventDetailView, event_createview, EventCreateViewfast ) urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', TemplateView.as_view(template_name='home.html')), url(r'^events/$', EventListView.as_view()), url(r'^events/create/$', EventCreateViewfast.as_view()), url(r'^events/(?P<slug>[\w-]+)/$', EventDetailView.as_view()), url(r'^about/$', TemplateView.as_view(template_name='about.html')), url(r'^content/$', TemplateView.as_view(template_name='content.html')), ] ``` ### **7. Login View** Untuk meastikan keamanan object yang ditambahkan oleh pengguna, maka untuk mengakses object-object tersebut diperlukan masuk ke dalam users yang terdaftar. 1. Edit file views.py ``` from django.db.models import Q from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import LoginRequiredMixin from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render, get_object_or_404 from django.views import View from django.views.generic import TemplateView, ListView, DetailView, CreateView from .forms import EventCreateFormfast from .models import Event @login_required() def events_listview(request): template_name = 'events/event_list.html' queryset = Event.objects.all() context = { "object_list": queryset } return render(request, template_name, context) def events_detailview(request, slug): template_name = 'events/event_detail.html' obj = Event.objects.get(slug=slug) context = { "object": obj } return render(request, template_name, context) class EventListView(ListView): def get_queryset(self): slug = self.kwargs.get("slug") if slug: queryset = Event.objects.filter( Q(category__iexact=slug) | Q(category__icontains=slug) ) else: queryset = Event.objects.all() return queryset class EventDetailView(DetailView): queryset = Event.objects.all() class EventCreateViewfast(LoginRequiredMixin, CreateView): form_class = EventCreateFormfast login_url = '/login/' template_name = 'events/form.html' success_url = "/events/" def form_valid(self, form): instance = form.save(commit=False) instance.owner = self.request.user return super(EventCreateViewfast, self).form_valid(form) ``` 2. Edit file urls.py ``` from django.conf.urls import url from django.contrib import admin from django.views.generic import TemplateView from events.views import ( events_listview, EventListView, EventDetailView, EventCreateViewfast ) from django.contrib.auth.views import LoginView urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', TemplateView.as_view(template_name='home.html')), url(r'^login/$', LoginView.as_view(), name='login'), url(r'^events/$', EventListView.as_view()), url(r'^events/create/$', EventCreateViewfast.as_view()), url(r'^events/(?P<slug>[\w-]+)/$', EventDetailView.as_view()), url(r'^about/$', TemplateView.as_view(template_name='about.html')), url(r'^content/$', TemplateView.as_view(template_name='content.html')), ] ``` 3. Membuat file login.html di dalam direktori /events/templates/registration/f ``` touch /events/templates/login.html ... {% extends "base.html" %} {% block content %} {% if form.errors %} <p>Your username and password didn't match. Please try again.</p> {% endif %} {% if next %} {% if user.is_authenticated %} <p>Your account doesn't have access to this page. To proceed, please login with an account that has access.</p> {% else %} <p>Please login to see this page.</p> {% endif %} {% endif %} <form method="post" action="{% url 'login' %}"> {% csrf_token %} {{ form.as_p }} <input type="submit" value="login"> <input type="hidden" name="next" value="{{ next }}"> </form> {% endblock %} ... ``` 4. cek melalui browser tanpa login user sebelum ditambahkan urls: ![Screenshot 2024-03-29 125455](https://hackmd.io/_uploads/Bktygf41R.png) setelah ditambahkan urls: ![Screenshot 2024-03-29 132344](https://hackmd.io/_uploads/BknklzVkA.png) ### **8. Using Revers for Shortcut Urls** Membuat shortcut url di dalam text untuk mempermudah users dalam mengakses aplikasi 1. Ubah file views.py ``` from django.db.models import Q from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import LoginRequiredMixin from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render, get_object_or_404 from django.views import View from django.views.generic import TemplateView, ListView, DetailView, CreateView from .forms import EventCreateFormfast from .models import Event @login_required() def events_listview(request): template_name = 'events/event_list.html' queryset = Event.objects.all() context = { "object_list": queryset } return render(request, template_name, context) def events_detailview(request, slug): template_name = 'events/event_detail.html' obj = Event.objects.get(slug=slug) context = { "object": obj } return render(request, template_name, context) class EventListView(ListView): def get_queryset(self): slug = self.kwargs.get("slug") if slug: queryset = Event.objects.filter( Q(category__iexact=slug) | Q(category__icontains=slug) ) else: queryset = Event.objects.all() return queryset class EventDetailView(DetailView): queryset = Event.objects.all() class EventCreateViewfast(LoginRequiredMixin, CreateView): form_class = EventCreateFormfast login_url = '/login/' template_name = 'events/form.html' success_url = "/events/" def form_valid(self, form): instance = form.save(commit=False) instance.owner = self.request.user return super(EventCreateViewfast, self).form_valid(form) class AboutView(TemplateView): template_name = 'about.html' class ContentView(TemplateView): template_name = 'content.html' ``` 2. Ubah file models.py ``` from django.db import models from django.conf import settings from django.db.models.signals import pre_save, post_save from .utils import unique_slug_generator from .validators import ( validate_category, validate_name, ) User = settings.AUTH_USER_MODEL class Event(models.Model): owner = models.ForeignKey(User) name = models.CharField(max_length=120, validators=[validate_name]) artist = models.CharField(max_length=120) category = models.CharField(max_length=120, validators=[validate_category]) location = models.CharField(max_length=120, null=True, blank=True) Event_date = models.DateField(auto_now=False, auto_now_add=False) timestamp = models.DateTimeField(auto_now=True) update = models.DateTimeField(auto_now_add=True) slug = models.SlugField(null=True, blank=True) def __str__(self): return self.name def get_absolute_url(self): return reverse('events:detail', kwargs={'slug': self.slug}) @property def title(self): return self.name def rl_pre_save_receiver(sender, instance, *args, **kwargs): instance.category = instance.category.capitalize() if not instance.slug: instance.slug = unique_slug_generator(instance) pre_save.connect(rl_pre_save_receiver, sender=Event) ``` 3. Membuat file urls.py di dalam direktori events ``` touch events/urls.py ... from django.conf.urls import url from events.views import ( EventListView, EventDetailView, EventCreateViewfast ) urlpatterns = [ url(r'^$', EventListView.as_view(), name='list'), url(r'^create/$', EventCreateViewfast.as_view(), name='create'), url(r'^(?P<slug>[\w-]+)/$', EventDetailView.as_view(), name='detail'), ] ... ``` 4. Ubah file urls.py di dalam direktori muypicky ``` from django.conf.urls import url, include from django.contrib import admin from django.views.generic import TemplateView from events.views import ( events_listview, EventListView, EventDetailView, EventCreateViewfast ) from django.contrib.auth.views import LoginView urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'), url(r'^login/$', LoginView.as_view(), name='login'), url(r'^events/', include('events.urls', namespace='events')), url(r'^about/$', TemplateView.as_view(template_name='about.html'), name='about'), url(r'^content/$', TemplateView.as_view(template_name='content.html'), name='content'), ] ``` 5. Ubah file nav.html ``` <div class='container'> <h1>EXO-l.com</h1> <a href='{% url "home" %}'>Home</a> <a href='{% url "about" %}'>About</a> <a href='{% url "content" %}'>Our Content</a> <a href='{% url "events:list" %}'>Events</a> </div> ``` 6. Ubah file event_list.html ``` {% extends "base.html" %} {% block head_tittle %}Events || {{ block.super }}{% endblock head_tittle %} {% block content %} <h1>Events List</h1> <ul> {% for obj in object_list %} <li><a href='{% url "events:detail" slug=obj.slug %}'>{{ obj }}</a><br/> {{ obj.name }} by {{ obj.artist }} as a {{ obj.category }} at {{ obj.location }} held on {{ obj.Event_date }}; added on: {{ obj.timestamp }}; editted on:{{ obj.update }}.</li> {% endfor %} </ul> {% endblock %} ``` 7. Cek melalui browser ![Screenshot 2024-03-29 140055](https://hackmd.io/_uploads/BkfLez4y0.png) saat masuk ke BLOOM: ![Screenshot 2024-03-29 140104](https://hackmd.io/_uploads/rkU8eG41A.png) saat kembali ke menu Home: ![Screenshot 2024-03-29 141159](https://hackmd.io/_uploads/S1OIxGEJ0.png) mengakses shortcut lain: ![Screenshot 2024-03-29 141208](https://hackmd.io/_uploads/S13Ulz4k0.png) #### :bulb: Access next documentation, that i have notice before, in **[TRY DJANGO 1.11 (Database & Logic UI)](https://hackmd.io/@syafaa/TryDjango2)**