Django Tutorial (Seri 01-05)
Django Tutorial (Seri 01-05)
Django Tutorial
Bahasa Indonesia,
seri 01-05
1
oleh @oonid
oonid
kelas ini diadakan untuk menjawab pertanyaan:
"gimana mulai belajar (buat web dengan) Django?"
https://docs.djangoproject.com/en/3.0/intro/tutorial01/
t.me/djangoID
t.me/surabayadotpy
t.me/telkommdv
bit.ly/kpmtelegram
youtube.com/oonid
Ikuti juga Seri Kelas Django REST Framework
Presentasi tersedia di https://bit.ly/djangorestid
Timeline
Membuat Django Project, Django App. Membangun views yang lebih kompleks. AUTOMATED TESTING :))
Menggunakan server development. Menggunakan sistem template.
Membuat views pertama (hello world!)
3 Mei 8 Mei
Pembahasan
Objektif Tutorial 01 Objektif Tutorial 03 Kenapa Django?
https://www.djangoproject.com/start/overview/
Tutorial 01
https://docs.djangoproject.com/en/3.0/intro/tutorial01/
aktifkan venv
Install Django
intermezzo: buat virtual environment djangotutorialid, aktikan, install Django dalam virtualenv tsb
Django Project
01
Setiap membuat web dengan Django, selalu diawali dengan
membuat sebuah proyek. Satu buah proyek di sini akan punya
satu setting utama, yang isinya konfigurasi umum: misalnya
koneksi ke basis data, konfigurasi DEBUG, timezone,
direktori static, konfigurasi Django App, dls.
Eksekusi Perintah:
django-admin startproject proyekweb
Struktur Direktori
01
Pada saat kita membuat Django Project dengan nama
“proyekweb”, maka akan dibuat sebuah direktori bernama
proyekweb yang di dalamnya ada file manage.py dan
direktori (lagi) proyekweb.
Client Implications:
Consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Lorem ipsum
dolor sit amet, consectetur adipiscing elit tempor incididunt
ut labore et dolore magna aliqua.
Development Server
01
Django Development (web) Server adalah sebuah web server
yang sudah bawaan dari Django, untuk memudahkan kita
langsung mulai melakukan development tanpa harus
memikirkan instalasi web server lain sebelum akhirnya bisa
melihat halaman web kita tampil.
Eksekusi Perintah:
python manage.py runserver
Buka di browser:
http://127.0.0.1:8000
Development Server
02
Jika diperhatikan, saat mengoperasikan development server
kita menggunakan file manage.py, ini adalah file bawaan hasil
kita instalasi Django. Berisi sejumlah perintah administratif
seperti (mirip) seperti halnya django-admin.
https://docs.djangoproject.com/en/3.0/ref/django-admin/
https://docs.djangoproject.com/en/3.0/howto/custom-management-commands/
Django App
01
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
do eiusmod tempor incididunt labore dolore magna aliqua.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Client Implications:
Consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Lorem ipsum
dolor sit amet, consectetur adipiscing elit tempor incididunt
ut labore et dolore magna aliqua.
Django App
02
Membuat Django App "polls", dalam Django Project.
Eksekusi Perintah:
python manage.py startapp polls
Apa itu views?
(skema MVT)
Modify polls/views.py:
def index(request):
return HttpResponse("Hello, world. You're at
the polls index.")
1st views, Hello World!
02
Pada saat membuat Django App, secara bawaan tidak ada file
urls.py, sehingga perlu menambahkan file baru yang akan
berisi daftar rute-rute (routes) dari App tersebut (polls).
urlpatterns = [
path('', views.index, name='index'),
]
1st views, Hello World!
03
Agar urls.py di Django App dapat digunakan, perlu
didaftarkan di urls.py di Django Project.
Modify proyekweb/urls.py:
urlpatterns = [
path('polls/', include('polls.urls')),
# ...
]
Tutorial 02
https://docs.djangoproject.com/en/3.0/intro/tutorial02/
PostgreSQL adalah favorit dari developer Ada juga dukungan dari pihak ketiga untuk
2 4
Django, sehingga ada fitur-fitur khusus, basis data: IBM DB2, MS SQL Server,
seperti field (kolom tabel) khusus untuk Firebird, (backend) ODBC.
PostgreSQL. Hingga GeoDjango dengan
PostgreSQL.
https://docs.djangoproject.com/en/3.0/ref/databases/
https://docs.djangoproject.com/en/3.0/ref/contrib/gis/
https://www.sqlite.org/famous.html
Database Setup
01
Secara bawaan, Django menggunakan SQLite, karena
dukungan secara native dari Python, tidak perlu pasang lagi
driver, tidak perlu instalasi database server karena SQLite
hanya berupa 1 buah file.
implementasi settings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'mydatabase',
}
} https://docs.djangoproject.com/en/3.0/ref/settings/#databases
Database Setup
02
Edit juga USE_TZ = True dan TIME_ZONE di settings.py.
Untuk bekerja dengan multi timezone, kita akan menyimpan
data di basis data dengan timezone UTC, sehingga saat
ditampilkan baru disesuaikan dengan timezone pengguna.
implementasi:
USE_TZ = True
TIME_ZONE = 'Asia/Makassar'
https://docs.djangoproject.com/en/3.0/ref/settings/#time-zone
Database Setup
03
Misalnya ingin menggunakan PostgreSQL, perlu instalasi
server basis data, tersedia di banyak sistem operasi.
Butuh instal paket driver, misalnya psycopg2.
implementasi settings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydatabase',
'USER': 'mydatabaseuser',
'PASSWORD': 'mypassword',
'HOST': '127.0.0.1',
'PORT': '5432', https://docs.djangoproject.com/en/3.0/ref/settings/#databases
}
}
Database Migration
01
Migrasi DB di Django adalah proses pembuatan skenario
perubahan dan implementasinya ke basis data, terkait Django
App. Setiap dibutuhkan perubahan kita membuat skenario
Migrasi baru, atau bahkan kita bisa mundur ke skenario
sebelumnya.
perintah terkait:
python manage.py makemigrations
implementasi polls/models.py:
implementasi model sebagai representasi tabel, dalam
pemrograman python digambarkan sebagai class, yakni
entitas utama di pemrograman berorientasi objek (OOP).
implementasi polls/models.py:
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
Model Choice
01
Ada yang berbeda di model Choice, selain field, model ini juga
punya ForeignKey yang mengacu ke model Question, inilah
yang disebut dengan relasi (antar) tabel.
implementasi polls/models.py:
class Choice(models.Model):
question = models.ForeignKey(Question,
on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
https://docs.djangoproject.com/en/3.0/ref/models/fields/
#module-django.db.models.fields.related
Relasi antar Model
01
Basis Data Relasional (RDBMS) tentu dinamakan karena
suatu sebab, yaitu adanya relasi antar tabel di basis data :-)
Many-to-Many
One-to-One
Registrasi Django App
01
Sebelum dapat melakukan Migrasi
dan mengaktifkan model, maka
Django App yang terkait model
tersebut perlu diregistrasikan
dahulu ke Django Project.
Implementasi settings.py:
INSTALLED_APPS = [
'polls.apps.PollsConfig',
# …
]
Buat Skenario Migrasi
01
Setiap kali ada perubahan pada struktur model (atau
gambarannya pada struktur tabel di basis data), kita harus
membuat skenario Migrasi.
Operations to perform:
Apply all migrations: admin, auth, contenttypes,
polls, sessions
Running migrations:
Rendering model states... DONE
Applying polls.0001_initial... OK
Interaksi DB pakai shell
01
Salah satu perintah yang tersedia di manage.py adalah "shell",
dimana fungsinya mirip seperti python shell hanya saja sudah
memuat semua konfigurasi dari Django Project.
Dengan shell ini kita bisa mengisi kode python seperti halnya
kita menuliskannya di bagian kode views.
eksekusi perintah:
python manage.py shell
class Choice(models.Model):
# …
def __str__(self):
return '(C) '+self.choice_text
Representasi String
dari Model
02
Untuk memastikan hasil pengubahan representasi string __str__()
berhasil, kita ambil kembali seluruh data dari Question.
implementasi:
class Question(models.Model):
# …
def was_published_recently(self):
return self.pub_date >= timezone.now() -
datetime.timedelta(days=1)
Mencari Data
01
Selain mengambil seluruh data all() tentunya kita butuh kemampuan
untuk mencari data yang spesifik, misalnya mencari id tertentu, atau
pertanyaan yang diawali teks tertentu. Pakai fungsi filter().
Perhatikan fungsi bawaan __startswith diawali double-underscore.
>>>
Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]>
Ambil Data dengan Primary Key
01
Selain menggunakan filter() untuk mengakses data menggunakan
primary key tersedia fungsi get(). Akses ke primary key akan lebih cepat.
Tapi fungsi ini akan mengembalikan error DoesNotExist apabila
primary key (PK) tidak ditemukan.
implementasi:
# The following is identical to Question.objects.get(id=1).
>>> Question.objects.get(pk=1)
<Question: What's up?>
>>> Question.objects.get(id=2)
Traceback (most recent call last):
…
DoesNotExist: Question matching query does not exist.
Menggunakan Fungsi ORM
01
Salah satu fungsi ORM yang akan dibahas mengenai
mengakses relasi ForeignKey (many-to-one).
model Choice memiliki relasi ForeignKey ke model Question,
sehingga untuk mengakses Choice dari Question,
menggunakan atribut sesuai nama modelnya "choice_set".
many-to-one: "many" Choice mengacu ke "one" Question.
implementasi:
>>> q = Question.objects.get(pk=1)
# Display any choices from the related object set
-- none so far.
>>> q.choice_set.all()
<QuerySet []>
Tambah Data pada Relasi
01
Setelah punya objek q dari Question, kita ingin menambah data Choice
yang mengacu ke objek tersebut.
ambil satu data dari relasi (queryset), pakai first() atau last():
>>> q.choice_set.last()
<Choice: Just hacking again>>
Client Implications:
Consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Lorem ipsum
dolor sit amet, consectetur adipiscing elit tempor incididunt
ut labore et dolore magna aliqua.
Membuat (Super) User
01
Untuk dapat mengakses Django Admin, butuh menggunakan
User yang memiliki akses superuser atau staff.
Username: superadmin
Email address: [email protected]
Password: **********
Password (again): *********
Superuser created successfully.
Akses Halaman Admin
01
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
do eiusmod tempor incididunt labore dolore magna aliqua.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
update polls/views.py:
def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id)
update polls/views.py:
# tambahan dari 3 fungsi di presentasi sebelumnya
ubah polls/urls.py:
urlpatterns = [
# ex: /polls/
path('', views.index, name='index'),
# ex: /polls/5/
path('<int:question_id>/', views.detail, name='detail'),
# ex: /polls/5/results/
path('<int:question_id>/results/', views.results, name='results'),
# ex: /polls/5/vote/
path('<int:question_id>/vote/', views.vote, name='vote'),
]
Melengkapi views index
01
Menampilkan 5 Question terbaru (berdasarkan pub_date).
Respon "HTML" nya sangat bergantung dari kode views
(python).
ubah polls/views.py:
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
output = ', '.join([q.question_text for q in latest_question_list])
return HttpResponse(output)
Apa itu Template?
(skema MVT)
https://developer.mozilla.org/id/docs/Learn/Server-side/Django/Introduction
https://docs.djangoproject.com/en/3.0/ref/templates/language/
Dukungan Template Engine (bawaan)
Django Templates adalah template engine bawaan dari Django.
1
Sintaksisnya dikenal dengan istilah Django Template Language (DTL).
Jinja2 adalah template engine lebih populer, modern dan ramah pada pengguna desainer
2
(designer-friendly), dimana bentuknya menirukan Django Template.
Memiliki sintaksis sendiri, yang berbeda, tapi banyak kemiripan dengan DTL.
https://docs.djangoproject.com/en/3.0/ref/templates/language/
http://jinja.pocoo.org/
Django Template
Language (DTL)
01
Ini adalah contoh sederhana dari sebuah template yang
menggambarkan sejumlah fungsi dasar dari DTL.
penjelasan:
Variables
Filters
Tags
Template Inheritance
- Comments
https://docs.djangoproject.com/en/3.0/ref/templates/language/
Membuat Template index
01
Untuk melengkapi views index, akan dibuat template
index.html, dengan markup HTML yang disederhanakan.
buat polls/templates/polls/index.html:
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{
question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
Membuat Template index
02
Ubah views index untuk menggunakan template.
ubah polls/views.py:
def index(request):
latest_question_list =
Question.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = {
'latest_question_list': latest_question_list,
}
return HttpResponse(template.render(context, request))
Membuat Template index
03
Atau singkatnya gunakan jalan pintas (shortcut) render.
ubah polls/views.py:
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
Membuat Template index
04
Mengubah link yang ditulis (hard-coded) menjadi nama url.
Dalam hal ini menjadi “{% url 'detail' question.id %}”
buat polls/templates/polls/index.html:
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="{% url 'detail' question.id %}">{{
question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
Membuat Template detail
01
Untuk melengkapi views detail, akan dibuat template
detail.html, dengan markup HTML yang disederhanakan.
buat polls/templates/polls/detail.html:
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
Membuat Template detail
02
Ubah views index untuk menggunakan template.
ubah polls/views.py:
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, 'polls/detail.html',
{'question': question})
Membuat Template detail
03
Atau singkatnya gunakan jalan pintas (shortcut) get_object_or_404.
ubah polls/views.py:
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
Namespace URL
01
Jika menggunakan banyak Django App, agar membedakan
setiap nama url, digunakan mekanisme namespace dengan
nama app.
implementasi polls/urls.py:
app_name = 'polls'
urlpatterns = [
# all existing codes
]
Namespace URL
02
Jika menggunakan banyak Django App, agar membedakan
setiap nama url, digunakan mekanisme namespace dengan
nama app; {% url 'polls:detail' question.id %}.
implementasi polls/templates/polls/index.html:
implementasi:
https://docs.djangoproject.com/en/3.0/ref/templates/language/
#template-inheritance
Tutorial 04
https://docs.djangoproject.com/en/3.0/intro/tutorial04/
implementasi:
views yang menangani Form metode GET dan POST
class Form
menggunakan instance dari Form di Template
lebih jauh, bisa membuat Form dari Model (class ModelForm)
https://docs.djangoproject.com/en/3.0/topics/forms/
Buat Form Sederhana
01
Berikut adalah sintaksis dari HTML form yang dilengkapi
dengan sejumlah sintaksis DTL untuk melengkapi form.
ubah polls/templates/polls/detail.html:
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
<input type="submit" value="Vote">
</form>
Buat Form Sederhana
02
Pengiriman (submission) Form akan ditangani oleh views vote.
ubah polls/views.py:
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': question, 'error_message': "You didn't select a choice.", })
else:
selected_choice.votes += 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing with POST data.
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
Buat Form Sederhana
03
Melengkapi views results dengan template results.html,
untuk menampilkan hasil polling.
ubah polls/templates/polls/results.html:
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>
<a href="{% url 'polls:detail' question.id %}">Vote again?</a>
Buat Form Sederhana
04
Melengkapi views results dengan template results.html,
untuk menampilkan hasil polling.
ubah polls/views.py:
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})
Membuat Form dari Model
01
Kita bisa membuat sebuah class Form secara otomatis
dibangkitkan dari class Model. Mekanisme ini yang digunakan
oleh Django Admin.
Implementasi:
from django.forms import modelform_factory
from myapp.models import Book
https://docs.djangoproject.com/en/3.0/topics/forms/modelforms/
#modelform-factory-function
Class-Based Views
01
views tidak terbatas pada sebuah fungsi, Django
menyediakan fasilitas dalam konsep OOP, sejumlah views
yang memungkinkan lebih reusable, dengan memanfaatkan
mekanisme inheritance dan mixin. Salah satu contohnya
adalah Django Generic Views.
https://docs.djangoproject.com/en/3.0/topics/class-based-views/
Mengubah IndexView
01
Akan mewarisi (menjadi turunan) ListView dari Django Generic Views.
ubah polls/views.py:
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
"""Return the last five published questions."""
return Question.objects.order_by('-pub_date')[:5]
https://docs.djangoproject.com/en/3.0/ref/class-based-views/generic-display
/#django.views.generic.list.ListView
Mengubah DetailView
01
Akan mewarisi (menjadi turunan) DetailView dari Django
Generic Views.
ubah polls/views.py:
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
https://docs.djangoproject.com/en/3.0/ref/class-based-views/generic-display
/#django.views.generic.detail.DetailView
Mengubah ResultsView
01
Akan mewarisi (menjadi turunan) DetailView dari Django
Generic Views.
ubah polls/views.py:
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
https://docs.djangoproject.com/en/3.0/ref/class-based-views/generic-display
/#django.views.generic.detail.DetailView
Ubah urls untuk CBV
01
Untuk menggunakan Class-Based Views di urls, kita akan
menggunakan metode (method) bawaan ".as_view()".
ubah polls/urls.py:
app_name = 'polls'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
Tutorial 05
https://docs.djangoproject.com/en/3.0/intro/tutorial05/
Automated Tests:
Proses pengujian (pengoperasian kode test) dilakukan oleh
sistem, salah satu contohnya penggunaan Continuous
Integration (CI).
Kenapa Test itu Penting?
01
Saat membuat sebuah aplikasi, mungkin kita merasa sudah
banyak sekali yang perlu dilakukan, lalu apa pentingnya untuk
menambah lagi pekerjaan dengan membuat test?
beberapa pertimbangan:
Tests justru akan menghemat waktu (aplikasi berskala besar)
Tests bukan hanya menunjukkan masalah, juga mencegah
Tests membantu tim bekerja bersama
Tests merupakan standar yang ditetapkan (developer global)
untuk kualitas
Running Tests
01
Untuk melakukan pengujian di Django, setelah mengubah file
tests.py di Django App, gunakan perintah berikut.
Proses tests tidak menggunakan basis data utama, tapi
membuat basis data baru, sehingga butuh membuat isinya.
ubah polls/tests.py:
class QuestionModelTests(TestCase):
def test_was_published_recently_with_future_question(self):
"""was_published_recently() returns False for questions
whose pub_date is in the future."""
time = timezone.now() + datetime.timedelta(days=30)
future_question = Question(pub_date=time)
self.assertIs(future_question.was_published_recently(), False)
Menguji sebuah view
01
Menguji dengan test Client.
Pada class TestCase sudah memiliki atribut client bawaan.
Implementasi:
>>> from django.test import Client
>>> client = Client()
>>> response = client.get('/')
>>> response.status_code
Menguji View Secara
Lengkap
01
TBD
Client Implications:
TBD
https://docs.djangoproject.com/en/3.0/intro/tutorial05/
#testing-our-new-view
Aturan Praktis Test
01
Karena diharapkan banyak test yang dibuat, sehingga
diperlukan beberapa aturan agar mudah mengelolanya.
https://www.obeythetestinggoat.com/book/part1.harry.html
Contoh Django Apps
01
Sebagai kelanjutan dari pembahasan tutorial ini, bisa dilihat
tempat penyimpanan kode Jago Django.
Di situ tersedia beberapa Django Apps yang dilengkapi
dengan tests, automated tests dengan continuous
integration, dengan pengujian lingkup (coverage).
https://github.com/jagodjango/kode/blob/master/profilpeng
gunafoto/tests.py
https://github.com/jagodjango/kode
Contoh Django Apps
02
Menggunakan GitHub Actions sebagai continuous
integration (CI).
https://github.com/jagodjango/kode/blob/master/.github/w
orkflows/djangoapps.yml
https://github.com/jagodjango/kode
Contoh Django Apps
02
Menggunakan codecov untuk menguji lingkup (coverage) dari
kode, memastikan semua kode (utama) yang ditulis sudah
dibuatkan test.
https://codecov.io/gh/jagodjango/kode
https://github.com/jagodjango/kode
Coverage
01
TBD
Client Implications:
TBD
https://pypi.org/project/coverage/
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt labore dolore magna aliqua. Lorem ipsum dolor sit amet,
Deliverables consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor incididunt labore dolore magna
aliqua. Lorem ipsum dolor sit amet, consectetur adipiscing elit.