Fakultas Ilmu Komputer UI
Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
PMPL
Collection of Practice
2019
1606889830-practice
Commits
943e667b
Commit
943e667b
authored
Dec 01, 2019
by
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
Changes
8
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
README.md
View file @
943e667b
...
...
@@ -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
functional_tests/test_simple_list_creation.py
View file @
943e667b
...
...
@@ -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
...
...
lists/migrations/0005_remove_duplicates.py
0 → 100644
View file @
943e667b
# 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
)
]
lists/migrations/0006_unique_together.py
0 → 100644
View file @
943e667b
# 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'
)},
),
]
lists/migrations/0007_item_slug.py
0 → 100644
View file @
943e667b
# 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
),
),
]
lists/migrations/0008_add_data.py
0 → 100644
View file @
943e667b
# 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
)
]
lists/models.py
View file @
943e667b
...
...
@@ -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
lists/tests/test_views.py
View file @
943e667b
...
...
@@ -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"
)
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment