Fakultas Ilmu Komputer UI

Commit 943e667b authored by LUTHFI DZAKY SAIFUDDIN's avatar LUTHFI DZAKY SAIFUDDIN
Browse files

Merge branch 'exercise-10' into 'master'

Exercise 10

See merge request !16
parents c8369495 87577d1f
Pipeline #26474 passed with stages
in 8 minutes and 10 seconds
......@@ -410,4 +410,161 @@ LOGGING = {
Namun, saya tidak menemukan error pada bagian logs di Heroku,
hal tersebut karena saya sudah melakukan solve error tersebut pada tutorial
sebelumnya dengan cara memasukkan env yang dibutuhkan email di settings.py
pada environment variables di Heroku.
\ No newline at end of file
pada environment variables di Heroku.
## Tutorial 10
### Bagian 1 (Kompetensi Minimal)
Pada tutorial kali ini tidak terlalu banyak perubahan kode. Namun,
lebih menekankan mengenai pemahaman tentang migrasi data. Misalkan,
pada kasus kali ini ingin membuat setiap To Do di list merupakan `unique`.
Sebelumnya, saya mengganti test yang sebelumnya membuat To Do yang
membuat duplikasi To Do, misalkan pada fungsi test_views.py seperti berikut:
```python
def test_function_message_is_five(self):
_list = List.objects.create()
for i in range(5):
Item.objects.create(text='itemey 2', list=_list)
self.assertEqual(message_todo(_list), "oh tidak")
```
Menjadi seperti berikut:
```python
def test_function_message_is_five(self):
_list = List.objects.create()
for i in range(5):
Item.objects.create(text='itemey 2' + str(i), list=_list)
self.assertEqual(message_todo(_list), "oh tidak")
```
Kemudian, pada models.py menambahkan kode berikut:
```python
class Meta:
ordering = ('id',)
unique_together = ('list', 'text')
```
Sebelumnya, pada database saya sudah menambahkan sebuah list dengan
duplikasi text seperti berikut:
```python
1. Test
2. Test
3. Test
```
Ketika melakukan `python3 manage.py migrate` akan muncul berikut:
```
django.db.utils.IntegrityError: could not create unique index "lists_item_list_id_text_a3f43fb7_uniq"
DETAIL: Key (list_id, text)=(2, test) is duplicated.
```
Hal tersebut terjadi karena ketika python ingin mengganti versi database dengan cara
menambahkan constraint bahwa id dan text harus unique, data yang sudah ada
(yang sudah saya tambahkan sebelumnya) merupakan duplikasi.
Cara yang biasanya dilakukan adalah menghapus database yang ada kemudian
melakukan migrasi dari ulang. Sehingga tidak akan menimbulkan error seperti
sebelumnya.
Cara kedua adalah melakukan migrasi data terlebih dahulu. Untuk melakukan migrasi
dengan membuat constraint unique, kita harus memigrasi data yang sudah ada sebelumnya.
Dengan membuat file migrasi yang akan dijalankan sebelum membuat constraint unique tersebut.
Dengan perintah `python3 manage.py makemigrations lists --empty` akan otomatis membuat
file migrasi dengan depedensi migrasi terakhir.
Kemudian, dengan menambahkan kode berikut:
```python
def find_dupes(apps, schema_editor):
List = apps.get_model("lists", "List")
for list_ in List.objects.all():
items = list_.item_set.all()
texts = set()
for ix, item in enumerate(items):
if item.text in texts:
item.text = '{} ({})'.format(item.text, ix)
item.save()
texts.add(item.text)
class Migration(migrations.Migration):
dependencies = [
('lists', '0004_item_list'),
]
operations = [
migrations.RunPython(find_dupes)
]
```
Kita akan membuat data duplikasi di database menjadi seperti berikut:
```
1. Test
2. Test (1)
3. Test (2)
```
Kemudian kita melakukan `python3 manage.py migrate` tidak akan terjadi error
karena seluruh data di database tidak akan melanggar constraint.
Hal tersebut bisa terjadi dalam beberapa kasus, misalnya dengan menambahkan kolom
yang foreign key terhadap suatu table dengan nilai default "X" namun X pada tabel
tersebut belum ada. Dengan cara tersebut jelas menguntungkan kita karena tidak
memerlukan menghapus database secara berulang-berulang.
### Bagian 2 (Kompetensi Tambahan)
Pada bagian kali ini, saya akan mencoba migrasi data dummy berjumlah
100 data. Dengan cara membuat 10 list dengan isi 10 item tiap listnya.
Saya membuat data dengan cara sebagai berikut:
```python
def create_data(apps, schema_editor):
List = apps.get_model("lists", "List")
Item = apps.get_model("lists", "Item")
for i in range(10):
_list = List.objects.create()
for z in range(10):
Item.objects.create(text='itemey 2' + str(z), list=_list)
```
Kemudian, dengan mengikuti tutorial pada link berikut:
[Link Berikut](https://www.codepolitan.com/cara-membuat-data-migration-dengan-django-5a749614988e4)
Saya akan mencoba menambah kolom slug dimana akan menampilkan slugify dari text
item tersebut. Hal tersebut dilakukan dengan cara menambahkan model seperti berikut:
```python
slug = models.SlugField(blank=True)
```
Kemudian migrasi seperti berikut untuk melakukan backfill pada 100 data yang sudah ada:
```python
from django.db import migrations
from django.utils.text import slugify
def slugify(apps, schema_editor):
List = apps.get_model("lists", "List")
for list_ in List.objects.all():
items = list_.item_set.all()
for ix, item in enumerate(items):
item.slug = slugify(item.text)
item.save()
class Migration(migrations.Migration):
dependencies = [
('lists', '0007_item_slug'),
]
operations = [
]
```
Eksekusi migrasi bisa dilakukan dengan menggunakan scheduler,
contoh caranya seperti berikut
[Klik disini](https://medium.com/@kevin.michael.horan/scheduling-tasks-in-django-with-the-advanced-python-scheduler-663f17e868e6)
Namun, kali ini saya langsung mengeksekusinya karena pada dasarnya yang
menggunakan aplikasi ini saya sendiri. Pada kasus asli, bisa dilakukan ketika
dinihari, atau ketika hari libur (jika memang aplikasi yang digunakan hanya
digunakan di hari kerja saja).
\ No newline at end of file
......@@ -69,7 +69,7 @@ class NewVisitorTest(FunctionalTest):
# She want to add another 3 to do
for x in range(3):
inputbox = self.browser.find_element_by_id('id_new_item')
inputbox.send_keys('To Do')
inputbox.send_keys('To Do' + str(x))
inputbox.send_keys(Keys.ENTER)
# She notices when to do is greater or equal than five the comment is change
......
# Generated by Django 2.2.5 on 2019-12-01 10:08
from django.db import models, migrations
def find_dupes(apps, schema_editor):
List = apps.get_model("lists", "List")
for list_ in List.objects.all():
items = list_.item_set.all()
texts = set()
for ix, item in enumerate(items):
if item.text in texts:
item.text = '{} ({})'.format(item.text, ix)
item.save()
texts.add(item.text)
class Migration(migrations.Migration):
dependencies = [
('lists', '0004_item_list'),
]
operations = [
migrations.RunPython(find_dupes)
]
# Generated by Django 2.2.5 on 2019-12-01 10:09
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('lists', '0005_remove_duplicates'),
]
operations = [
migrations.AlterModelOptions(
name='item',
options={'ordering': ('id',)},
),
migrations.AlterUniqueTogether(
name='item',
unique_together={('list', 'text')},
),
]
# Generated by Django 2.2.5 on 2019-12-01 13:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lists', '0006_unique_together'),
]
operations = [
migrations.AddField(
model_name='item',
name='slug',
field=models.SlugField(blank=True),
),
]
# Generated by Django 2.2.5 on 2019-12-01 13:14
from django.db import migrations
from django.utils.text import slugify
def slugify(apps, schema_editor):
List = apps.get_model("lists", "List")
for list_ in List.objects.all():
items = list_.item_set.all()
for ix, item in enumerate(items):
item.slug = slugify(item.text)
item.save()
class Migration(migrations.Migration):
dependencies = [
('lists', '0007_item_slug'),
]
operations = [
migrations.RunPython(slugify)
]
......@@ -11,3 +11,8 @@ class List(models.Model):
class Item(models.Model):
text = models.TextField(default='')
list = models.ForeignKey(List, default=None, on_delete=models.CASCADE)
slug = models.SlugField(blank=True)
class Meta:
ordering = ('id',)
unique_together = ('list', 'text')
\ No newline at end of file
......@@ -137,5 +137,5 @@ class TodoMessageTest(TestCase):
def test_function_message_is_five(self):
_list = List.objects.create()
for i in range(5):
Item.objects.create(text='itemey 2', list=_list)
Item.objects.create(text='itemey 2' + str(i), list=_list)
self.assertEqual(message_todo(_list), "oh tidak")
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment