# **Django | Portofolio Website** [TOC] --- ## **About Website** ![image](https://hackmd.io/_uploads/Hy1QDbONR.png) Pada Kesempatan kali ini, saya berkesempatan untuk membangun website berisikan portofolio pribadi. Portofolio ini terdiri dari beberapa bagian, yaitu: 1. **Header** Pada bagian ini, terdapat navabar yang dapat menunjukkan posisi resume, project, serta contact pada halaman. Serta pengenalan singkat mengenai indetitas diri, serta button untuk mengunduh CV. 2. **Resume** ![image](https://hackmd.io/_uploads/Hy8YvWdNA.png) ![image](https://hackmd.io/_uploads/SyPqwWdEA.png) Pada section Resume, saya membagi menjadi sub section yang terdiri dari Education dan Experience. Masing-masing menunjukkan card dengan value setiap education dan experience yang dimiliki. 3. **Project** ![image](https://hackmd.io/_uploads/BJDhDWd40.png) Pada Section project, saya ingin menonjolkan detail informasi mengenai project yang telah dilakukan dengan tambahan gambar, serta link menuju dokumentasi. 4. **Contact** ![image](https://hackmd.io/_uploads/BkTaDZdNA.png) Pada section contact, saya menambahkan informasi instagram,linkedin, github, dan email yang terhubung langsung dengan identitas yang didaftarkan. Sebelum memulai lebih jauh, berikut ialah pengenalan singkat mengenai apa itu Django: --- :::success :bulb: **Attention** Acces my other documentation on: [My Portofolio Website](https://syafa.pythonanywhere.com) [Github Repository](https://github.com/syafaningrum/django-portofolio-web) [Detail Fitur](https://youtu.be/6cya4iZmyAY) [Docker Image](https://hub.docker.com/r/syafaa/myporto) Hope you enjoy it!!! ::: --- ## **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**. --- ## **Instalasi** Django yang digunakan pada project ini ialah versi 4.2.11. Beberapa langkah yang perlu diambil untuk dapat menjalankan Django diantaranya ialah: 1. Siapkan environment untuk pengembangan. Saya menggunakan Ubuntu 20.04 2. Update VM ``` sudo apt-get update ``` 3. Melakukan instalasi Phyton3 dan pip ``` sudo apt install python3 python3-pip ``` 4. 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 ``` 5. Membuat direktori baru bernama Dev/myweb/ dan pindah ke dalamnya 6. Melakukan instalasi virtualenv python ``` sudo apt install python3-virtualenv virtualenv -p python3 . source /bin/activate ``` 7. Menginstal Django dan depedencynya di dalam virtualenv ``` pip install django asgiref pillow pytz sqlparse typing_extensions ``` --- ## **Memulai Project Django** Setelah melakukan instalasi, maka Django project dapat dimulai. Berikut ini ialah langkah yang perlu dilakukan: 1. Membuat direktori benama porto/ dan masuk ke dalamnya 2. Membuat project baru ``` django-admin startproject porto ``` 3. Membuat aplikasi yang dibutuhkan ``` python manage.py startapp identity ``` 4. Menambahkan aplikasi identity ke dalam file porto/settings.py ``` nano settings.py ... INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'identity', #menambahkan app identity ] ``` 5. Menambahkan models di file identity/models.py ``` from django.db import models class Identity(models.Model): name = models.CharField(max_length=120) email = models.EmailField() instagram = models.URLField(max_length=200) linkdin = models.URLField(max_length=200) github = models.URLField(max_length=200) avatar = models.ImageField(upload_to='assets/',) born_date = models.DateField(auto_now_add=False) born_place = models.CharField(max_length=120, blank=True) spesialized= models.CharField(max_length=120) description= models.TextField(blank=True, null=True) timestamp = models.DateTimeField(auto_now_add=True) def __str__(self): return self.name class Education(models.Model): institution = models.CharField(max_length=120) start = models.CharField(max_length=120) end = models.CharField(max_length=120) major = models.CharField(max_length=120) def __str__(self): return self.institution class Project(models.Model): name = models.CharField(max_length=120) category = models.CharField(max_length=120) purpose = models.CharField(max_length=120) skill = models.TextField(blank=True, null=True) description = models.TextField(blank=True, null=True) date = models.CharField(max_length=120) documentation= models.URLField(max_length=200) image = models.ImageField(upload_to='assets/',) def __str__(self): return self.name class Experience(models.Model): name = models.CharField(max_length=120) category = models.CharField(max_length=120) heldby = models.CharField(max_length=120) date = models.CharField(max_length=120) place = models.CharField(max_length=120, blank=True) description= models.TextField(blank=True, null=True) def __str__(self): return self.name ``` 6. Ubah file admin.py ``` from django.contrib import admin from .models import Identity, Experience, Education, Project admin.site.register(Identity) admin.site.register(Experience) admin.site.register(Education) admin.site.register(Project) ``` 7. Jalankan migrasi untuk memulai aplikasi ``` python manage.py makemigrations python manage.py migrate ``` 8. Start server ``` python manage.py runserver ``` 9. Akses http:127.0.0.1:8000 melalui browser local ![image](https://hackmd.io/_uploads/B1aSsZONA.png) 10. Tambah object pada setiap models dengan sesuai --- ## **Membuat Tampilan Website** Berikut merupakan cara untuk membuat tampilan html pada website: 1. Buat file identity/templates/index.html ``` {% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <meta name="description" content="" /> <meta name="author" content="" /> <title>Portofolio | Syafa</title> <!-- Custom Google font--> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@100;200;300;400;500;600;700;800;900&amp;display=swap" rel="stylesheet" /> <!-- Bootstrap icons--> <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css" rel="stylesheet" /> <!-- Core theme CSS (includes Bootstrap)--> <link href="{% static 'css/styles.css' %}" rel="stylesheet" /> </head> <body class="d-flex flex-column h-100"> <main class="flex-shrink-0"> <nav class="navbar navbar-expand-lg navbar-light bg-white py-3"> <div class="container px-5"> <a class="navbar-brand" href="index.html"><span class="fw-bolder text-primary">Syafa</span></a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav ms-auto mb-2 mb-lg-0 small fw-bolder"> <li class="nav-item"><a class="nav-link" href="#home">Home</a></li> <li class="nav-item"><a class="nav-link" href="#resume">Resume</a></li> <li class="nav-item"><a class="nav-link" href="#project">Projects</a></li> <li class="nav-item"><a class="nav-link" href="#contact">Contact</a></li> </ul> </div> </div> </nav> <header class="py-5 mt-md-5"> <div class="container px-5 pb-5"> <div class="row gx-5 align-items-center"> <div class="col-xxl-5"> <div class="text-center text-xxl-start"> {% for identity in identity %} <h1 class="display-3 fw-bolder mb-5"><span class="text-gradient d-inline">Hi! <br> I'm {{ identity.name }}</span></h1> <p class="lead fw-light text-primary mb-4"><span class="fw-bolder text-secondary">I am a </span><span class="text-gradient d-inline" style="font-size: 20px; font-weight: bold;">{{ identity.spesialized }} </span> <span class="fw-bolder text-secondary">{{ identity.description }}</span></p> <div class="d-grid gap-3 d-sm-flex justify-content-sm-center justify-content-xxl-start mb-3"> <a class="btn btn-primary btn-lg px-5 py-3 me-sm-3 fs-6 fw-bolder" href="{% static 'assets/CV.pdf' %}">Download My Resume</a> </div> </div> </div> <div class="col-xxl-7"> <!-- Header profile picture--> <div class="d-flex justify-content-center mt-5 mt-xxl-0"> <img class="profile-img" src="{{ identity.avatar.url }}" alt="Avatar" /> </div> {% endfor %} </div> </header> <section id="resume"class="my-md-5"> <div class="container mt-md-5 px-5 my-5"> <div class="text-center mb-5"> <h1 class="display-5 fw-bolder mb-0"><span class="text-gradient d-inline">Resume</span></h1> </div> <div class="row gx-5 justify-content-center"> <!-- Education Section--> <section> <h2 class="mt-md-5 text-primary fw-bolder mb-0">Education</h2> {% for education in education %} <div class="card shadow border-0 rounded-4 mb-5"> <div class="card-body p-5"> <div class="row align-items-center gx-5"> <div class="text-secondary fw-lighter mb-1">{{ education.start }} - {{ education.end }}</div> <div class="text-primary fw-bolder fs-6">{{ education.institution }} </div> <div class="small fst-italic">{{ education.major }}</div> </div> </div> </div> {% endfor %} </section> <section > <div class="mt-md-5 d-flex align-items-center justify-content-between mb-4"> <h2 class="text-primary fw-bolder mb-0">Experience</h2> </div> {% for experience in experience %} <div class="card shadow border-0 rounded-4 mb-5"> <div class="card-body p-5"> <div class="row align-items-center gx-5"> <div class="col text-center text-lg-start mb-4 mb-lg-0"> <div class="bg-light p-4 rounded-4"> <div class="text-primary fw-bolder mb-2">{{ experience.date }}</div> <div class="small fw-bolder fst-italic">{{ experience.category }}</div> <div class="small text-muted">{{ experience.place }}</div> </div> </div> <div class="col-lg-8"> <div class="text-primary fw-bolder">{{ experience.name }} </div> <div class="text-secondary fw-lighter">Held by {{ experience.heldby }} </div> <div class="text-secondary fw-lighter">{{ experience.description }} </div> </div> </div> </div> </div> {% endfor %} </section> </section> <section id="project"> <section class="py-5"> <div class="container px-5 mb-5"> <div class="text-center mb-5"> <h1 class="display-5 fw-bolder mb-0"><span class="text-gradient d-inline">Projects</span></h1> </div> <div class="row gx-5 justify-content-center"> <!-- Project Card 1--> {% for project in project %} <div class="card overflow-hidden shadow rounded-4 border-0 mb-5"> <div class=" row card-body p-0"> <div class="col-xxl-2 d-flex align-items-center"><img class="project"src="{{ project.image.url }}" alt="{{ project.name }}"></div> <div class="col-xxl-7 d-flex align-items-center"> <div class="p-5"> <h2 class="fw-bolder">{{ project.name }}</h2> <div class="small fw-bolder fst-italic">{{ project.category }}</div> <div class="text-secondary fw-lighter">Purpose :{{ project.purpose }} </div> <div class="text-secondary fw-lighter">Skills : {{ project.skill }} </div> <div class="text-secondary fw-lighter">{{ project.description }} </div> <a class="btn btn:focus-visible btn-sm fst-italic" href="{{ project.documentation }}">Click to see my documentation</a> </div> </div> </div> </div> {% endfor %} </div> </section> <section id="contact"> <section class="bg-light py-5"> <div class="container px-5"> <div class="row gx-5 justify-content-center"> <div class="col-xxl-8"> <div class="text-center my-5"> <h2 class="display-5 fw-bolder"><span class="text-gradient d-inline">Keep In Touch</span></h2> {% for identity in identity %} <div class="d-flex justify-content-center fs-2 gap-4"> <a class="text-gradient" href="{{ identity.instagram }}"><i class="bi bi-instagram"></i></a> <a class="text-gradient" href="{{ identity.linkdin }}"><i class="bi bi-linkedin"></i></a> <a class="text-gradient" href="{{ identity.github }}"><i class="bi bi-github"></i></a> <a class="text-gradient" href="mailto:{{ identity.github }}"><i class="bi bi-envelope-fill"></i></a> </div> {% endfor %} </div> </div> </div> </div> </section> </main> </footer> <!-- Bootstrap core JS--> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script> <!-- Core theme JS--> <script src="js/scripts.js"></script> </body> </html> ``` 2. Buat direktori static, serta direktori assets, css, dan js di dalamnya. 3. Tambahkan file styles.css, pada file ini, isi dengan class yang diperlukan untuk file index.html 4. Upload file CV.pdf pada direktori static/assets, nantinya file ini yang akan dikirimkan ketika pengguna memilih button 'Download My Resume'. --- ## **Menghubungkan Models dan HTML** Untuk menghubungkan file html sebagai front website dengan models Django, gunakan file views.py, ubah konfigurasi file menjadi sebagaimana berikut: ``` from django.shortcuts import render from .models import Identity, Experience, Project, Education # Create your views here. def index(request): template_name = 'index.html' identity = Identity.objects.all() experience = Experience.objects.all() project = Project.objects.all() education = Education.objects.all() context = { "identity": identity, "experience": experience, "project": project, "education": education } return render(request, template_name, context) ``` Kemudian, tambahkan url pada porto/urls.py ``` from django.contrib import admin from django.urls import path, include from django.conf import settings from django.conf.urls.static import static from identity.views import index urlpatterns = [ path('admin/', admin.site.urls), path('', index), ] if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ``` Cek melalui browser lokal ![Screenshot 2024-06-01 092728](https://hackmd.io/_uploads/rJ1FEKOER.png) --- ## **Unggah Repository ke GitHub** 1. Instal git ``` sudo apt install git ``` 2. Konfigurasi git ``` git config --global user.name "username" git config --global user.email "email@gmail.com" ``` 3. Git remote ``` git remote set-url origin https://ssh@github.com/syafaningrum/django-portofolio-web ``` 4. Tambahkan folder yang ingin di push ``` git add . ``` 5. Menyimpan perubahan ``` git cmmit -m "comment" ``` 6. Melakukan push ke repository ``` git push -u origin main ``` 7. Cek pada repository GitHub ![image](https://hackmd.io/_uploads/r1k18FONC.png) --- ## **Deploy Docker** 1. Instal Docker pada vm yang digunakan ``` sudo apt update sudo apt upgrade sudo apt install apt-transport-https ca-certificates curl software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" sudo apt update sudo apt install docker-ce sudo systemctl status docker ``` ![image](https://hackmd.io/_uploads/Hksanb_4A.png) 2. Membuat akun pada hub.docker.com ![image](https://hackmd.io/_uploads/Hk7ae4O4A.png) 3. Mebuat Dockerfile ``` FROM python:3.8.10 WORKDIR /app COPY requirements.txt requirements.txt RUN pip3 install -r requirements.txt COPY . . CMD [ "python3", "porto/manage.py", "runserver", "0.0.0.0:7000"] ``` 4. Membuat docker image ``` docker build -t username/repository_name . atau docker build -t syafaa/myporto . ``` ![Screenshot 2024-06-01 103530](https://hackmd.io/_uploads/ryWRZEuV0.png) 5. Melakukan login aku Docker Hub ``` docker login ``` 7. Push image ke Docker Hub ``` docker push nama_pengguna/nama_image ``` ![Screenshot 2024-06-01 103636](https://hackmd.io/_uploads/rJcAbV_4A.png) 8. Cek repositori melalui browser ![Screenshot 2024-06-01 103611](https://hackmd.io/_uploads/BJkJzNuNC.png) ![Screenshot 2024-06-01 103559](https://hackmd.io/_uploads/S17kGEOE0.png) ## **Akses Melalui Docekr Image** Berikut merupakan langkah untuk melakukan instalasi repository melalui Docker image: 1. Pastikan environtment yang digunakan telah terinstal Docker. Ikuti langkah deploy Docker pertama jika belum. 2. Melakukan pull dari docker image ``` docker pull syafaa/myporto ``` ![Screenshot 2024-06-01 103424](https://hackmd.io/_uploads/r1ODMVOV0.png) 3. Jalankan Docker image dengan port 8080 ``` docker run -d -p 8080:7000 syafaa/myporto ``` ![Screenshot 2024-06-01 103447](https://hackmd.io/_uploads/BJU5fNONC.png) 4. Akses 127.0.0.1:8080 melalui browser lokal ![Screenshot 2024-06-01 103344](https://hackmd.io/_uploads/SyZ2fN_4C.png) Nantinya akan keluar log seperti gambar berikut: ![Screenshot 2024-06-01 103454](https://hackmd.io/_uploads/rJvnGNuV0.png) ## **Hosting Website** ![image](https://hackmd.io/_uploads/ryZGyt_EC.png) Untuk hosting project ini saya menggunakan layanan dari pythonanywhere.com PythonAnywhere adalah integrated development environment (IDE) online dan layanan hosting web berdasarkan bahasa pemrograman Python . Untuk bisa menikmati layanan PythonAnywhere, berikut adlah langkah yang perlu diambil: 1. Akses www.pythonanywhere.com 2. Membuat akun baru dan login ![image](https://hackmd.io/_uploads/SJvEeKOVA.png) 3. Masuk ke bagian Console, kemudian pilih bagian bash ![image](https://hackmd.io/_uploads/rykDbtdNC.png) 4. Lakukan git clone dari repository GitHub ``` git clone https://github.com/syafaningrum/django-portofolio-web ``` 5. Instal virtual environtment dan masuk ke dalamnya ``` python -m venv env source env/bin/activate ``` 6. Pindah ke direktori django dan instal semua requirements ``` pip install -r requirements.txt ``` 7. Akses "Web" pada bagain navbar dan membuat app baru ![image](https://hackmd.io/_uploads/Sy9_xF_VC.png) 8. Pilih manual configuration dan lanjutkan ![Screenshot 2024-06-01 180807](https://hackmd.io/_uploads/HyhPGFuE0.png) ![Screenshot 2024-06-01 180817](https://hackmd.io/_uploads/Sk4ufKO4A.png) 9. Ubah direktori pada source code sesuai pada direktori Django berada, ubah working direktory menjadi direktori kerja, ubah Virtualenv menjadi direktori env yang tadi sudah dibuat ![image](https://hackmd.io/_uploads/S1dHmtuVR.png) 10. Konfigurasi file WSGI ``` import os import sys path = os.path.expanduser('~/django-portofolio-web/portofolio/') if path not in sys.path: sys.path.insert(0, path) os.environ['DJANGO_SETTINGS_MODULE'] = 'porto.settings' from django.core.wsgi import get_wsgi_application from django.contrib.staticfiles.handlers import StaticFilesHandler application = StaticFilesHandler(get_wsgi_application()) ``` 11. Tambah allowed host pada file porto/setting.py ``` ALLOWED_HOSTS = ['syafa.pythonanywhere.com'] ``` 12. Reload website ![image](https://hackmd.io/_uploads/rJrTXtOE0.png) 13. Akses pada syafa.pythonanywhere.com ![image](https://hackmd.io/_uploads/H1l14K_EC.png)