Saturday, April 19, 2025

Membuat Aplikasi GUI Python dengan PyQt6


Membuat virtual environment

  • Dalam kasus ini akan menggunakan Anaconda, buka anaconda prompt
  • Cek virtual environment: conda env list
  • Buat virtual environment baru, misal dengan nama pyqt6_app: conda create --name pyqt6_app python=3.10
  • Aktifkan virtual environment: conda activate pyqt6_app
  • Jika ingin keluar dari VE: conda deactivate
  • Jika ingin menghapus VE: conda remove --name pyqt6_app --all


  • Install PyQt
  • install pyQt6: pip3 install pyqt6
  • Membuat Aplikasi Pertama
  • Buat folder kerja dengan nama pyqt6: mkdir pyqt6
  • Di folder pyt6, buat file dengan nama myapp.py, kemudian masukan kode:
  • from PyQt6.QtWidgets import QApplication, QWidget

  • #Only needed for access to command line arguments
  • import sys

  • #You need one (and only one) QApplication instance per application.
  • #Pass in sys.argv to allow command line arguments for your app.
  • #If you know you wan't use command line arguments Application([]) works too.
  • app = QApplication(sys.argv)

  • #Create a Qt widget, which will be our window.
  • window = QWidget()
  • window.show() #IMPORTANT!!! window will hidden by default.

  • #Start the event loop
  • app.exec()

  • #Your application won't reach here until you exit the event
  • #loop has stoped.
  • Jalankan aplikasi: python myapp.py

  • Maka akan dihasilkan window kosong seperti pada gambar diatas. Penjelasan dari kode adalah
  • from PyQt6.QtWidgets import QApplication, QWidget
  • Pertama kita import class PyQt6 yang dibutuhkan dalam aplikasi, yaitu import QApplication sebagai handler aplikasi, dan QWidget untuk tampilan widget kosong GUI dari modul QtWidgets.
  • Ada beberapa modul utama untuk Qt yang biasa digunakan yaitu QtWidgets, QtGUI, dan QtCore.
  • app = QApplication(sys.argv)
  • Selanjutnya buat instance dari QApplication, dengan passing perintah dalam sys.arg, yang berisi lisi perintah yang dikirim ke aplikasi. Jika kita tahu tidak akan kirim perintah maka bisa menusilkan app = QApplication([])
  • window = QWidget()
    window.show()
  • Selanjutnya membuat intstance dari QWidget menggunakan variabel yang bernama window. Dalam Qt top level widgets adalah window, dimana tidak punya parent dan tidak nested dengan widget atau layout yang lain. Perintah .show() digunakan untuk menampilkan window invisible. Kalau perintah .show() tidak diberikan maka aplikasi akan jalan namun tidak bisa di close.
  • app.exec()
  • Perintah untuk menjalankan event loop aplikasi.
  • Contoh lain kode sederhana dengan mengganti QtWidget dengan QPushButton untuk menampilkan button sederhana. Kodenya adalah seperti ini:
  • import sys

    from PyQt6.QtWidgets import QApplication, QPushButton

    app = QApplication(sys.argv)

    window = QPushButton("Tekan saya")
    window.show()

    app.exec()
  • Hasil dari kode diatas adalah tampilan window dengan satu buah button sederhana dengan tulisan "Tekan saya".

  • Membuat Tampilan dengan MainWindow
  • Dalam aplikasi kita tidak akan menggunakan hanya satu UI, maka diperlukan sebuah window yang dapat memuat beberapa kontor UI dalam tampilan window. Untuk masalah ini akan menggunakan QMainWindow merupakan sebuah widget yang dapat memuat fitur window lain seperti toolbar, menu, status bar, dockable widget dan lain sebagainya.
  • Untuk melakukan hal ini pada bagian atas kode program import QMainWindow.
  • #main_window.py
    #create by : wawanHN

    import sys

    from PyQt6.QtWidgets import QApplication, QMainWindow

    app = QApplication(sys.argv)

    window = QMainWindow()
    window.show() #Window secara default tidak ditampilkan

    app.exec()
  • Hasil dari kode diatas masih sama seperti pada Gambar 1, namun sebenarnya berbeda karena pada kode ini kita buat MainWindow yang akan bisa ditambahkan window widget-widget lain.
  • Kita coba MainWindow dengan menambahkan button.



  • Selanjutnya dengan MainWindow tambahkan button dan set ukuran window.
  • import sys
    from PyQt6.QtCore import QSize, Qt
    from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton

    # Subclass QMainWindow to customize your application's main window
    class MainWindow(QMainWindow):
    def __init__(self):
    super().__init__()
    self.setWindowTitle("My App")
    button = QPushButton("Klik saya!")
    self.setFixedSize(QSize(400, 300))

    # Set the central widget of the Window.
    self.setCentralWidget(button)

    app = QApplication(sys.argv)

    window = MainWindow()
    window.show()

    app.exec()
  • Maka akan menghasilkan window dengan ukuran 400 x 300

  • Signals dan Slots
  • Sejauh ini dalam kode-kode sebelumnya sudah membuat aplikasi menampilkan button, namun button tresebut tidak melakukan apapun. Biasanya dalam sebuah aplikasi ketika kita menambahkan button pasti akan melakukan suatu aksi, misal jika button tersebut di klik, yang dalam Qt dihasilkan dari Signal dan Slots. Signals merupakan notifikasi yang disampaikan oleh widget ketika sesuatu dijalankan. Misal angka, text atau apaoun ketika misal button di klik. Dan Slots merupakan bagian dari Qt yang menerima signals, dalam Python semua fungsi atau method dapat dikategorikan sebagai slots. Dalam contoh kode ini akan dibuat windows yang berisi button yang melakukan sesuatu ketika di klik, yaitu menampilkan text di console.
  • # signals_slots1.py

  • import sys
  • from PyQt6.QtWidgets import (
  • QApplication,
  • QMainWindow,
  • QPushButton,
  • )

  • class MainWindow(QMainWindow):
  • def __init__(self):
  • super().__init__()

  • self.setWindowTitle("My App")

  • button = QPushButton("Tekan saya")
  • button.setCheckable(True)
  • button.clicked.connect(self.button_telah_diklik)

  • #Set the central widget of the window.
  • self.setCentralWidget(button)

  • def button_telah_diklik(self):
  • print("Telah di klik")

  • app = QApplication(sys.argv)

  • window = MainWindow()
  • window.show()

  • app.exec()
  • Gunakan cls untuk membersihkan layar
  • ketikan perintah: python signals_slots1.py


  • Dari hasil kode yang dibuat akan menampilkan window yang terdiri dari sebuah button yang jika di kllik maka akan menampilkan tulisan "Telah di klik" di bagian console atau command prompt.
  • Selanjutkan bagaimana kalau menambahkan fungsi atau method saat button diklik akan menampilkan teks "Telah diklik" dan akan memberikan informasi status apakah button dalam posisi checked True atau False setelah button di klik.
  • #signals_slots2.py
    #created by wawanHN

    import sys
    from PyQt6.QtWidgets import (
    QApplication,
    QMainWindow,
    QPushButton,
    )

    class MainWindow(QMainWindow):
    def __init__(self):
    super().__init__()

    self.setWindowTitle("Aplikasi Signals Slot 2")
    self.setFixedSize(300, 200)

    button = QPushButton("Klik saya")
    button.setCheckable(True)
    button.clicked.connect(self.button_telah_diklik)
    button.clicked.connect(self.button_telah_beralih)

    #Set ditengah window
    self.setCentralWidget(button)

    def button_telah_diklik(self):
    print("Telah di klik")

    def button_telah_beralih(self, checked):
    print("Status checked?" , checked)

    app = QApplication(sys.argv)

    window = MainWindow()
    window.show()

    app.exec()
  • Hasil di kode program tersebut adalah, dengan sebelumnya keikan perintah python signals_slots2.py di command prompt
  • Atau dengan sedikit modifikasi kode program untuk mengasilkan seperti gambar diatas bisa juga dengan kode seperti ini
  • #signals_slots3.py
    #created by wawanHN

    import sys
    from PyQt6.QtWidgets import (
    QApplication,
    QMainWindow,
    QPushButton,
    )

    class MainWindow(QMainWindow):
    def __init__(self):
    super().__init__()

    self.button_is_checked = True

    self.setWindowTitle("Aplikasi Signals Slot 2")
    self.setFixedSize(300, 200)

    button = QPushButton("Klik saya")
    button.setCheckable(True)
    button.clicked.connect(self.button_telah_beralih)
    button.setChecked(self.button_is_checked)

    #Set ditengah window
    self.setCentralWidget(button)

    def button_telah_beralih(self, checked):
    self.button_is_checked = checked
    print("Status checked?" , checked)

    app = QApplication(sys.argv)

    window = MainWindow()
    window.show()

    app.exec()
  • Atau dengan memodifikasi kode program dengan menambahkan fungsi release button
  • #signals_slots4.py
    #created by wawanHN

    import sys
    from PyQt6.QtWidgets import (
    QApplication,
    QMainWindow,
    QPushButton,
    )

    class MainWindow(QMainWindow):
    def __init__(self):
    super().__init__()

    self.button_is_checked = True

    self.setWindowTitle("Aplikasi Signals Slot 2")
    self.setFixedSize(300, 200)

    self.button = QPushButton("Klik saya")
    self.button.setCheckable(True)
    self.button.released.connect(
    self.button_telah_dilepas
    )
    self.button.setChecked(self.button_is_checked)

    #Set ditengah window
    self.setCentralWidget(self.button)

    def button_telah_dilepas(self):
    self.button_is_checked = self.button.isChecked()
    print(self.button_is_checked)

    app = QApplication(sys.argv)

    window = MainWindow()
    window.show()

    app.exec()
  • Ketikan python signals_slots4.py

  • Akan menghasilkan

  • Selanjutnya akan melakukan fungsi sederhana untuk merubah judul window ketika button di klik
  • #signals_slots2.py
    #created by wawanHN

    import sys

    from PyQt6.QtWidgets import (
    QApplication,
    QMainWindow,
    QPushButton,
    )
    from random import choice

    window_titles = [
    "Aplikasiku",
    "Aplikasiku",
    "Masih Aplikasiku",
    "Masih Aplikasiku",
    "Apa yang terjadi",
    "Apa yang terjadi",
    "Sungguh Mengagetkan",
    "Sungguh Mengagetkan",
    "Terjadi Kesalahan",
    ]

    class MainWindow(QMainWindow):
    def __init__(self):
    super().__init__()

    self.n_times_clicked = 0

    self.setWindowTitle("Aplikasi Signals Slot 2")
    self.button = QPushButton("Klik saya")
    self.button.clicked.connect(self.button_telah_diklik)
    self.setFixedSize(300, 200)

    self.windowTitleChanged.connect(
    self.judul_window_telah_berubah
    )
    #Set ditengah window
    self.setCentralWidget(self.button)

    def button_telah_diklik(self):
    print("Telah di klik.")
    new_window_title = choice(window_titles)
    print("Seting Judul: %s" % new_window_title)
    self.setWindowTitle(new_window_title)

    def judul_window_telah_berubah(self, window_title):
    print("Judul window telah berubah: %s" %window_title)

    if window_title == "Terjadi Kesalahan":
    self.button.setDisabled(True)

    app = QApplication(sys.argv)

    window = MainWindow()
    window.show()

    app.exec()
  • Signals dan Slots selain membutuhkan fungsi untuk melakukan sesuatu, bisa juga menghubungkan antara widget tanpa membuat slots. Seperti contoh
  • #signals_slots6.py
    #created by wawanHN

    import sys

    from PyQt6.QtWidgets import (
    QApplication,
    QMainWindow,
    QLabel,
    QLineEdit,
    QVBoxLayout,
    QWidget,
    )

    class MainWindow(QMainWindow):
    def __init__(self):
    super().__init__()

    self.n_times_clicked = 0

    self.setWindowTitle("My App")
    self.label = QLabel()

    self.input = QLineEdit()
    self.input.textChanged.connect(self.label.setText)

    self.setFixedSize(200, 200)

    layout = QVBoxLayout()
    layout.addWidget(self.input)
    layout.addWidget(self.label)

    container = QWidget()
    container.setLayout(layout)

    #Set ditengah window
    self.setCentralWidget(container)

    def button_telah_diklik(self):
    print("Telah di klik.")
    new_window_title = choice(window_titles)
    print("Seting Judul: %s" % new_window_title)
    self.setWindowTitle(new_window_title)

    def judul_window_telah_berubah(self, window_title):
    print("Judul window telah berubah: %s" %window_title)

    if window_title == "Terjadi Kesalahan":
    self.button.setDisabled(True)

    app = QApplication(sys.argv)

    window = MainWindow()
    window.show()

    app.exec()
  • Ketika python signals_slots6.py, maka akan dihasilkan


Sekian dulu, tutorial dasar pembuatan GUI dengan Qt nanti dilanjut di bagian kedua. 38 @wawanhn

Referensi:
  • Create GUI Application with Python and Qt6 5th edition 
  • https://www.pythonguis.com/topics/pyqt6/

Monday, May 13, 2024

Menggunakan RStudio Cloud (Posit Cloud) Bagian 1


Posit cloud sebelumnya dikenal sebagai RStudio Cloud merupakan salah satu tool online yang powerfull digunakan untuk pengolahan data sains via browser dengan kemudahan tanpa instalaasi dan konfigurasi sistem yang komplek. Dengan menggunakan tool ini dapat melakukan pengolahan data dengan menggunakan bahasa R atau Python.

- Oke, untuk menggunakan tool ini solahkan menuju link posit.cloud sehingga menampilkan halaman web Posit.Cloud. 


- Selanjutnya, buat akun untuk dapat membuat projek analisis data yang akan kita lakukan.
- Kemudian silahkan login dengan akun yang sudah dimiliki.
- Buat Project baru, dengan terdapat 3 pilihan yaitu New RStudi Project (untuk mengunakan bahasa R), New Jupyter Project (untuk bahasa Python), dan pilihan New Project from Git Repository (untuk import project dari Github).


@wawanhn





Sunday, October 9, 2022

Membuat Aplikasi Django dan PostgreSQL dengan menggunakan Docker cara 2

Setelah sebelumnya membuat aplikasi Django dan PostgreSQL di 

Membuat Aplikasi Django Dan PostgreSQL Dengan Menggunakan Docker Cara 1

Sekarang dengan sedikit perbedaan akan membuat aplikasi Django dan PostgreSQL di Windows.

Langkah yang dilakukan adalah dengan membuat virtual environment terlebih dahulu kemudian baru membuat kontainer dengan Docker. Hal ini dilakukan untuk lebih memahami persamaan dan perbedaan DOcker dengan virtual environment yang biasa dilakukan dalam pengembangan aplikasi Django. 

Membuat Virtual Environment


  • Buka command prompt dan buat direktori kerja
mkdir dockertest
  • Masuk ke folder direktori kerja
cd dockertest
  • Buat virtual environment, misal dengan nama venv
python -m venv venv
  • Aktifkan virtual environment
cd venv/scripts

activate
  • Setelah virtual environment active dengan ditandai di promt (venv)... Install Djanggo versi terakhir 4,
python -m pip install Django~=4.0.0
  • Install psycopg2-binary
python -m pip install psycopg2-binary==2.9.3
  • Buat project Django, misal dengan nama django_project
django-admin startproject django_project .
  • Lakukan migrate
python manage.py migrate
  • Jalankan server
python manage.py runserver
  • Cek di browser dengan alamat http:127.0.0.1:8000, jika berhasil menampilkan halama aplikasi Djanggo maka langkah yang dilakukan berhasil.
  • Buat file requirements.txt yang berisi paket yang dibutuhkan dari aplikasi Django yang sudah dibuat
pip freeze > requirements.txt
  • Selanjutnya akan membuat kontainer dengan docker, maka matikan virtual environment.
deactivate

Membuat Docker

  • Buat file Dockerfile, masukan kode:
vim Dokerfile

  • Masukan kode kedalam dile Dockerfile:

#Pull base image
FROM python:3.9

#SEt environment variable
ENV PIP_DISABLE_PIP_VERSION_CHECK 1
ENV PYTHONDONTBYTECODE 1
ENV PYTHONUNBUFFERED 1

#Set work directory
WORKDIR /code

#Install dependecies
COPY ./requirements.txt .
RUN pip install -r requirements.txt

#Copy project
COPY . .
  • Sebelum membangun image, buat file .dockerignore
vim .dockerignore
  • Masukan kode:
.venv
.git
.gitignore
  • Membangun docker,
docker build .
  • Membuat file docker-compose.yml
vim docker-compose.yml
  • Masukan kode, dengan catatan buat dulu database di PostgreSQL dan tentukan user dan password untuk akses ke database:
version: "3.9"

services:
  db:
    image: postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password

  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db    

volumes:
  postgres_data:
  • Lakukan konfigurasi untuk seting database di file docker_project/settings.py
vim docker_project/settings.py
  • Masukin kode skrip di bagian DATABASES:
DATABASES ={
     'default': {
         'ENGINE': 'django.db.backends.postgresql',
         'NAME': 'postgres',
         'USER': 'postgres',
         'PASSWORD': 'password',
         'HOST': 'db',
         'PORT': '5432',
         }
}
  • Menjalankan Docker
docker-compose up
  • Setelah proses selesai, silahkan cek server di browser dengan memasukan alamat http://127.0.0.1:8000. Jika berhasil menampilkan tampilan halaman aplikasi Django maka langkah-langkah yang dilakukan berhasil.
  • Atau dengan cara lain dapat dilakukan dengan mengabung perintah build dan docker-compose up dengan cara:
docker-compose up -d --build
  • Setelah dicek server berlajan, untuk keluar dari tampilan service docker dengan cara tekan Ctrl + C
  • Selanjutnya akan membuat aplikasi dengan nama accounts, untuk membuat aplikasi untuk pengguna.

Membuat Apps aaccounts

  • Membuat App dengan nama accounts
docker-compose run web python manage.py startapp accounts

atau

docker-compose exec web python manage.py startapp accounts
  • Membuat CustomUser dengan menggunakan AbstractUser, edit file #accounts/models.py 
from django.db import models
from django.contrib.auth.models import AbstractUser

# Create your models here.
class CustomUser(AbstractUser):
    pass

  • Tambahkan App accounts di bagian INSTALLED_APPS pada file #django_project/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    #local
    'accounts.apps.AccountsConfig', #tambahkan
]
  • Tambahkan juga di bagian bawah file #django_project/settings.py
AUTH_USER_MODEL = 'accounts.CustomUser'

  • Lakukan makemigrations
docker-compose exec web python manage.py makemigrations accounts

output:

Migrations for 'accounts':
  accounts/migrations/0001_initial.py
    - Create model CustomUser

  • Lakukan migrate
docker-compose exec web python manage.py migrate

output:

Operations to perform:
  Apply all migrations: accounts, admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0001_initial... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying accounts.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying sessions.0001_initial... OK
  • Edit file #accounts/forms.py:
#accounts/forms.py
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm, UserChangeForm

class CustomUserCreationForm(UserCreationForm):
    class Meta:
        model = get_user_model()
        fields = ("email", "username",)


class CustomUserChangeForm(UserChangeForm):
    class Meta:
        model = get_user_model()
        fields = ("email", "username",)

  • Edit file #accounts/admin.py
#accounts/admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin

from .forms import CustomUserCreationForm, CustomUserChangeForm

# Register your models here.
CustomUser = get_user_model()

class CustomUserAdmin(UserAdmin):
    add_form = CustomUserCreationForm
    form = CustomUserChangeForm
    model = CustomUser

    list_display = [
        "email",
        "username",
        "is_superuser",
        ]

admin.site.register(CustomUser, CustomUserAdmin)
  • Buat superuser untuk admin, misal dengan username: postgresqladmin, email: postgresqladmin@email.com, dan password: testpass123.
    docker-compose exec web python manage.py createsuperuser
  • Lalu coba di browser alamat admin http://127.0.0.1:8000/admin, login dengan user yang tadi dibuat.
  • Silahkan klik di menu ACCOUNTS/Users, dengan menu tersebut bisa melihat, merubah user dengan menampilkan inputan username dan password serta kemudian menambahkan email dan status user. Silahkan dicoba-coba.

Melakukan test Aplikasi

Setelah dibuat fungsional baru pada aplikasi accounts, selanjutnya dilakukan testing dengan menggunakna unit testing dari framework Django. Testing dilakukan karena meupakan hal penting yang harus dilakukan seperti yang disampaikan oleh pendiri Django yaitu Jacob Kaplan-Moss bahwa "Kode program tanpa dilakukan test adalah sebuah kerusakan dalam desain". Dalam Django terdapat dua tipe test yaitu:

  • Unit test kecil, cepat, dan terisolasi untuk sebagian fungsi dalam aplikasi.
  • Test yang terintegrasi dimana besar, lambat, dan unit test dilakukan pada keseluruhan aplikasi. 

Dalam contoh ini dilakukan unit test sekala kecil pada bagian fungsi yang baru dibuat. Langkah yang dilakukan adalah:

  • Edit file #accounts/test.py 
vim accounts/tests.py
  • Dan masukan kode di file #accounts/test.py:
#accounts/test.py
from django.contrib.auth import get_user_model
from django.test import TestCase

class CustomUserTests(TestCase):
    def test_create_user(self):
        User = get_user_model()
        user = User.objects.create_user(username="wawanhn", email="wawanhn@email.com", password="testpass123")

        self.assertEqual(user.username, "wawanhn")
        self.assertEqual(user.email, "wawanhn@email.com")
        self.assertTrue(user.is_active)
        self.assertFalse(user.is_staff)
        self.assertFalse(user.is_superuser)

    def test_create_superuser(self):
        User = get_user_model()
        admin_user = User.objects.create_superuser(username="superadmin", email="superadmin@email.com", password="testpass123")
        self.assertEqual(admin_user.username, "superadmin")
        self.assertEqual(admin_user.email, "superadmin@email.com")
        self.assertTrue(admin_user.is_active)
        self.assertTrue(admin_user.is_staff)
        self.assertTrue(admin_user.is_superuser)
  • Lakukan test
docker-compose exec web python manage.py test
  • Jika berhasil maka akan menghasilkan output:

output:

Found 2 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..
----------------------------------------------------------------------
Ran 2 tests in 0.494s

OK
Destroying test database for alias 'default'...

Membuat Homepage Aplikasi

  • Buat aplikasi pages
docker-compose exec web python manage.py startapp pages
  • Tambahkan pages di file #django_project/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'accounts.apps.AccountsConfig',
    'pages.apps.PagesConfig', #tambahan baru
]
  • Tentukan BASE Directory dan templates di file #django_project/settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR/'templates'], #tambahkan di baris ini
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
  • Buat folder templates di Direktory kerja dengan nama templates
mkdir templates
  • Buat file html di folder templates dengan nama _base.html dan home.html
vim templates/_base.html
vim templates/home.html
  • File _base.html cara penulisan didepan kata base ada underscore ini hanya merupakan kebiasaan yang menunjukan bahwa file ini akan digunakan/extends untuk file html di seluruh aplikasi (diwariskan). Buat kerangka standar file html untuk file #templates/_base.html
<!-- templates/_base.html -->
<!DOCTYPE html>
<html>
    <head>
        <meta charset='utf-8'>
        <title>{% block title %} Toko Buku {% endblock title %}</title>
    </head>
    <body>
        <div class='container'>
            {% block content %}

            {% endblock content %}
        </div>
    </body>
</html>

  • Masukan kode program pada file #templates/home.html
<!-- templates/home.html -->
{% extends '_base.html' %}

{% block title %} Home {% endblock title %}

{% block content %}
  <h1>Tihs is our home page.</h1>
{% endblock content %}

  • Selanjutnya buat routing alamat web index atau link ke halaman saat pertama kali aplikasi dibuka, tambahkan navigasi ke halaman utama dengan mengedit file #django_project/urls.py
from django.contrib import admin
from django.urls import path, include #tambahkan ini

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('pages.urls')), #tambahkan ini
]
  • Buat routing di aplikasi pages, yaitu file #pages/urls.py
vim pages/urls.py
  • Tambahkan kode:
#pages/urls.py
from django.urls import path
from .views import HomePageView

urlpatterns = [
        path('', HomePageView.as_view(), name='home'),
        ]
  • Edit tampilan view di file #pages/views.py
#pages/views.py
from django.shortcuts import render
from django.views.generic import TemplateView

# Create your views here.
class HomePageView(TemplateView):
    template_name = 'home.html'
  • Untuk melihat perubahan karena sudah menambahkan app pages dan routing, matikan docker dan jalankan lagi
docker-compose down

docker compose up -d 

  • Buka alamat http://127.0.0.1:8000/ maka akan menampilkan tampilan halaman home.html


Membuat Test untuk app pages

Test Untuk Homepages

  • Lakukan test dengan menggunakna Django SimpleTest
vim pages/tests.py
  • Buka file #pages/test.py dan masukan kode:
#pages/tests.py
#from django.test import TestCase
from django.test import SimpleTestCase
from django.urls import reverse

# Create your tests here.
class HomepageTests(SimpleTestCase):
    def test_url_exists_at_correct_location(self):
        response = self.client.get('/')
        self.assertEqual(response.status_code, 200)

    def test_homepage_url_name(self):
        response = self.client.get(reverse('home'))
        self.assertEqual(response.status_code, 200)
  • Lakukan simpletest, dengan kode:
docker-compose exec web python manage.py test
  • jika berhasil maka akan menghasilkan output:
Found 4 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
....
----------------------------------------------------------------------
Ran 4 tests in 0.554s

OK
Destroying test database for alias 'default'...
  • Dari info diatas dilakukan 4 tes karena terdapat 2 tes sebelumnya untuk Custom User Model. Dan jika menginginkan test hanya untuk untuk aplikasi pages maka perintahnya:
docker-compose exec web python manage.py test pages
  • Dan hasil dari perintah tersebut:
Found 2 test(s).
System check identified no issues (0 silenced).
..
----------------------------------------------------------------------
Ran 2 tests in 0.025s

OK
  • Dari hasil test diatas tidak melibatkan akses ke database.

Test Untuk Templates

  • Untuk test template menggunakan fungsi assertTemplateUsed tambahkan kode di file #pages/tests.py
#pages/tests.py
#from django.test import TestCase
from django.test import SimpleTestCase
from django.urls import reverse

# Create your tests here.
class HomepageTests(SimpleTestCase):
    def test_url_exists_at_correct_location(self):
        response = self.client.get('/')
        self.assertEqual(response.status_code, 200)

    def test_homepage_url_name(self):
        response = self.client.get(reverse('home'))
        self.assertEqual(response.status_code, 200)

    def test_homepage_template(self): #tambahan baru
        response = self.client.get('/')
        self.assertTemplateUsed(response, 'home.html')
  • Lakukan test, dan jika berhasil akan menghasilkan ouput Found 3 test dan no issues
docker-compose exec web python manage.py test pages

Test Untuk Html, dll

  • Keseluruhan kode test app page di file #pages/tests.py
#pages/tests.py
#from django.test import TestCase
from django.test import SimpleTestCase
from django.urls import reverse, resolve
from .views import HomePageView

# Create your tests here.
class HomepageTests(SimpleTestCase):
    def setUp(self):
        url = reverse('home')
        self.response = self.client.get(url)

    def test_url_exists_at_correct_location(self):
        #response = self.client.get('/')
        self.assertEqual(self.response.status_code, 200)

    def test_homepage_url_name(self):
        response = self.client.get(reverse('home'))
        self.assertEqual(response.status_code, 200)

    def test_homepage_template(self):
        #response = self.client.get('/')
        self.assertTemplateUsed(self.response, 'home.html')

    def test_homepage_contains_correct_html(self):
        #response = self.client.get('/')
        self.assertContains(self.response, 'home page')

    def test_homepage_does_not_contain_incorect_html(self):
        #response = self.client.get('/')
        self.assertNotContains(self.response,'Hi there! Should not be on the page.')

    def test_homepage_url_resolves_homepageview(self):
        view = resolve('/')
        self.assertEqual(view.func.__name__,HomePageView.as_view().__name__)

  • Lakukan test:
docker-compose exec web python manage.py test pages
  • Jika berhasil tidak ada error maka akan menghasilkan output
Found 6 test(s).
System check identified no issues (0 silenced).
......
----------------------------------------------------------------------
Ran 6 tests in 0.037s

OK
  • asda
  • asdas
  • s

Demkian langkah-langkah membuat aplikasi Django dan PostgreSQL dengan menggunakan Docker sederhana, semoga menambah pengetahuan. @wawanhn