Anda di halaman 1dari 144

Database PostgreSQL, Pemrograman Python,

dan SMS Gateway

RAB Linux Indonesia

©2012
Daftar Isi

1 Alasan 5
2 Pemasangan 6
3 Hello World! 9
3.1 Variabel dan Tipe Datanya . . . . . . . . . . . . . . . . . . . . . 10
3.2 Kondisi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.3 Perulangan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

4 Tipe Data 17
4.1 String . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
4.2 Bilangan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4.2.1 Konversi Tipe Data . . . . . . . . . . . . . . . . . . . . . 19
4.2.2 Formatting . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.2.3 Kalkulator . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.3 List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.3.1 Pemenggalan . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.3.2 Keberadaan Elemen . . . . . . . . . . . . . . . . . . . . . 22
4.3.3 Mengubah Elemen . . . . . . . . . . . . . . . . . . . . . . 25
4.4 Di tionary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.5 Waktu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

5 Modularitas 31
5.1 Membuat Fungsi . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
5.2 Membuat Modul . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5.3 Sear h Path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

6 Fungsi 37
6.1 Memanggil Dirinya Sendiri . . . . . . . . . . . . . . . . . . . . . 37
6.2 Format Uang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

7 Database 42
7.1 Tabel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
7.1.1 Sequen e . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
7.1.2 Mengubah Struktur . . . . . . . . . . . . . . . . . . . . . 49

1
DAFTAR ISI 2

7.2 View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
7.3 Ba kup dan Restore . . . . . . . . . . . . . . . . . . . . . . . . . 53
7.3.1 En oding . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
7.4 Fungsi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
7.4.1 PL/pgSQL . . . . . . . . . . . . . . . . . . . . . . . . . . 56
7.4.2 PL/Python . . . . . . . . . . . . . . . . . . . . . . . . . . 61

8 Python Akses Database 63


8.1 A tive Re ord . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
8.2 Auto Commit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
8.3 Syn hronizer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
8.3.1 Aspek Keamanan . . . . . . . . . . . . . . . . . . . . . . . 74
8.3.2 Tambah, Perbaharui, Hapus . . . . . . . . . . . . . . . . . 76
8.4 Migrasi dari Database Lain . . . . . . . . . . . . . . . . . . . . . 78

9 Lintas Sistem 80
9.1 Command Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
9.2 File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
9.3 Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
9.4 XMLRPC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
9.4.1 PHP sebagai XMLRPC Client . . . . . . . . . . . . . . . 87
9.4.2 Drupal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88

10 Pengemasan 90
10.1 Paket Debian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
10.2 Debian Repository . . . . . . . . . . . . . . . . . . . . . . . . . . 95
10.3 Remastering Ubuntu . . . . . . . . . . . . . . . . . . . . . . . . . 96

11 Graphi al User Interfa e 99


11.1 Orientasi Objek . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
11.2 Daftar Pegawai . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

12 Obje t Oriented Programming 106


12.1 Lebih Terstruktur . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
12.2 Lebih Umum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
12.3 Tingkat Kerumitan . . . . . . . . . . . . . . . . . . . . . . . . . . 109

13 Kerja Sampingan 112


14 SMS Gateway 115
14.1 Pemasangan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
14.1.1 IMEI Chip . . . . . . . . . . . . . . . . . . . . . . . . . . 117
14.1.2 Database . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
14.2 Hello world! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
14.3 Instant Messenger Gateway . . . . . . . . . . . . . . . . . . . . . 119
14.3.1 Yahoo! Messenger . . . . . . . . . . . . . . . . . . . . . . 119
14.3.2 XMPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
DAFTAR ISI 3

14.4 Broad ast . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

15 Web 124
15.1 Django . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
15.2 Webpy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

16 Hosting 125
16.1 Virtualmin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
16.1.1 Pemasangan Ubuntu . . . . . . . . . . . . . . . . . . . . . 125
16.1.2 Kongurasi Network . . . . . . . . . . . . . . . . . . . . . 126
16.1.3 Pemasangan Virtualmin . . . . . . . . . . . . . . . . . . . 127
16.1.4 Text Editor . . . . . . . . . . . . . . . . . . . . . . . . . . 128
16.1.5 Kongurasi PHP . . . . . . . . . . . . . . . . . . . . . . . 129
16.1.6 Mail Server . . . . . . . . . . . . . . . . . . . . . . . . . . 129
16.1.7 PostgreSQL . . . . . . . . . . . . . . . . . . . . . . . . . . 130
16.1.8 Kongurasi Awal Virtualmin . . . . . . . . . . . . . . . . 130
16.1.9 Mail A ount . . . . . . . . . . . . . . . . . . . . . . . . . 131
16.1.10 Hak Akses . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
16.1.11 Berikan Bash . . . . . . . . . . . . . . . . . . . . . . . . . 132
16.1.12 Kongurasi Python . . . . . . . . . . . . . . . . . . . . . . 132
16.1.13 Mengubah Sifat Virtualmin . . . . . . . . . . . . . . . . . 133
16.1.14 Pendaftaran Domain . . . . . . . . . . . . . . . . . . . . . 138
16.1.15 User Spa e . . . . . . . . . . . . . . . . . . . . . . . . . . 139
16.2 Google Apps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
Kata Pengantar
Terimakasih saya u apkan untuk I Made Wiryana yang telah mengusulkan
Python kepada penulis untuk pertama kali. Juga kepada Arie Zanahar yang
mengusulkan penggunaan Virtualmin sebagai hosting management.

4
Bab 1

Alasan
Mengapa Python merupakan bahasa yang tepat untuk pembuatan berbagai
aplikasi ? Berikut ini alasannya.

Multiplatform Python merupakan bahasa pemrograman yang tersedia di berba-


gai platform seperti Linux, Windows, Ma , Unix. Bahkan sudah tersedia
di platform handphone seperti Symbian dan Android.

Mudah Python tergolong s ripting, artinya Anda ukup tulis sour e-nya di
text editor biasa, lalu jalankan.

Hemat Bahasa ini berkonsep hemat sour e. Tampak pada ara penulisannya
yang tidak membutuhkan karakter atau kata khusus untuk BEGIN dan
END. Sebagai gantinya sub-blo k dipisahkan dengan indent (penulisan
menjorok ke kanan).

Lalu mengapa PostgreSQL dipilih sebagai media penyimpanan datanya ?

Multiplatform PostgreSQL tersedia di Linux, Windows, Ma , dan Unix.

Lengkap PostgreSQL tergolong lengkap dan mudah dikembangkan. Memili-


ki sifat umum traditional database seperti transa tion, stored pro edure
(fun tion), dan trigger. Bahkan fun tion bisa ditulis dalam berbagai ba-
hasa (tidak hanya SQL), Python, Perl, Shell, dan Java adalah ontoh ba-
hasa yang didukungnya. Ia juga memiliki modul khusus untuk kebutuhan
GIS (Geographi Information System).

5
Bab 2

Pemasangan
Untuk memudahkan penjelasan, kita gunakan distro Linux berbasis Ubuntu.
Pada saat tulisan ini dibuat kami menggunakan Ubuntu 10.04 (Lu id). Anda
juga bisa menggunakan jenis Ubuntu lainnya seperti Kubuntu (window manager
KDE), atau BlankOn (buatan Indonesia).
Pas a instalasi Ubuntu Python sudah disertakan. Namun masih ada yang
perlu diunduh (download) lagi. Sebelumnya perbaharui daftar paket yang akan
diunduh, lakukan ini di konsole:

1 $ sudo a p t −g e t update

Pasang PostgreSQL:

1 $ sudo a p t −g e t install postgresql p o s t g r e s q l −p l p y t h o n −8.4


plpython digunakan saat kita membuat fun tion di PostgreSQL, alternatif
lain dari plpgsql yang terpasang se ara default.
Pasang SQLAl hemy agar Python bisa menggunakan PostgreSQL:

1 $ sudo a p t −g e t install python −s q l a l h e m y python −p s y o p g 2

Saat pemasangan paket postgresql se ara otomatis paket postgresql- lient-8.4


terpasang. Paket ini memuat psql yang digunakan untuk terhubung ke Post-
greSQL server, se ara ommand line. Ada baiknya Anda juga memasang versi
web-nya:

1 $ sudo a p t −g e t install phppgadmin

Kadang web server Apa he tidak otomatis hidup:

1 $ sudo / e t / i n i t . d/ apa he2 start

Se ara default Apa he hidup otomatis saat komputer boot. Lalu buatlah sym-
link phppgadmin:

1 $ sudo ln −s / u s r / s h a r e / phppgadmin / v a r /www/

Kemudian di browser (sebaiknya Firefox) buka url:

6
BAB 2. PEMASANGAN 7

http://lo alhost/phppgadmin

Bagi pengguna window manager Gnome Anda bisa gunakan gedit sebagai text
editor. Sedangkan pengguna KDE bisa gunakan kate. Keduanya berbasis GUI.
Jika Anda lebih nyaman dengan konsole bisa gunakan nano, joe, atau vi.

1 $ sudo a p t −g e t install vim

Kemudian sesuaikan /et /vim/vimr ,

1 $ sudo vi / e t / vim / v i m r

Biasanya option sudah disediakan, Anda tinggal menghapus tanda kutip di


awal option. Aktifkan pewarnaan agar nyaman saat memba a sour e:

1 " Vim5 and later versions support syntax highlighting .


Un ommenting the next
2 " line enables syntax highlighting by default .
3 syntax on

Saat Anda membuka le untuk keduakalinya, maka kursor langsung menuju
ke lokasi sebelumnya.

1 " Un omment the following to h a v e Vim jump to the last


position when
2 " reopening a file
3 if h a s ( " auto md " )
4 au BufReadPost * if l i n e ( " ' \ " " ) > 0 && l i n e ( " ' \ " " ) <=
l i n e (" $ ") | exe " normal g '\"" | endif
5 endif

Menjorok otomatis (auto indent), dan penekanan tombol TAB diganti den-
gan SPACE 4 kali:

1 " Un omment the following to h a v e Vim load indentation


rules a ording to the
2 " dete ted filetype . Per default D e b i a n Vim only load
filetype spe ifi
3 " plugins .
4 if h a s ( " auto md " )
5 filetype indent on
6 set smartindent
7 set expandtab
8 set t a b s t o p=4
9 set s o f t t a b s t o p =4
10 set s h i f t w i d t h =4
11 endif

Pen arian mengabaikan huruf besar atau ke il (in asesensitive).

1 set ignore ase " Do ase insensitive mat hing


BAB 2. PEMASANGAN 8

Bila kata yang di ari mengandung huruf besar dan huruf ke il, maka pen-
arian memperhatikan huruf besar atau ke il ( asesensitive).

1 set smart ase " Do s m a r t ase mat hing

Aktifkan kedua opsi pen arian di atas, maka pen arian di vim ( menggu-
nakan perintah slash / ) semakin mudah.
Bab 3

Hello World!
Anda bisa memulai Python dalam modus interaktif. Nanti kalau sour e sudah
mulai panjang kita simpan dalam le. Modus interaktif dijalankan di konsole,
lalu ketik:

1 $ python

maka sambutannya seperti ini:

1 Python 2.6.5 ( r265 : 7 9 0 6 3 , Apr 16 2010 , 13:57:41)


2 [GCC 4 . 4 . 3 ℄ on linux2
3 Type " help " , " opyright " , " redits" or " li ense " for more
4 information .
5 >>>

Mulailah dengan yang sederhana, menampilkan sebuah pesan menggunakan


perintah print.

1 >>> p r i n t ' Hello World ! '


2 Hello World !

Gunakan tombol panah atas untuk mengulang perintah sebelumnya, lalu ki-
ta oba sedikit salah satu iri pemgrograman berorientasi objek (obje t oriented
programming / OOP).

1 >>> p r i n t ' Hello World ! ' . u p p e r ( )


2 HELLO WORLD!
3 >>> p r i n t ' Hello World ! ' . l o w e r ( )
4 hello world !

'Hello World!' adalah sebuah string, yaitu DATA yang boleh berisi alphanu-
meri , boleh terdiri dari huruf dan angka atau karakter lainnya. Contoh di atas
menyebutkan bahwa string tidak hanya berisi data, ia juga memuat FUNGSI
yang bernama upper() dan lower(). Dengan demikian 'Hello World!' bukan
sekedar string, tapi disebut OBJEK string. Inilah iri objek, memuat data dan
fungsi.

9
BAB 3. HELLO WORLD! 10

Bingung ? Lupakan dulu pemrograman berorientasi objek. Untuk keluar


dari modus interaktif tekan Ctrl-D.

3.1 Variabel dan Tipe Datanya

Selain menggunakan kutip tunggal, string juga dapat dibatasi oleh kutip ganda:

1 >>> p r i n t " H a r i Jum ' a t "


2 H a r i Jum ' a t

Bila string lebih dari satu baris Anda bisa gunakan kutip tiga kali:

1 >>> p r i n t " " "Nama : Bummi Dwi Putera


2 ... Alamat : Bogor
3 ... Hobi : Menggambar " " "
4 Nama : Bummi Dwi Putera
5 Alamat : Bogor
6 Hobi : Menggambar

Perhatikan tiga buah titik di atas yang berarti sebuah perintah belum be-
rakhir.
Selanjutnya marilah membuat s ript yang akan menanyakan nama, alamat,
dan hobi, lalu menampilkannya kembali di layar. Kali ini kita simpan dalam
sebuah le pegawai.py. Anda bisa gunakan text editor favorit seperti gedit,
kate, nano, joe, atau vi.

Listing 3.1: pegawai.py

1 nama = r a w _ i n p u t ( ' Nama : ')


2 a l a m a t = r a w _ i n p u t ( ' Alamat : ')
3 h o b i = r a w _ i n p u t ( ' Hobi : ')
4 print ' Nama : ' , nama
5 print ' Alamat : ' , alamat
6 print ' Hobi : ' , hobi

Setelah disimpan jalankan:

1 $ python p e g a w a i . py

Lalu masukkan data seperti yang diminta:

1 Nama : Bummi Dwi Putera


2 Alamat : Bogor
3 Hobi : Menggambar

raw_input() adalah fungsi untuk menerima masukkan dari user. Fungsi ini
menghasilkan string yang berisi masukkan user tersebut, dan dilimpahkan ke
variabel nama, alamat, dan hobi. Anda bisa kembali ke modus interaktif untuk
sekedar mengetahui tipe data dari variabel nama.
BAB 3. HELLO WORLD! 11

1 >>> nama = r a w _ i n p u t ( ' Nama : ')


2 Nama : Bummi
3 >>> p r i n t t y p e ( nama )
4 <t y p e ' s t r '>

Pada s ript di atas kita mulai mengenal apa yang disebut variabel, yaitu
nama, alamat, dan hobi. Variabel bisa dikatakan sebagai penampung. Tipe
data ketiga variabel di atas adalah string. Mari kita oba tipe data lainnya.

1 >>> a = 3
2 >>> b = 5
3 >>> p r i n t a + b
4 8
5 >>> p r i n t type ( a )
6 <t y p e ' i n t '>

Variabel a dan b bertipe integer alias bilangan bulat. Berikut ini untuk
bilangan pe ahan (oat).

1 >>> = 7 . 2
2 >>> p r i n t type ( )
3 <t y p e ' f l o a t '>

Ya, pemisah bilangan bulat dengan pe ahannya adalah dengan titik. Oh ya,
Python tergolong ketat dalam hal pengoperasian antar tipe data. Kita tidak
diperkenankan menambahkan string dengan integer.

1 >>> nama = ' Bummi '


2 >>> umur = 2 4
3 >>> p r i n t nama + ' usia ' + umur + ' tahun '
4 Tra eba k ( most re ent all last ) :
5 File "< s t d i n >" , line 1, i n <module>
6 TypeError : annot on atenate ' str ' and ' int ' obje ts

Untuk mengatasinya jadikan variabel umur menjadi string:

1 >>> p r i n t nama + ' usia ' + s t r ( umur ) + ' tahun '


2 Bummi usia 24 tahun

Atau dengan ara lain yg lebih mudah diba a:

1 >>> p r i n t '% s u s i a %s tahun ' % ( nama , umur )


2 Bummi usia 24 tahun

Meski string tidak bisa ditambah dengan integer, namun string bisa dikalikan
dengan integer:

1 >>> p r i n t ' ab ' * 10


2 a b a b a b a b a b a b ab ab ab ab

Kembali ke le pegawai.py, tidak diperkenankan menulis tidak rapi. Cobal-


ah membuat kesalahan di baris terakhir pada le pegawai.py, yaitu dengan
menambahkan dua spasi sebelum print:
BAB 3. HELLO WORLD! 12

1 nama = r a w _ i n p u t ( ' Nama : ')


2 a l a m a t = r a w _ i n p u t ( ' Alamat : ')
3 h o b i = r a w _ i n p u t ( ' Hobi : ')
4 print ' Nama : ', nama
5 print ' Alamat : ', alamat
6 print ' Hobi : ', hobi

Kemudian jalankan:

1 $ python p e g a w a i . py

hasilnya Python protes karena ada indent (menjorok masuk) yang tidak
diperkenankan:

1 $ python p e g a w a i . py
2 File " p e g a w a i . py " , line 6
3 print ' Hobi : ', hobi
4 ^
5 IndentationError : unexpe ted indent

Seperti kita lihat, s ript Python tanpa diawali suatu BEGIN .. END atau
{ .. } atau berbagai penanda lainnya sebagai bentuk awal dan akhir program.
Baris-baris utama selalu tanpa indent alias rapat kiri. Baris yang memiliki
indent berarti dianggap bagian dari sub-blok seperti dalam looping (for) atau
kondisi (if ).

1 nama = r a w _ i n p u t ( ' Nama : ')


2 a l a m a t = r a w _ i n p u t ( ' Alamat : ')
3 h o b i = r a w _ i n p u t ( ' Hobi : ')
4 print ' Nama : ', nama
5 print ' Alamat : ', alamat
6 if hobi :
7 print ' Hobi : ', hobi

S ript di atas berarti jika hobi diisi maka ditampilkan.

3.2 Kondisi

Python punya sema am pedoman dalam hal kondisi (if ), dimana jika suatu
variabel ada isinya maka True, jika kosong maka False.

1 if hobi :
2 print ' Hobi : ', hobi

bisa juga ditulis dengan

1 if hobi != ' ':


2 print ' Hobi : ', hobi

Se ara tipe data hobi tentulah sebuah string, tapi bagaimana dengan hobi
!=  ? Mari kita uji di modus interaktif dimana variabel hobi ada isinya.
BAB 3. HELLO WORLD! 13

Tipe False True (Contoh)

String  'ab '


Integer 0 1
Float 0 1.2
List [℄ [10,20,30℄
Di tionary {} {'nama': 'Bummi', 'alamat': 'Bogor'}
Objek None True

Tabel 3.1: Kondisi False di berbagai tipe data

1 >>> h o b i = ' Menggambar '


2 >>> h o b i != ''
3 True
4 >>> h o b i == ''
5 False

Lalu obalah variabel hobi kosong.

1 >>> h o b i = ''
2 >>> h o b i != ''
3 False
4 >>> h o b i == ''
5 True

Pahami baik-baik perbedaan keduanya. Perhatikan juga penggunaan karak-


ter samadengan dua kali ( == ) yang berarti operasi logika (boolean operation).

1 >>> k o s o n g = h o b i == ''
2 >>> p r i n t kosong
3 True

Kembali ke pegawai.py dimana bila hobi tidak diisi maka program akan
memberikan saran. Salinlah menjadi pegawai1.py seperti berikut ini.

Listing 3.2: pegawai1.py

1 nama = r a w _ i n p u t ( ' Nama : ')


2 a l a m a t = r a w _ i n p u t ( ' Alamat : ')
3 h o b i = r a w _ i n p u t ( ' Hobi : ')
4 print ' Nama : ' , nama
5 print ' Alamat : ' , alamat
6 if hobi :
7 print ' Hobi : ' , hobi
8 else :
9 print ' Sebaiknya hobi diisi . '

else digunakan untuk kondisi sebaliknya (False). Bagaimana jika kondisi


tambahan ? Misalkan jika hobinya menggambar maka pesan untuk hadir di
hari Sabtu ditampilkan.
BAB 3. HELLO WORLD! 14

Listing 3.3: pegawai2.py

1 nama = r a w _ i n p u t ( ' Nama : ')


2 a l a m a t = r a w _ i n p u t ( ' Alamat : ')
3 h o b i = r a w _ i n p u t ( ' Hobi : ')
4 print ' Nama : ' , nama
5 print ' Alamat : ' , alamat
6 if h o b i . u p p e r ( ) == 'MENGGAMBAR' :
7 print ' Datanglah di pelatihan gambar setiap Sabtu . '
8 elif hobi :
9 print ' Hobi : ' , hobi
10 else :
11 print ' Sebaiknya hobi diisi . '

Perhatikan juga penggunaan titik dua ( : ) pada if dan else. Ini iri lain
untuk menandai awal suatu sub-blok. Jadi bisa dipastikan setelah titik dua
baris berikutnya selalu menjorok ke dalam (indent).

3.3 Perulangan

Mari kita buat input pegawai jadi lebih mudah, dimana program akan menanyakan
data terus-menerus dan baru berhenti bila nama tidak diisi.

Listing 3.4: pegawai3.py

1 while True :
2 nama = r a w _ i n p u t ( ' Nama : ')
3 if not nama :
4 break
5 a l a m a t = r a w _ i n p u t ( ' Alamat : ')
6 h o b i = r a w _ i n p u t ( ' Hobi : ')
7 print ' Nama : ' , nama
8 print ' Alamat : ' , alamat
9 if hobi :
10 print ' Hobi : ' , hobi
11 else :
12 print ' Sebaiknya hobi diisi . '

Perhatikan baris pertama yang berarti perulangan tanpa henti. Yang menghen-
tikannya adalah baris ke empat. break adalah kata khusus untuk menghentikan
perulangan dimana alur keluar menuju blok bawah di luar perulangan tersebut.
Kebetulan dalam ontoh ini tidak ada blok lain di luar perulangan.
Selanjutnya kita buat aturan baru untuk pengisian data ini, dimana:

1. Nama dan alamat harus diisi.

2. Bila selesai satu data pegawai maka program akan menanyakan apakah
akan memasukkan data berikutnya.
BAB 3. HELLO WORLD! 15

Di sini akan kita ubah sedikit logika while-nya.

Listing 3.5: pegawai4.py

1 lanjut = 'Y '


2 while lanjut != 'S ' :
3 nama = r a w _ i n p u t ( ' Nama : ')
4 if not nama :
5 print ' Nama h a r u s diisi . '
6 ontinue
7 a l a m a t = r a w _ i n p u t ( ' Alamat : ')
8 if not alamat :
9 print ' Alamat harus diisi . '
10 ontinue
11 h o b i = r a w _ i n p u t ( ' Hobi : ')
12 print ' Nama : ' , nama
13 print ' Alamat : ' , alamat
14 if hobi :
15 print ' Hobi : ' , hobi
16 else :
17 print ' Sebaiknya hobi diisi . '
18 lanjut = r a w _ i n p u t ( ' Tekan "S" jika selesai : ' ) . upper ( )

ontinue pada baris ke 6 menandakan alur kembali ke while pada baris ke 2.


Perhatikan juga penggunaan raw_input() pada baris terakhir. Karena fungsi
ini mengembalikan nilai string maka kita bisa lanjutkan dengan memanggil
fungsi upper(). Dengan ara ini user diperbolehkan memasukkan dengan s ke il
maupun S besar.
while o ok untuk perulangan yang kondisinya tidak menentu. Bagaimana
bila kita butuh perulangan yang jumlahnya sudah diketahui ? Misalkan etak
angka 1 hingga 5.

1 for i in [1 ,2 ,3 ,4 ,5℄:
2 print i

Hasilnya:

1
2
3
4
5

Perhatikan [1,2,3,4,5℄ yang merupakan data bertipe list atau sering juga disebut
sebagai array. Kita bisa persingkat penulisannya dengan fungsi range().

1 for i in range ( 5 ) :
2 print i

Hasilnya
BAB 3. HELLO WORLD! 16

0
1
2
3
4

Meski tidak dimulai dari 1 tapi jumlah barisnya tetap 5. Jika tetap ingin dimulai
dari 1 gunakan range(1,6).

1 for i in range ( 1 , 6 ) :
2 print i

Karena for merupakan perulangan juga sebagaimana while, maka perintah


break dan ontinue juga berlaku di dalamnya.
Bab 4

Tipe Data
Memperhatikan tipe data salah satu pokok pada Python dan ini juga menjadi
salah satu kun i agar mudah dalam pen arian kesalahan (debugging).

4.1 String

Sudah dibahas sebelumnya bagaimana menuliskan data bertipe string.

1 >>> nama = ' Agus '

Atau bisa juga menggunakan kutip ganda.

1 >>> nama = Agus

Jika Anda butuh kutip tunggal di dalam string, siasatilah.

1 >>> h a r i = Jum ' a t

Masih belum yakin apa tipe data variabel nama ? Gunakan type().

1 >>> t y p e ( nama )
2 <t y p e ' s t r '>

Data bertipe string bisa berisi karakter apa saja seperti huruf, angka, tanda
ba a, atau gabungannya.
Menggabungkan dua buah variabel string bisa menggunakan tanda plus ( +
).

1 >>> p r i n t nama + ' lahir hari ' + hari


2 Agus lahir hari Jum ' a t

Namun ara ini tidak disarankan karena membuat program menjadi sulit
diba a. Kalau program sulit diba a menyulitkan penelusuran bila ada kesalahan
(debugging). Jadi sebaiknya gunakan formatting.

1 >>> p r i n t '% s lahir h a r i %s ' % ( nama , hari )


2 Agus lahir hari Jum ' a t

17
BAB 4. TIPE DATA 18

Lalu bagaimana menampilkan % itu sendiri di dalam formatting ? Sebutkan-


lah dua kali.

1 >>> p r i n t ' Keuntungan bulan ini m e n i n g k a t %d %%' % ( 1 0 )


2 Keuntungan bulan ini meningkat 10 %

4.2 Bilangan

Bilangan bulat atau integer atau disingkat int dinyatakan tanpa titik.

1 >>> a = 1 0

a ditambah 2

1 >>> a + 2
2 12

a dikurang 4

1 >>> a − 4
2 6

a dikali 5

1 >>> a * 5
2 50

a dibagi dengan 3

1 >>> a / 3
2 3

Mengapa bukan 3.3333 ?


Pembagian bilangan bulat dengan bilangan bulat menghasilkan bilangan bu-
lat juga. Jika Anda mengharapkan hasil yang lebih rin i maka salah satunya
harus bilangan pe ahan (oat).

1 >>> a / 3.0
2 3.3333333333333335

Untuk mendapatkan sisa pembagian (modulus) gunakan tanda persen ( %


).

1 >>> a % 3
2 1

a pangkat 2

1 >>> a ** 2
2 100
BAB 4. TIPE DATA 19

4.2.1 Konversi Tipe Data


Konversi dari string menjadi bilangan bulat menggunakan fungsi int().

1 >>> i n t ( ' 1 0 ' )


2 10

int() juga dapat digunakan untuk pembulatan.

1 >>> i n t ( 1 0 . 2 )
2 10

Untuk pembulatan yang mendekati gunakan round().

1 >>> r o u n d ( 1 0 . 4 )
2 10
3 >>> r o u n d ( 1 0 . 5 )
4 11

round() akan membulatkan ke bawah bila pe ahan suatu bilangan lebih ke il


dari 0,5. Sebaliknya ia akan membulatkan ke atas.
Untuk konversi dari string menjadi bilangan pe ahan menggunakan fungsi
oat().

1 >>> float ( '10.5 ')


2 10.5

4.2.2 Formatting
Menuliskan bilangan ke dalam string bisa menggunakan formatting.

1 >>> a = 3
2 >>> b = 2
3 >>> p r i n t '% s + %s = %s ' % ( a , b, a+b )
4 3 + 2 = 5

Meski formatting %s bisa digunakan untuk tipe data apa saja, sebaiknya An-
da menggunakan formatting yang lebih spesik sesuai tipe datanya. Katakanlah
Anda menetapkan bahwa variabel a itu harus bertipe bilangan bulat (integer),
begitu pula dengan variabel b, maka gunakanlah %d.

1 >>> p r i n t '%d + %d = %d ' % ( a , b, a+b )


2 3 + 2 = 5

Untuk bilangan pe ahan (oat) gunakan %f.

1 >>> a = 3 . 5
2 >>> p r i n t '% f + %f = %f ' % ( a , b, a+b )
3 3.500000 + 2.000000 = 5.500000

Anda juga bisa mengatur jumlah digit di belakang koma.

1 >>> print '%.2f + %.2 f = %.2f ' % (a , b , a +b)


2 3.50 + 2.00 = 5.50
BAB 4. TIPE DATA 20

4.2.3 Kalkulator
Membuat kalkulator tidaklah sulit, Anda ukup gunakan eval(). Buatlah le
al .py berikut ini.

Listing 4.1: al .py

1 while True :
2 h i t u n g = raw_input ( ' Hitung : ')
3 if not hitung :
4 break
5 print eval ( hitung )

Jalankan.

1 $ python a l . py
2 Hitung : 2+3
3 5
4 Hitung : 7 ** 2
5 49
6 Hitung : 7 + 2 * 3
7 13
8 Hitung :
9 $

Perhatikan baik-baik. Semua kalimat Python diterjemahkan oleh eval(), baik


kalimat itu mengandung spasi ataupun tidak, eval() sanggup memahaminya.
Mudah bukan?
Perhatikan juga kalimat 7 + 2 * 3 yang menghasilkan nilai 13. Ini artinya
aturan prioritas pada matematika umum berlaku, dimana perkalian lebih dulu
dilakukan ( 2 * 3 ). Barulah hasilnya ( 6 ) ditambahkan dengan 7.
Program di atas akan terus meminta masukkan dari user hingga tombol
Enter saja yang ditekan.

4.3 List

Tipe data list kerap digunakan. Kita lihat pada ontoh sebelumnya bagaimana
list menjadi wajib pada perulangan for. Bahkan string sebenarnya bisa dianggap
sebagai list.

1 for h in ' Bummi ' :


2 print h ,

hasilnya:

1 Bummi

Perhatikan penggunaan koma pada print yang berarti jangan ganti baris.
Mari kembali ke modus interaktif untuk men oba list.
BAB 4. TIPE DATA 21

Gambar 4.1: Struktur list

1 >>> d a t a = [ ' Bummi Dwi P u t e r a ' , ' Bogor ' , ' Menggambar ' , 2 4 ℄
2 >>> p r i n t data [ 0 ℄
3 ' Bummi Dwi Putera '
4 >>> p r i n t data [ 1 ℄
5 ' Bogor '

Tampilkan elemen terakhir:

1 >>> p r i n t data [ −1℄


2 24

Elemen kedua dari terakhir:

1 >>> p r i n t data [ −2℄


2 ' Menggambar '

4.3.1 Pemenggalan
Selain dapat diambil per elemen, juga dapat diambil beberapa elemen sekali-
gus, ini disebut sebagai pemenggalan (sli ing). Tampilkan elemen pertama dan
kedua:

1 >>> p r i n t data [ 0 : 2 ℄
2 [ ' Bummi Dwi Putera ' , ' Bogor ' ℄

Atau ukup ditulis tanpa 0:

1 >>> p r i n t data [ : 2 ℄
2 [ ' Bummi Dwi Putera ' , ' Bogor ' ℄

Tampilkan 3 elemen terakhir:

1 >>> p r i n t data [ −3:℄


2 [ ' Bogor ' , ' Menggambar ' , 24℄

Ada baiknya kita pahami ara kerjanya. Pemenggalan list bekerja dengan
batas elemen. Gambar 4.1 adalah ontoh string Python yang bisa dianggap
sebagai list. Cermati baik-baik bagaimana bekerja dengan elemen dan batas
elemen (untuk pemenggalan).
BAB 4. TIPE DATA 22

4.3.2 Keberadaan Elemen


Anda memiliki daftar nama buah yang dapat di ari oleh user. Setelah user
memasukkan nama buah program akan men arinya dalam list dan memberi-
tahukan hasilnya. Setelah itu program akan kembali menanyakan nama buah
berikutnya. Program berakhir jika user hanya menekan Enter saja, alias tidak
memasukkan apapun. Sekarang buatlah produk.py berikut ini.

Listing 4.2: produk.py

1 d a f t a r = [ ' j e r u k ' , ' mangga ' , ' a p e l ' , ' p i s a n g ' , ' jambu ' ℄
2
3 while True :
4 a r i = raw_input ( ' C a r i buah : ')
5 if not ari :
6 print ' Selesai '
7 break
8 if in
ari daftar :
9 print ( ' Ditemukan ' )
10 else :
11 print ( ' Tidak ditemukan ' )

Jalankanlah.

1 $ python p r o d u k . py
2 Cari buah : mangga
3 Ditemukan
4 Cari buah : duku
5 Tidak ditemukan
6 Cari buah :
7 Selesai

Keberadaan elemen bisa digunakan sebagai kondisi. Misalkan program Anda


dapat menerima masukan (input parameter) sesaat sebelum dijalankan, sering
disebut sebagai argument. Seperti pada ontoh at.py berikut ini.

Listing 4.3: at.py

1 import sys
2 print sys . argv

Jalankanlah.

1 $ python a t . py
2 [ ' a t . py ' ℄

Jalankan lagi dengan input parameter.

1 $ python a t . py /et /hosts


2 [ ' a t . py ' , '/ et / hosts ' ℄

Perhatikan elemen pertama adalah le at.py itu sendiri, dan elemen kedua
adalah nama le yang akan ditampilkan. Ya, kita akan membuatnya dapat
membuka le yang disebutkan dan menampilkannya di layar.
BAB 4. TIPE DATA 23

Listing 4.4: at1.py

1 import sys
2
3 f i l e n a m e = sys . argv [ 1 ℄
4 f = open ( f i l e n a m e )
5 print f . read ( )
6 f . lose ()

Jalankan.

1 $ python a t 1 . py /et /hosts


2 127.0.0.1 lo alhost ompaq
3 127.0.1.1 ompaq
4
5 # The following lines are desirable for IPv6 apable
hosts
6 ::1 lo alhost i p 6−l o a l h o s t i p 6 −l o o p b a k
7 fe00 : : 0 i p 6−l o a l n e t
8 ff00 ::0 i p 6 −m a s t p r e f i x
9 ff02 ::1 i p 6 −a l l n o d e s
10 ff02 ::2 ip6−a l l r o u t e r s
11 ff02 ::3 ip6−a l l h o s t s

Kita perlu mengantisipasi kesalahan yang dilakukan user, dimana bisa saja
ia tidak tahu ara menggunakan at1.py, yaitu langsung menjalankan tanpa
menyertakan nama le.

1 $ python a t 1 . py
2 Tra eba k ( most re ent all last ) :
3 File " a t . py " , line 3, i n <module>
4 f i l e n a m e = sys . argv [ 1 ℄
5 IndexError : list index out of range

Tampilan kesalahan ini jelas kurang informatif dan bisa jadi user tidak tahu
apa yang harus dilakukan. Saatnya menggunakan deteksi keberadaan elemen.

Listing 4.5: at2.py

1 import sys
2
3 if not sys . argv [ 1 : ℄ :
4 print ( ' Cara menggunakannya : p y t h o n %s <nama− f i l e > ' %
sys . argv [ 0 ℄ )
5 sys . exit ()
6
7 f i l e n a m e = sys . argv [ 1 ℄
8 f = open ( f i l e n a m e )
9 print f . read ( )
10 f . lose ()
BAB 4. TIPE DATA 24

Jalankanlah tanpa input parameter,

1 $ python a t 2 . py
2 Cara menggunakannya : python a t . py <nama− f i l e >

Kini program akan menampilkan petunjuk ara menggunakannya. Mari kita


bahas ara kerjanya.
Perhatikan baris ketiga

if not sys.argv[1:℄:

Kalau kita perhatikan lagi isi dari sys.argv pada saat tidak diberikan input
parameter adalah:

[' at.py'℄

Dengan begitu sys.argv[1:℄ akan bernilai list hampa:

[℄

Ingatlah mengenai pemenggalan list pada pembahasan sebelumnya. Bila suatu


variabel hampa maka ia bisa dianggap sebagai boolean False, sehingga

if not sys.argv[1:℄:

bisa berarti

if not [℄:

yang berarti

if not False:

dan ini bisa diartikan menjadi:

if True:

True berarti kondisi terpenuhi dan blok di dalam if dijalankan, dan akhirnya
tampillah pesan ara penggunaan at2.py tadi.
Lalu apa yang terjadi jika program mendapat input parameter ? Nilai
sys.argv menjadi

[' at.py', '/et /hosts'℄

Dengan begitu

if not sys.argv[1:℄:

bisa berarti

if not ['/et /hosts'℄:


BAB 4. TIPE DATA 25

Karena ['/et /hosts'℄ adalah list yang berisi (tidak hampa) maka bisa dianggap
sebagai boolean True

if not True:

dan ini berarti juga

if False:

False berarti kondisi tidak terpenuhi sehingga blok di dalam if tidak dijalankan.
Pahamilah baik-baik penjelasan ini, Anda akan banyak menemuinya nanti.
Inilah salah satu mengapa program yang dibuat dengan Python begitu ringkas
namun tetap mudah diba a.

4.3.3 Mengubah Elemen


Contoh sebelumnya menjelaskan bagaimana menggunakan list. Kini kita oba
berawal dari list hampa dan mengisinya dengan elemen data. Kembali ke modus
interaktif.

1 >>> d a f t a r = [℄
2 >>> d a f t a r
3 [℄

Tambahkan mangga.

1 >>> d a f t a r . append ( ' mangga ' )


2 >>> d a f t a r
3 [ ' mangga ' ℄

Bisa juga dengan ara lain.

1 >>> d a f t a r += [ ' p i s a n g ' ℄


2 >>> d a f t a r
3 [ ' mangga ' , ' pisang ' ℄

Kita akan ubah elemen kedua (index ke 1) dari pisang menjadi jeruk.

1 >>> d a f t a r [ 1 ℄ = ' jeruk '


2 >>> d a f t a r
3 [ ' mangga ' , ' jeruk ' ℄

Selanjutnya mangga dihapus yang berarti elemen pertama atau index ke 0.

1 >>> d e l daftar [ 0 ℄
2 >>> d a f t a r
3 [ ' jeruk ' ℄
BAB 4. TIPE DATA 26

4.4 Di tionary

List adalah serangkaian elemen yang alamatnya adalah nomor urut, sering
disebut sebagai index. Di tionary juga mirip, hanya saja alamatnya tidak harus
berupa angka yang berurutan. Bahkan bisa bertipe string atau tipe data lain-
nya. Sekarang buatlah s ript berikut ini.

Listing 4.6: produk1.py

1 daftar = {
2 2: ' jeruk ' ,
3 7: ' mangga ' ,
4 4: ' pisang ' ,
5 3: ' jambu ' ,
6 9: ' apel ' ,
7 }
8
9 print daftar

Jalankan.

1 $ python p r o d u k 1 . py
2 {9: ' apel ' , 2: ' jeruk ' , 3: ' jambu ' , 4: ' pisang ' , 7: '
mangga ' }

Perhatikan urutan pada sour e, dan bandingkan urutan buah saat dita-
mpilkan. Begitulah di tionary, dia memang tidak memperhatikan urutan. Ini-
lah salah satu yang membedakannya dengan list. Di tionary o ok untuk pen-
arian. Pada ontoh di atas angka 2, 7, 4, 3, dan 9 merupakan kun i (key)
bagi variabel daftar. Key ini bisa saja dianggap sebagai kode barang atau kode
buah. Sedangkan apel, jeruk, jambu, pisang, dan mangga merupakan nilai (val-
ue). Karena itu di tionary sering disebut sebagai tipe data dengan formasi key
value.
Sekarang kita buat pen arian berdasarkan kode barang.

Listing 4.7: produk2.py

1 daftar = {
2 2: ' jeruk ' ,
3 7: ' mangga ' ,
4 4: ' pisang ' ,
5 3: ' jambu ' ,
6 9: ' apel ' ,
7 }
8
9 while True :
10 k e y = r a w _ i n p u t ( ' Kode barang : ')
11 if not key :
12 print ' Selesai '
13 break
BAB 4. TIPE DATA 27

14 if key in daftar :
15 print d a f t a r [ key ℄
16 else :
17 print ' Kode barang ' , key , ' tidak ditemukan '

Cobalah.

1 $ python p r o d u k 2 . py
2 Kode barang : 5
3 Kode barang 5 tidak ditemukan
4 Kode barang : 9
5 Kode barang 9 tidak ditemukan
6 Kode barang :
7 Selesai

Kode barang 5 boleh jadi tidak ditemukan, karena memang tidak ada 5
dalam variabel daftar. Tapi mengapa 9 juga tidak ditemukan ? Seharusnya
program menampilkan apel.
Jawabannya ada pada tipe data. Fungsi raw_input() itu mengembalikan
nilai bertipe string. Berarti key pada baris

key = raw_input('Kode barang: ')

juga bertipe string. Lalu

if key in daftar:

berarti men ari string key dalam daftar yang isinya bilangan bulat (integer)
semua, yaitu 2, 7, 4, 3, dan 9. Jelas tidak akan ditemukan. Untuk membuktikan
bahwa key itu adalah string ubahlah sedikit pada baris terakhir

print 'Kode barang', key, 'tidak ditemukan'

menjadi

print 'Kode barang', [key℄, 'tidak ditemukan'

Coba jalankan lagi.

1 $ python p r o d u k 2 . py
2 Kode barang : 9
3 Kode barang [ '9 '℄
4 tidak ditemukan
5 Kode barang :
6 Selesai

Dengan memberikan kurung siku pada variabel maka akan tampak bahwa
key adalah string. Terlihat adanya kutip tunggal pada '9'. Lalu bagaimana
mengubah key agar bertipe integer ? Gunakan fungsi int().
BAB 4. TIPE DATA 28

Listing 4.8: produk3.py

1 daftar = {
2 2: ' jeruk ' ,
3 7: ' mangga ' ,
4 4: ' pisang ' ,
5 3: ' jambu ' ,
6 9: ' apel ' ,
7 }
8
9 while True :
10 k e y = r a w _ i n p u t ( ' Kode barang : ')
11 if not key :
12 print ' Selesai '
13 break
14 key = i n t ( key )
15 if in
key daftar :
16 print d a f t a r [ key ℄
17 else :
18 print ' Kode barang ' , key , ' tidak ditemukan '

Jalankan lagi.

1 $ python p r o d u k 3 . py
2 Kode barang : 5
3 Kode barang [5℄ tidak ditemukan
4 Kode barang : 9
5 apel
6 Kode barang :
7 Selesai

Resapi kembali mengenai tipe data ini karena akan sering dijumpai nanti.

4.5 Waktu

Modul time digunakan untuk penanganan waktu. Kita kembali ke modus inter-
aktif dulu untuk memudahkan latihan.

1 >>> i m p o r t time
2 >>> t = t i m e . l o a l t i m e ( )
3 >>> t
4 t i m e . s t r u t _ t i m e ( tm_year = 2 0 1 0 , tm_mon=8 , tm_mday=20 ,
tm_hour =11 , tm_min=44 , tm_se =47 , tm_wday=4 , tm_yday
=232 , t m _ i s d s t =0)

Fungsi time.lo altime() digunakan untuk mendapatkan waktu saat ini. Per-
hatikan variabel t di atas. Jika Anda ingin mengambil tahunnya:

1 >>> t . tm_year
2 2010
BAB 4. TIPE DATA 29

atau bulannya

1 >>> t . tm_mon
2 8

atau harinya

1 >>> t . tm_mday
2 20

dan seterusnya hingga jam, menit, dan detiknya, ada di sana.


Waktu juga bisa diwujudkan dalam bilangan pe ahan (oat), sering disebut
sebagai epo h atau Unix time.

1 >>> t i m e . t i m e ( )
2 1282280699.2280381

Epo h ini adalah jumlah detik sejak 1 Januari 1970 jam 00:00:00 (GMT)
hingga saat ini.
Fungsi time.lo altime() sebenarnya bisa diberikan masukan berupa epo h
ini. Kita bisa mulai dengan angka 0.

1 >>> t i m e . l o a l t i m e ( 0 )
2 t i m e . s t r u t _ t i m e ( tm_year = 1 9 7 0 , tm_mon=1 , tm_mday=1 ,
tm_hour=7 , tm_min=0 , tm_se =0 , tm_wday=3 , tm_yday=1 ,
t m _ i s d s t =0)

Epo h 0 berarti 1 Januari 1970. Lalu mengapa tm_hour menunjukkan angka


7 ? Ini terkait dengan zona waktu (timezone) pada komputer yang berarti
wilayah Jakarta (+7). Jika komputer Anda diset pada zona waktu Bali maka
nilai tm_hour menjadi 8.
Untuk mendapatkan epo h pada tanggal 17 Agustus 2010 maka bisa gunakan
time.mktime():

1 >>> t i m e . mktime ( ( 2 0 1 0 , 8 , 1 7 , 0 , 0 , 0 , 0 , 0 , 0 ) )
2 1281978000.0

Dengan epo h kita bisa mendapatkan jumlah hari sejak 1 Agustus 2010
hingga 17 Agustus 2010.

1 >>> a w a l = t i m e . mktime ( ( 2 0 1 0 , 8 , 1 , 0 , 0 , 0 , 0 , 0 , 0 ) )
2 >>> a k h i r = t i m e . mktime ( ( 2 0 1 0 , 8 , 1 7 , 0 , 0 , 0 , 0 , 0 , 0 ) )
3 >>> a k h i r − awal
4 1382400.0

Itu adalah jumlah detiknya. Untuk mendapatkan hari kita perlu mengolah-
nya kembali.

1 >>> ( a k h i r − awal ) / 24 / 60 / 60
2 16.0

Sehingga diperoleh 16 hari.


BAB 4. TIPE DATA 30

Modul datetime
Menghitung hari lebih mudah menggunakan modul datetime.

1 >>> f r o m datetime import date


2 >>> a w a l = d a t e ( 2 0 1 0 , 8 , 1 )
3 >>> a k h i r = d a t e ( 2 0 1 0 , 8 , 1 7 )
4 >>> d = a k h i r − awal
5 >>> d . d a y s
6 16

Dengan modul ini kita juga dapat menghitung jumlah detik sejak 16 Agustus
2010 jam 22:00 hingga 17 Agustus 2010 jam 10:00.

1 >>> f r o m datetime import datetime


2 >>> a w a l = d a t e t i m e ( 2 0 1 0 , 8 , 1 6 , 2 2 , 0 , 0 )
3 >>> a k h i r = d a t e t i m e ( 2 0 1 0 , 8 , 1 7 , 1 0 , 0 , 0 )
4 >>> d = a k h i r − awal
5 >>> d . s e o n d s
6 43200

Untuk mendapatkan jumlah jamnya:

1 >>> d . s e o n d s / 60 / 60
2 12
Bab 5

Modularitas
Mari kita buat program yang menghitung nilai faktorial. Apa itu faktorial ?
Berikut ini ontohnya:

5! = 5 * 4 * 3 * 2 * 1 = 120
4! = 4 * 3 * 2 * 1 = 24
3! = 3 * 2 * 1 = 6
2! = 2 * 1 = 2
1! = 1
0! = 1
-1! = 1
Dengan demikian rumus faktorial memiliki ketentuan:

1. Jika n < 2 maka n! = 1

2. n! = n * (n-1)!

Selanjutnya kita akan buat program yang akan menanyakan nilai n dan menampilkan
nilai faktorial-nya.

Listing 5.1: faktorial1.py

1 print ' Menghitung nilai faktorial '


2 while True :
3 n = raw_input ( ' n = ')
4 if not n:
5 break
6 n = int (n)
7 if n < 2:
8 f = 1
9 else :
10 f = 1
11 for in i r a n g e ( 1 , n+1) :
12 *
f = f i
13 print '%d ! = %d ' % ( n , f)

31
BAB 5. MODULARITAS 32

Jalankan.

1 $ python f a k t o r i a l 1 . py
2 Menghitung nilai faktorial
3 n = 2
4 2! = 2
5 n = 3
6 3! = 6
7 n = 4
8 4 ! = 24
9 n =
10 $

Selesai sudah. Berikutnya Anda diminta membuatnya dalam lingkungan


gras (graphi al user interfa e / GUI). Tentu saja tidak ada lagi yang namanya
raw_input() dan print, karena ia digunakan untuk lingkungan teks ( onsole).
Juga tidak ada lagi while karena GUI sudah mengatur perulangannya.
Lalu apa yang diambil untuk mengambil sour e faktorial ? Baris 6 - 12
saja yang perlu di- opy-paste di sour e GUI nanti. Anda juga harus menye-
suaikan variabel n yang menjadi masukannya, karena n tidak lagi berasal dari
raw_input() melainkan dari komponen GUI.
Di sini mulai terasa sour e faktorial di atas tidak modular karena menyulitkan
opy-paste. Kesulitan yang dimaksud adalah sour e faktorial menyatu dengan
sour e yang mengurus tampilan. Faktorial adalah ontoh sederhana, bagaimana
kalau nanti Anda diminta membuat rumus lainnya yang jauh lebih rumit ?

5.1 Membuat Fungsi

Sudah saatnya Anda mengenal pembuatan fungsi. Dengannya Anda pisahkan


urusan menghitung nilai faktorial dengan urusan input dan output tampilannya.

Listing 5.2: faktoria2l.py

1 def f akt ori al (n) :


2 if n < 2:
3 return 1
4 f = 1
5 for in
i r a n g e ( 1 , n+1) :
6 f = f * i
7 return f
8
9
10 print ' Menghitung nilai faktorial '
11 while True :
12 n = raw_input ( ' n = ')
13 if not n:
14 break
BAB 5. MODULARITAS 33

15 n = int (n)
16 h a s i l = f a k t o r i a l (n)
17 print '%d ! = %d ' % ( n , hasil )

Jalankan.

1 $ python f a k t o r i a l 2 . py
2 Menghitung nilai faktorial
3 n = 5
4 5 ! = 120
5 n = 2
6 2! = 2
7 n = 1
8 1! = 1
9 n = −1
10 − 1! = 1
11 n =

Hasilnya memang sama saja, namun kini sour e faktorial lebih mudah diba a
dan di- opy-paste. Perhatikan juga penggunaan return yang membuat alur
keluar dari fungsi.
Apa ini sudah ukup modular ? Jawabannya belum.

5.2 Membuat Modul

Copy-paste sour e seperti itu tentu saja lebih sulit ketimbang opy-paste le-
nya. Oleh karena itu Anda perlu membuat sour e itu menjadi modul faktorial
yang berarti namanya menjadi faktorial.py sehingga program lain yang mem-
butuhkannya ukup menggunakannya seperti ini ( ontoh):

1 from faktorial import faktorial


2 n = 5
3 print f a k t o r i a l (n)

Sekarang buatlah faktorial.py.

Listing 5.3: faktorial.py

1 def faktorial (a) :


2 if a < 2:
3 return 1
4 for in i range ( 1 , a ) :
5 a = a* i
6 return a

Lalu buatlah obafaktorial.py yang menggunakan modul faktorial ini.

Listing 5.4: obafaktorial.py

1 from faktorial import faktorial


BAB 5. MODULARITAS 34

2
3 print ' Menghitung nilai faktorial '
4 while True :
5 n = raw_input ( ' n = ')
6 if not n:
7 break
8 n = int (n)
9 h a s i l = f a k t o r i a l (n)
10 print '%d ! = %d ' % ( n , hasil )

Jalankan.

1 $ python o b a f a k t o r i a l . py
2 Menghitung Nilai Faktorial
3 n = 5
4 5 ! = 120
5 n = 2
6 2! = 2
7 n =

Hasilnya tetap sama, namun kini Anda lebih mudah opy-paste sour e fungsi
faktorial() karena ukup faktorial.py yang di- opy ke direktori program lainnya.
Untuk men oba modul faktorial Anda perlu membuat le lainnya yaitu
obafaktorial.py. Agar lebih praktis, mengapa tidak disatukan saja ?
Benar, alangkah praktisnya jika sour e untuk menguji fungsi faktorial() juga
berada di le yang sama.
Namun Anda perlu membuat sedikit perubahan agar saat

from faktorial import faktorial

sour e uji oba tersebut tidak dijalankan. Silahkan ubah faktorial.py menjadi
berikut ini.

Listing 5.5: faktorial.py

1 def faktorial (a) :


2 if a < 2:
3 return 1
4 for in i range ( 1 , a ) :
5 a = a * i
6 return a
7
8 if __name__ == '__main__ ' :
9 print ' Menghitung nilai faktorial '
10 while True :
11 n = raw_input ( ' n = ')
12 if not n:
13 break
14 n = int (n)
BAB 5. MODULARITAS 35

15 hasil = fakt orial (n)


16 print '%d ! = %d ' % ( n , hasil )

Perhatikan bahwa __name__ adalah name yang diawali dan diakhiri oleh
dua unders ore. Begitu juga dengan __main__. Kemudian jalankan.

1 $ python f a k t o r i a l . py
2 Menghitung nilai faktorial
3 n = 3
4 3! = 6
5 n = 4
6 4 ! = 24
7 n =

Jadi perubahannya adalah pada

if __name__ == '__main__':
Dengan baris ini Python diberitahu bahwa sour e dibawahnya hanya dijalankan
jika faktorial.py merupakan program utama. Kalau faktorial.py sebagai modul
maka ia tidak dijalankan.
Anda juga masih bisa menggunakan obafaktorial.py seperti biasa.

1 $ python o b a f a k t o r i a l . py

5.3 Sear h Path

Meng- opy faktorial.py ke berbagai direktori program yang membutuhkan tentu


saja merepotkan. Apalagi bila ada perubahan sour e pada faktorial.py, maka
Anda harus menyebarkannya lagi.
Ada banyak direktori dimana Python akan men ari modul yang dipang-
gil. Untuk mengetahui direktori mana saja yang terdaftar gunakan variabel
sys.path. Masuklah ke modus interaktif untuk melihatnya.

1 >>> i m p o r t sys
2 >>> s y s . p a t h
3 [ ' ' ,
4 ' / u s r / l i b / python2 . 6 ' ,
5 ' / u s r / l i b / p y t h o n 2 . 6 / p l a t −l i n u x 2 ' ,
6 ' / u s r / l i b / python2 . 6 / l i b −t k ' ,
7 ' / u s r / l i b / python2 . 6 / l i b −o l d ' ,
8 ' / u s r / l i b / p y t h o n 2 . 6 / l i b −d y n l o a d ' ,
9 ' / u s r / l i b / p y t h o n 2 . 6 / d i s t −p a k a g e s ' ,
10 ' / u s r / l i b / p y t h o n 2 . 6 / d i s t −p a k a g e s / PIL ' ,
11 ' / u s r / l i b / p y t h o n 2 . 6 / d i s t −p a k a g e s / g s t − 0 . 1 0 ' ,
12 ' / u s r / l i b / pymodules / python2 . 6 ' ,
13 ' / u s r / l i b / p y t h o n 2 . 6 / d i s t −p a k a g e s / g t k
−2.0 ' ,
14 ' / u s r / l i b / pymodules / python2 . 6 / gtk −2.0 ' ,
15 ' / u s r / l o a l / l i b / p y t h o n 2 . 6 / d i s t −p a k a g e s ' ℄
BAB 5. MODULARITAS 36

Pertama kali Python akan men ari di direktori dimana program utama be-
rada. Selanjutnya ia akan men ari di direktori lainnya seperti yang Anda lihat
di atas.
Lalu dimana sebaiknya faktorial.py diletakkan ? Karena meletakkannya
tidak melalui instalasi paket Debian, maka saya sarankan diletakkan di direktori

/usr/lo al/lib/python2.6/dist-pa kages

Anda bisa menyalinnya menggunakan perintah

1 $ sudo p f a k t o r i a l . py / u s r / l o a l / l i b / python2 . 6 / d i s t −
pa kages

Supaya lebih yakin pindahkan sekalian.

1 $ s u d o mv f a k t o r i a l . py / u s r / l o a l / l i b / python2 . 6 / d i s t −
pa kages

Jika Anda punya direktori lain, Anda bisa tambahkan pada sys.path terlebih
dahulu sebelum import.

1 >>> i m p o r t sys
2 >>> s y s . p a t h . append ( ' / home / s u g i a n a / l i b ' )
3 >>> f r o m faktorial import faktorial
Bab 6

Fungsi

6.1 Memanggil Dirinya Sendiri

Fungsi faktorial() sudah bekerja dengan baik. Tapi mungkin sour e-nya terlalu
panjang. Cobalah ubah menjadi seperti di bawah ini pada faktorial.py.

1 def faktorial (a) :


2 if a < 2:
3 return 1
4 return a * f a k t o r i a l ( a − 1)

Jauh lebih esien bukan? Teknik seperti ini disebut juga sebagai rekursif.
Pertama kali yang harus diperhatikan dalam pembuatan fungsi rekursif adalah
batas kedalaman. Batas ini ditunjukkan pada baris 2-3. Rekursif yang tidak
memiliki batas kedalaman akan menampilkan pesan kesalahan.

6.2 Format Uang

Untuk menampilkan uang biasanya ada pemisah ribuannya. Untuk Indonesia


pemisah ribuan adalah titik, sedangkan pemisah pe ahan adalah koma. Untuk
kebutuhan tersebut kita bisa gunakan modul lo ale.

1 >>> i m p o r t lo ale
2 >>> l o a l e . s e t l o a l e ( l o a l e . LC_ALL, ' id_ID . UTF− 8 ' )
3 ' id_ID . UTF8 '
4 >>> l o a l e . format ( '%.2 f ' , 10000 , True )
5 '10.000 ,00 '

Jika pe ahannya tidak ingin ditampilkan:

1 >>> l o a l e . format ( '%.0 f ' , 10000 , True )


2 '10.000 '

Namun jika saat setlo ale Anda menjumpai pesan kesalahan seperti ini:

37
BAB 6. FUNGSI 38

1 Tra eba k ( most re ent all last ) :


2 File "< s t d i n >" , line 1, i n <module>
3 File " / u s r / l i b / p y t h o n 2 . 6 / l o a l e . py " , line 513 , in
setlo ale
4 return _ s e t l o a l e ( ategory , lo ale )
5 l o a l e . Error : unsupported lo ale setting

Berarti Anda perlu memasang format id_ID.UTF-8 pada sistem. Keluarlah


dari modus interaktif dan jalankan:

1 $ sudo l o a l e −g e n id_ID . UTF−8


2 Generating lo ales . . .
3 id_ID . UTF− 8 . . . up−t o −d a t e
4 Generation omplete .

Kalau sudah obalah kembali ontoh pemisah ribuan di atas.


Kini saatnya membuat fungsi untuk menampilkan nilai uang ini. Kita na-
makan dengan uang(). Fungsi ini akan menerima dua masukan:

1. Nilai uang yang akan ditampilkan

2. Jumlah digit pe ahan yang akan ditampilkan, default-nya adalah 2 digit


pe ahan.

Karena uang() adalah fungsi umum yang akan banyak digunakan di berbagai
program, ada baiknya kita simpan sebagai modul bernama uang.py.

Listing 6.1: uang.py

1 import lo ale
2 l o a l e . s e t l o a l e ( l o a l e . LC_ALL, ' id_ID . UTF−8 ' )
3
4
5 def uang ( n i l a i , p e a h a n =2) :
6 return l o a l e . f o r m a t ( '%%.%d f ' % p e a h a n , nilai , True )
7
8
9 if __name__ == '__main__ ' :
10 print uang ( 1 0 0 0 0 )
11 print uang ( 1 0 0 0 0 . 3 )
12 print uang ( 1 0 0 0 0 . 5 , 0 )

Cobalah.

1 $ python uang . py
2 10.000 ,00
3 10.000 ,30
4 10.000

Perhatikan bagian

'%%.%df' % pe ahan
BAB 6. FUNGSI 39

Itu adalah formatting seperti yang dijelaskan di halaman 17.


Butuh fungsi yang lebih erdas ? Misalkan dengan sifat seperti ini:

1. Jika pe ahan tidak disebutkan maka modus otomatis berlaku. Otomatis


yang dimaksud adalah bila tipe data variabel nilai adalah bilangan bulat
(integer) maka pe ahan tidak ditampilkan. Selain kondisi itu berarti di-
anggap bilangan pe ahan (oat) maka pe ahan ditampilkan sebanyak 2
digit.

2. Selain kondisi di atas maka nilai uang ditampilkan seperti biasa sesuai
jumlah pe ahan yang disebutkan.

Masih di uang.py.

Listing 6.2: uang.py

1 import lo ale
2 l o a l e . s e t l o a l e ( l o a l e . LC_ALL, ' id_ID . UTF−8 ' )
3
4
5 def uang ( n i l a i , p e a h a n=None ) :
6 if pe ahan is None :
7 if t y p e ( n i l a i ) == t y p e ( 0 ) :
8 pe ahan = 0
9 else :
10 pe ahan = 2
11 return l o a l e . f o r m a t ( '%%.%d f ' % p e a h a n , nilai , True )
12
13
14 if __name__ == '__main__ ' :
15 print uang ( 1 0 0 0 0 )
16 print uang ( 1 0 0 0 0 . 3 )
17 print uang ( 1 0 0 0 0 . 5 , 4 )

Jalankan lagi.

$ python uang.py
10.000
10.000,30
10.000,5000

Cermatilah baik-baik hasilnya. Di sini kita sudah mengenal fungsi yang memiliki
dua masukan dan juga memiliki nilai default pada salah satu masukannya. Juga
ada objek hampa bawaan Python bernama None.
Rasanya fungsi uang kurang lengkap bila tidak disertai dengan mata uangnya.
Kita akan jalankan skenario berikut ini:

1. Fungsi uang diberi satu masukan baru yaitu variabel tanda untuk memberi
kesempatan programmer memasukkan mata uang seperti Rp, $, dst.
BAB 6. FUNGSI 40

2. Bila variabel tanda tidak diisi maka mata uang diambil dari sistem, meng-
gunakan module lo ale.

Listing 6.3: uang.py

1 import lo ale
2 l o a l e . s e t l o a l e ( l o a l e . LC_ALL, ' id_ID . UTF−8 ' )
3 from types import IntType
4
5
6 def ribu ( n i l a i , p e a h a n=None ) :
7 if pe ahan is None :
8 if t y p e ( n i l a i ) == I n t T y p e :
9 pe ahan = 0
10 else :
11 pe ahan = 2
12 return l o a l e . f o r m a t ( '%%.%d f ' % p e a h a n , nilai , True )
13
14 def uang ( n i l a i , p e a h a n=None , t a n d a=None ) :
15 if tanda is None :
16 tanda = l o a l e . l o a l e o n v ( ) [ ' urren y_symbol ' ℄
17 return '%s%s ' % ( t a n d a , ribu ( n i l a i , pe ahan ) )
18
19
20 if __name__ == '__main__ ' :
21 print ribu (10000)
22 print ribu (10000.3)
23 print ribu (10000.5 , 4)
24 print uang ( 1 0 0 0 0 . 7 )
25 print uang ( 1 0 0 0 0 . 7 , 2, '$ ' )
26 print uang ( 1 0 0 0 0 . 7 , t a n d a= ' $ ' )

Perhatikan fungsi tambahan ribu(). Fungsi ini sebenarnya salinan dari fungsi
uang() sebelumnya. Mengapa tidak langsung mengubah fungsi uang() seperti
biasanya ?
Tujuannya adalah kita tidak ingin mengganggu algoritma yang sudah ber-
jalan baik itu. Sehingga bila ada kekeliruan pada algoritma di uang(), area
pen arian kesalahan bisa diminimalisir.
Perhatikan juga baris terakhir,

print uang(10000.7, tanda='$')


dimana kita melewatkan variabel kedua, yaitu pe ahan pada fungsi uang(),

def uang(nilai, pe ahan=None, tanda=None):


Python tidak mempermasalahkan variabel pe ahan dilewatkan, karena variabel
ini telah diberi nilai default yaitu None.
BAB 6. FUNGSI 41

Karena modul uang ini merupakan modul umum yang bisa digunakan oleh
banyak aplikasi, maka letakkanlah uang.py di /usr/lo al/lib/python2.6/dist-
pa kages agar bisa digunakan oleh program lainnya. Lalu uji keberadaannya di
modus interaktif.

1 >>> f r o m uang import uang


2 >>> uang ( 1 0 0 0 0 )
3 '10.000 '
Bab 7

Database
Database atau penyimpan data biasa digunakan untuk aplikasi bisnis seperti
kasir (point of sales), a ounting, payroll, dsb.
Pasanglah

1 $ sudo a p t −g e t install postgresql

Superuser di PostgreSQL adalah postgres. Nama ini ter antum di sistem


Linux maupun di sistem PostgreSQL itu sendiri. Pas a pemasangan user post-
gres tidak memiliki password. Jadi gunakanlah sudo:

1 $ sudo su

Masukkan password user yang Anda gunakan ketika login pertama kali. Kini
Anda telah menjadi root, dan mulailah sebagai user postgres:

1 # su − postgres

Kini Anda sudah menjadi user postgres. Menurut ketentuan default, bila
user Linux dan user PostgreSQL sama maka tidak perlu password untuk login
ke PostgreSQL server. Sekarang mulailah membuat user database:

1 $ reateuser −P ilham
2 Enter password for new role :
3 Enter it again :
4 Shall the new role be a superuser? ( y /n ) n
5 Shall the new role be allowed to reate databases? ( y/n )
n
6 Shall the new role be allowed to reate more new roles? (
y /n ) n

Isilah password dengan 1234. Saat diketik password tidak akan ditampilkan.
Selebihnya user ilham ini tidak dizinkan sebagai superuser, tidak diizinkan mem-
buat database, dan tidak diizinkan membuat user.
Untuk menghapusnya:

1 $ dropuser ilham

42
BAB 7. DATABASE 43

Selanjutnya membuat database:

1 $ reatedb −O ilham totalindo

Ini artinya kita membuat database bernama totalindo yang dimiliki oleh user
ilham. Untuk menghapusnya:

1 $ dropdb totalindo

Untuk melihat daftar database bisa menggunakan psql:

1 $ psql
2 psql (8.4.4)
3 Type " help " for help .
4
5 p o s t g r e s=# \ l
6 List of databases
7 Name | Owner | En oding | Collation |
8 −−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−+
9 postgres | p o s t g r e s | UTF8 | id_ID . UTF−8 |
10 t e m p l a t e 0 | p o s t g r e s | UTF8 | id_ID . UTF−8 |
11 t e m p l a t e 1 | p o s t g r e s | UTF8 | id_ID . UTF−8 |
12 t o t a l i n d o | ilham | UTF8 | id_ID . UTF−8 |
13 (4 rows )
14
15 p o s t g r e s=#

Untuk keluar gunakan \q atau tekan Ctrl-D:

1 p o s t g r e s=# \ q
2 $ whoami
3 postgres

Anda masih sebagai user postgres, keluarlah dengan perintah logout atau
tekan Ctrl-D:

1 $ logout
2 # whoami
3 root

Kini Anda sebagai root, keluarlah lagi dengan perintah logout agar kembali
sebagai user biasa:

1 # logout
2 $ whoami
3 sugiana

Sekarang kita login ke database totalindo sebagai user ilham:

1 $ psql −U ilham totalindo −h lo alhost


2 Password for user ilham :
3 psql (8.4.4)
4 SSL onne tion ( ipher : DHE−RSA−AES256−SHA, bits : 256)
BAB 7. DATABASE 44

5 Type " help " for help .


6
7 t o t a l i n d o=>

Perhatikan di sini kita menggunakan option yang lengkap di psql, padahal


pada saat sebagai user postgres kita ukup mengetikkan psql saja. Apa bedanya
?
psql saja tanpa option apapun berarti:

1. Usernya sesuai user Linux.

2. Nama database sesuai nama user.

3. Koneksi melalui jalur UNIX so ket, tidak melalui network.

7.1 Tabel

Panduan membuat tabel:

1. Harus memiliki PRIMARY KEY, yaitu sebuah / beberapa eld yang men-
jadi identitas re ord.

2. Sebisa mungkin setiap eld memiliki DEFAULT value dimana kalau tidak
diisi maka nilai default digunakan.

3. Sebisa mungkin setiap eld NOT NULL yang berarti harus diisi.

Mulailah membuat tabel pegawai di psql menggunakan perintah CREATE TA-


BLE.

1 t o t a l i n d o=> CREATE TABLE p e g a w a i (


2 t o t a l i n d o (> id serial NOT NULL,
3 t o t a l i n d o (> nama v a r h a r ( 3 0 ) NOT NULL,
4 t o t a l i n d o (> t g l _ l a h i r DATE NOT NULL,
5 t o t a l i n d o (> PRIMARY KEY( i d )
6 t o t a l i n d o (> ) ;
7 NOTICE : CREATE TABLE will reate impli it sequen e "
pegawai_id_seq " for serial olumn " pegawai . i d "
8 NOTICE : CREATE TABLE / PRIMARY KEY w i l l reate impli it
index " p e g a w a i _ p ke y" for table " p e g a w a i " CREATE TABLE
9 t o t a l i n d o=>

Perhatikan prompt

totalindo=>

dan bedakan dengan prompt

totalindo(>
BAB 7. DATABASE 45

yang bermakna prompt itu kelanjutan dari prompt sebelumnya. Penulisan

CREATE TABLE pegawai(

yang diikuti dengan penekanan tombol Enter membuat prompt memberitahukan


Anda bahwa kurung buka masih aktif dan membutuhkan kurung tutup sebelum
diakhiri dengan titik koma.
Perintah dalam SQL (stru tured query language) sebenarnya tidak memper-
hatikan huruf besar / ke il (in asesensitive). Anda boleh menuliskan

CREATE TABLE

menjadi

reate table

Sekarang kita lihat daftar tabel yang ada di database totalindo ini menggunakan
perintah \dt.

1 t o t a l i n d o=> \ d t
2 List of relations
3 S hema | Name | Type | Owner
4 −−−−−−−−+−−−−−−−−−+−−−−−−−+−−−−−−−
5 publi | pegawai | table | ilham
6 (1 row )
7
8 t o t a l i n d o=>

Perintah yang diawali ba kslash ( \ ) adalah perintah program psql,


bukan jenis query seperti CREATE TABLE, SELECT, dst.

Lalu lihat struktur tabelnya menggunakan perintah \d diikuti nama tabel.

1 t o t a l i n d o=> \d pegawai
2 Table " p u b l i . pegawai "
3 Column | Type |
Modifiers
4 −−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−
5 id | integer | not null default
n e x t v a l ( ' pegawai_id_seq ' : : r e g l a s s )
6 nama | hara ter varying (30) | not null
7 tgl_lahir | date | not null
8 Indexes :
9 " p e g a w a i _ p k ey" PRIMARY KEY, btree ( id )
10
11 t o t a l i n d o=>
BAB 7. DATABASE 46

Perhatikan kolom / eld id yang bertipe integer, padahal sebelumnya kita


tulis bertipe serial. Mengapa demikian ?
Tipe serial hanyalah ara epat untuk membuat sebuah eld menjadi au-
toin rement (nomor urut). Jadi pendenisian suatu eld menjadi serial akan
membuat:

1. Tipenya menjadi integer (bilangan bulat).

2. Memiliki default value nomor urut berikutnya. Nomor urut berikutnya


tersimpan dalam sebuah sequen e.

Apa itu sequen e ?

7.1.1 Sequen e
Sequen e mirip tabel, tepatnya tabel satu re ord yang berisi data untuk ke-
butuhan nomor urut. Pada ontoh di atas sequen e bernama pegawai_id_seq
otomatis terbentuk saat eld id pada tabel pegawai didenisikan sebagai seri-
al. Data pada sequen e bisa dilihat sebagaimana tabel menggunakan perintah
SELECT.

1 t o t a l i n d o=> SELECT * FROM p e g a w a i _ i d _ s e q ;


2 sequen e_name | last_value | is_ alled |
3 −−−−−−−−−−−−−−−−+−−−−−−−−−−−−+−−−−−−−−−−−+
4 pegawai_id_seq | 1 | f |
5
6 (1 row )

Sekarang kita lihat isi tabel pegawai.

1 t o t a l i n d o=> SELECT * FROM p e g a w a i ;


2 id | nama | tgl_lahir
3 −−−−+−−−−−−+−−−−−−−−−−−
4 (0 rows )

Tampak tabel pegawai masih kosong, mari tambah datanya.

1 t o t a l i n d o=> INSERT INTO p e g a w a i ( nama , t g l _ l a h i r )


2 t o t a l i n d o −> VALUES ( ' Bummi Dwi Putera ' , '1985 −8 −17 ') ;
3 INSERT 0 1

Perhatikan perintah di baris pertama tidak diakhiri dengan titik koma yang
berarti perintah belum berakhir dan dilanjutkan di baris berikutnya. Perhatikan
juga prompt pada baris kedua menjadi

totalindo->
yakni menggunakan karakter minus ( - ) yang berarti baris ini merupakan ke-
lanjutan dari baris sebelumnya. Jika Anda salah dalam menuliskan perintah di
baris pertama dan terlanjur menekan Enter, akhiri saja dengan titik koma di
baris kedua. Kemudian mulai lagi dari awal. Berikut ini ontoh kesalahan yang
bisa saja terjadi.
BAB 7. DATABASE 47

1 t o t a l i n d o=> INSERT INT p e g a w a i ( nama , t g l _ l a h i r )


2 t o t a l i n d o −> ;
3 ERROR: syntax error at or near "INT"
4 LINE 1: INSERT INT p e g a w a i ( nama , t g l _ l a h i r )
5 ^
6 t o t a l i n d o=>

Untuk mengulangi perintah sebelumnya tekan tombol panah atas.


Kembali ke tabel pegawai yang sudah kita isi dengan perintah INSERT.
Sekarang lihat hasilnya.

1 t o t a l i n d o=> SELECT * FROM p e g a w a i ;


2 id | nama | tgl_lahir
3 −−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−
4 1 | Bummi Dwi P u t e r a | 1985 − 08 − 17
5 (1 row )

Perhatikan saat INSERT tadi eld id tidak disertakan, namun perintah SE-
LECT memperlihatkan bahwa eld id terisi dengan angka 1. Inilah yang dise-
but dengan eld autoin rement. Lalu apa yang terjadi dengan sequen e pe-
gawai_id_seq ?

1 t o t a l i n d o=> SELECT * FROM p e g a w a i _ i d _ s e q ;


2 sequen e_name | last_value | is_ alled
3 −−−−−−−−−−−−−−−−+−−−−−−−−−−−−+−−−−−−−−−−−
4 pegawai_id_seq | 1 | t
5
6 (1 row )

Bandingkan dengan nilai-nilai pegawai_id_seq pada SELECT sebelum IN-


SERT. Yang perlu diperhatikan adalah eld is_ alled dimana sebelumnya f
(False) kini menjadi t (True). Ini artinya sequen e sudah digunakan agar
nextval() berikutnya tahu bahwa nilai berikutnya menghasilkan last_value + 1
= 2.
Sekarang lanjut dengan pegawai berikutnya.

1 t o t a l i n d o=> INSERT INTO p e g a w a i ( nama , t g l _ l a h i r )


2 t o t a l i n d o −> VALUES ( ' A r i e f S e t i a d i ' , '1972 −5 −2 ') ;
3 INSERT 0 1
4 t o t a l i n d o=> SELECT * FROM p e g a w a i ;
5 id | nama | tgl_lahir
6 −−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−
7 1 | Bummi Dwi P u t e r a | 1985 − 08 − 17
8 2 | Arief Setiadi | 1972 − 05 − 02
9 (2 rows )

Perhatikan kembali eld id yang terisi dengan angka 2, dan lihat juga pe-
gawai_id_seq.

1 t o t a l i n d o=> SELECT * FROM p e g a w a i _ i d _ s e q ;


BAB 7. DATABASE 48

2 sequen e_name | last_value | is_ alled |


3 −−−−−−−−−−−−−−−−+−−−−−−−−−−−−+−−−−−−−−−−−+
4 pegawai_id_seq | 2 | t | 1
5
6 (1 row )

Kini last_value menjadi 2, sehingga nextval() berikutnya last_value + 1 =


3. Mudah-mudahan bisa dipahami.
Mengenai eld tgl_lahir, bolehkah diisi menggunakan format Indonesia yaitu
dengan urutan tanggal-bulan-tahun ?
Jawabannya boleh, hanya ada yang perlu diperhatikan pada kongurasi
PostgreSQL, yaitu pada le

/et /postgresql/8.4/main/postgresql. onf

Coba lihat dengan text editor.

1 $ sudo nano / e t / p o s t g r e s q l / 8 . 4 / main / p o s t g r e s q l . o n f

Carilah kata datestyle.

datestyle = 'iso, dmy'

Jika sudah tampak dmy seperti di atas maka Anda diizinkan mengisi eld tang-
gal dengan format tanggal-bulan-tahun. Namun jika Anda mendapati isinya

datestyle = 'iso, mdy'

maka ubahlah mdy menjadi dmy, simpan, logout semua psql, dan restart Post-
greSQL.

1 $ sudo / e t / i n i t . d/ p o s t g r e s q l −8.4 restart

Perlu Anda ketahui, format dmy otomatis Anda dapatkan bila saat instalasi
Ubuntu menggunakan bahasa Indonesia.
Cobalah untuk menambah data pegawai lagi dengan tanggal lahir berformat
tanggal-bulan-tahun.

1 t o t a l i n d o=> INSERT INTO p e g a w a i ( nama , t g l _ l a h i r )


2 t o t a l i n d o −> VALUES ( ' Ce ep Zahrudin ' , '1 −6 −1972 ') ;
3 INSERT 0 1
4 t o t a l i n d o=> SELECT * FROM p e g a w a i ;
5 id | nama | tgl_lahir
6 −−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−
7 1 | Bummi Dwi P u t e r a | 1985 − 08 − 17
8 2 | Arief Setiadi | 1972 − 05 − 02
9 3 | Ce ep Z a h r u d i n | 1972 − 06 − 01
10 (3 rows )

Agar tampil urut sesuai abjad gunakan ORDER BY.


BAB 7. DATABASE 49

1 t o t a l i n d o=> SELECT * FROM p e g a w a i ORDER BY nama ;


2 id | nama | tgl_lahir
3 −−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−
4 2 | Arief Setiadi | 1972 − 05 − 02
5 1 | Bummi Dwi P u t e r a | 1985 − 08 − 17
6 3 | Ce ep Z a h r u d i n | 1972 − 06 − 01
7 (3 rows )

Gunakan WHERE untuk mendapatkan re ord tertentu.

1 t o t a l i n d o=> SELECT * FROM p e g a w a i WHERE i d = 1 ;


2 id | nama | tgl_lahir
3 −−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−
4 1 | Bummi Dwi P u t e r a | 1985 − 08 − 17
5 (1 row )

Tampilkan pegawai yang lahir di tahun 1972 dan diurutkan mulai yang ter-
tua.

1 t o t a l i n d o=> SELECT * FROM p e g a w a i


2 t o t a l i n d o −> WHERE d a t e _ p a r t ( ' y e a r ' , t g l _ l a h i r ) = 1972
3 t o t a l i n d o −> ORDER BY t g l _ l a h i r ;
4 id | nama | tgl_lahir
5 −−−−+−−−−−−−−−−−−−−−−+−−−−−−−−−−−−
6 2 | Arief Setiadi | 1972 − 05 − 02
7 3 | Ce ep Z a h r u d i n | 1972 − 06 − 01
8 (2 rows )

Gunakan DESC pada ORDER BY jika ingin diurut mulai yang termuda.
Tekan tombol panah atas untuk mengulang perintah sebelumnya dan tam-
bahkan DESC.

1 t o t a l i n d o=> SELECT * FROM p e g a w a i


2 WHERE d a t e _ p a r t ( ' y e a r ' , t g l _ l a h i r ) = 1972
3 ORDER BY t g l _ l a h i r DESC ;
4 id | nama | tgl_lahir
5 −−−−+−−−−−−−−−−−−−−−−+−−−−−−−−−−−−
6 3 | Ce ep Z a h r u d i n | 1972 − 06 − 01
7 2 | Arief Setiadi | 1972 − 05 − 02
8 (2 rows )

7.1.2 Mengubah Struktur


Pegawai sebelumnya tampak sebagai laki-laki, terlihat dari namanya. Cobalah
untuk memasukkan nama perempuan.

1 t o t a l i n d o=> INSERT INTO p e g a w a i ( nama , t g l _ l a h i r )


2 t o t a l i n d o −> VALUES ( ' N i t a Pandria ' , '19 −9 −1976 ') ;
3 INSERT 0 1
BAB 7. DATABASE 50

Manusia bisa jadi memahami mana nama laki-laki dan mana perempuan.
Namun komputer mengalami kesulitan bila mengandalkan nama. Oleh karena
itu kita perlu menambah eld pria yang bertipe logika (boolean). Kita membu-
tuhkan perintah ALTER TABLE di sini.

1 t o t a l i n d o=> ALTER TABLE p e g a w a i ADD p r i a b o o l e a n NOT NULL


DEFAULT t r u e ;
2 ALTER TABLE

Seperti dijelaskan pada sesi Python sebelumnya, boolean hanya bisa diisi
dengan dua nilai, bisa True atau False. Kita menamakan eld ini dengan pria
dengan begitu nilai default-nya adalah True. Jika eld pria False berarti pegawai
tersebut perempuan. Sekarang kita lihat isi tabel pegawai setelah penambahan
eld di atas.

1 t o t a l i n d o=> SELECT * FROM p e g a w a i ORDER BY nama ;


2 id | nama | tgl_lahir | pria
3 −−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−+−−−−−−
4 2 | Arief Setiadi | 1972 − 05 − 02 | t
5 1 | Bummi Dwi P u t e r a | 1985 − 08 − 17 | t
6 3 | Ce ep Z a h r u d i n | 1972 − 06 − 01 | t
7 4 | Nita Pandria | 1976 − 09 − 19 | t
8 (4 rows )

Perhatikan eld pria, tampak semua tertulis t yang artinya True. Apa data
tabel ini sudah benar? Jelas belum.
Nita Pandria adalah perempuan, sedangkan tabel pegawai menyatakannya
laki-laki. Kita perlu mengubahnya dengan perintah UPDATE.

1 t o t a l i n d o=> UPDATE p e g a w a i SET p r i a = F a l s e WHERE i d = 4 ;


2 UPDATE 1
3 t o t a l i n d o=> SELECT * FROM p e g a w a i ORDER BY nama ;
4 id | nama | tgl_lahir | pria
5 −−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−+−−−−−−
6 2 | Arief Setiadi | 1972 − 05 − 02 | t
7 1 | Bummi Dwi P u t e r a | 1985 − 08 − 17 | t
8 3 | Ce ep Z a h r u d i n | 1972 − 06 − 01 | t
9 4 | Nita Pandria | 1976 − 09 − 19 | f
10 (4 rows )

Kita sudah membuat re ord dengan INSERT, menampilkannya dengan SE-


LECT, dan mengubahnya dengan UPDATE. Kini kita oba untuk menghapus-
nya dengan DELETE FROM yaitu pegawai dengan id 2.

1 t o t a l i n d o=> DELETE FROM p e g a w a i WHERE i d = 2 ;


2 DELETE 1
3 t o t a l i n d o=> SELECT * FROM p e g a w a i ORDER BY nama ;
4 id | nama | tgl_lahir | pria
5 −−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−+−−−−−−
BAB 7. DATABASE 51

6 1 | Bummi Dwi Putera | 1985 − 08 − 17 | t


7 3 | Ce ep Zahrudin | 1972 − 06 − 01 | t
8 4 | Nita Pandria | 1976 − 09 − 19 | f
9 (3 rows )

Jika Anda kurang suka dengan eld pria yang bertipe boolean bisa dihapus
dengan perintah ALTER TABLE.

1 t o t a l i n d o=> ALTER TABLE p e g a w a i DROP p r i a ;


2 ALTER TABLE

Anda masih kurang berkenan dengan struktur tabel pegawai ? Silahkan


hapus dengan perintah DROP TABLE.

1 t o t a l i n d o=> DROP TABLE p e g a w a i ;


2 DROP TABLE

SELECT, INSERT, UPDATE, dan DELETE adalah hal yang terkait den-
gan re ord / baris data sehingga disebut sebagai Data Manipulation Language
(DML). Sedangkan CREATE, ALTER, dan DROP terkait dengan struktur tabel
sehingga disebut sebagai Data Denition Language (DDL).

7.2 View

Dibutuhkan sebuah laporan yang menampilkan data pegawai beserta usianya.


Untuk mendapatkan usia kita bisa gunakan rumus:

usia = tgl sekarang - tgl lahir

Lalu kita tampilkan dengan urutan diawali yang paling tua.

1 t o t a l i n d o=> SELECT i d , nama , now ( ) − t g l _ l a h i r FROM


p e g a w a i ORDER BY t g l _ l a h i r ;
2 id | nama | ? olumn ?
3 −−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−
4 2 | Arief Setiadi | 13957 days 11:21:54.083022
5 3 | Ce ep Zahrudin | 13927 days 11:21:54.083022
6 4 | Nita Pandria | 12356 days 11:21:54.083022
7 1 | Bummi Dwi Putera | 9102 days 11:21:54.083022
8 (4 rows )

Kolom ketiga berisi usia, tapi PostgreSQL tidak tahu harus dinamakan apa,
sehingga jadilah bernama ? olumn?. Ada baiknya kita berikan nama usia.

1 t o t a l i n d o=> SELECT i d , nama , now ( ) − tgl_lahir AS usia


2 t o t a l i n d o −> FROM p e g a w a i ORDER BY t g l _ l a h i r ;
3 id | nama | usia
4 −−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−
5 2 | Arief Setiadi | 13957 days 11:28:34.001142
6 3 | Ce ep Zahrudin | 13927 days 11:28:34.001142
BAB 7. DATABASE 52

7 4 | Nita Pandria | 12356 days 11:28:34.001142


8 1 | Bummi Dwi Putera | 9102 days 11:28:34.001142
9 (4 rows )

Satuan usia menggunakan hari tentu saja kurang nyaman diba a. Sebaiknya
kita ganti rumusnya:

usia = tahun sekarang - tahun kelahiran

sehingga query-nya menjadi:

1 t o t a l i n d o=> SELECT i d , nama ,


2 t o t a l i n d o −> e x t r a t ( y e a r from now ( ) ) − e x t r a t ( year from
tgl_lahir ) AS usia
3 t o t a l i n d o −> FROM p e g a w a i ORDER BY t g l _ l a h i r ;
4 id | nama | usia
5 −−−−+−−−−−−−−−−−−−−−−−−+−−−−−−
6 2 | Arief Setiadi | 38
7 3 | Ce ep Zahrudin | 38
8 4 | Nita Pandria | 34
9 1 | Bummi Dwi Putera | 25
10 (4 rows )

Perintah SQL (query) di atas dapat disimpan dalam sebuah VIEW.

1 t o t a l i n d o=> CREATE VIEW v_pegawai AS SELECT i d , nama ,


2 e x t r a t ( year from now ( ) ) − e x t r a t ( year from tgl_lahir )
AS usia
3 FROM p e g a w a i ORDER BY t g l _ l a h i r ;
4 CREATE VIEW

Selanjutnya kita tampilkan VIEW tadi layaknya sebuah tabel.

1 t o t a l i n d o=> SELECT * FROM v_pegawai ;


2 id | nama | usia
3 −−−−+−−−−−−−−−−−−−−−−−−+−−−−−−
4 2 | Arief Setiadi | 38
5 3 | Ce ep Zahrudin | 38
6 4 | Nita Pandria | 34
7 1 | Bummi Dwi Putera | 25
8 (4 rows )

Penamaan VIEW tidak harus berawalan v_. Penggunaan awalan itu un-
tuk membedakan VIEW dengan tabel sebenarnya. Meski ia dapat di-SELECT
namun VIEW tidak dapat di-INSERT begitu saja.
Walau v_pegawai sudah mengandung ORDER BY, kita masih bisa meng-
gunakan ORDER BY saat SELECT, misalnya diurut berdasar nama.

1 t o t a l i n d o=> SELECT * FROM v_pegawai ORDER BY nama ;


2 id | nama | usia
BAB 7. DATABASE 53

3 −−−−+−−−−−−−−−−−−−−−−−−+−−−−−−
4 2 | Arief Setiadi | 38
5 1 | Bummi Dwi Putera | 25
6 3 | Ce ep Zahrudin | 38
7 4 | Nita Pandria | 34
8 (4 rows )

7.3 Ba kup dan Restore

Jika tabel pegawai benar-benar Anda hapus, sebaiknya mulailah membuatnya


lagi dan mengisinya. Selain langsung melalui psql modus interaktif, Anda bisa
membuatnya dulu dalam sebuah le pegawai.sql.

Listing 7.1: pegawai.sql

1 CREATE TABLE pegawai (


2 id serial ,
3 var har NOT NULL
nama (30) ,
4 date NOT NULL
tgl_lahir ,
5 pria NOT NULL DEFAULT true
boolean ,
6 PRIMARY KEY ( id )
7 ) ;
8
9 INSERT INTO p e g a w a i ( nama , t g l _ l a h i r , p r i a ) VALUES ( ' Bummi
Dwi P u t e r a ' , ' 1985 − 8 − 17 ' , true );
10 INSERT INTO p e g a w a i ( nama , t g l _ l a h i r , p r i a ) VALUES ( ' Arief
S e t i a d i ' , ' 1972 − 5 − 2 ' , true );
11 INSERT INTO p e g a w a i ( nama , t g l _ l a h i r , p r i a ) VALUES ( ' Ce ep
Z a h r u d i n ' , ' 1972 − 6 − 1 ' , true );
12 INSERT INTO p e g a w a i ( nama , t g l _ l a h i r , p r i a ) VALUES ( ' Nita
P a n d r i a ' , ' 1976 − 9 − 19 ' , false ) ;

Lalu di psql jalankan le tersebut:

1 t o t a l i n d o=> \ i pegawai . s q l
2 p s q l : s q l / pegawai . s q l : 7 : NOTICE : CREATE TABLE will reate
impli it sequen e " pegawai_id_seq " for serial olumn
" pegawai . i d "
3 p s q l : s q l / pegawai . s q l : 7 : NOTICE : CREATE TABLE / PRIMARY
KEY w i l l reate impli it index " p e g a w a i _ p ke y" for
table " pegawai "
4 CREATE TABLE
5 INSERT 0 1
6 INSERT 0 1
7 INSERT 0 1
8 INSERT 0 1

Kalau Anda menemui kegagalan


BAB 7. DATABASE 54

No su h file or dire tory


obalah menuliskan nama le se ara fullpath, misalnya.

1 t o t a l i n d o=> \ i /home/ s u g i a n a / p e g a w a i . s q l

Sesuaikan dengan direktori dimana Anda menyimpan pegawai.sql. Mudah-


mudahan Anda mengerti maksudnya.
Kini ba kup database totalindo dalam sebuah le berformat tar.

1 $ pg_dump −U ilham totalindo −h lo alhost −F t −f


totalindo . sql . tar

Mulailah untuk latihan restore, yaitu dengan membuat database lain berna-
ma totalindo_1 (lihat pembuatan database di awal bab ini). Lalu jalankan:

1 $ pg_restore −U ilham −h lo alhost −d totalindo_1


totalindo . sql . tar

Anda juga bisa ba kup menggunakan format teks biasa (plaintext):

1 $ pg_dump −U ilham totalindo −h lo alhost −f totalindo .


sql

dan restore dengan psql:

1 $ psql −U ilham totalindo_1 −h lo alhost −f totalindo . sql

Manfaat penggunaan plaintext adalah Anda bisa mengubah le totalin-


do.sql menggunakan teks editor biasa. Namun penggunaan format ini terkadang
menimbulkan masalah saat restore bila ada karakter aneh, yaitu karakter den-
gan nomor ASCII lebih besar dari 126.

7.3.1 En oding
PostgreSQL versi terdahulu biasanya menggunakan SQL_ASCII sebagai en od-
ing hara ter. Anda bisa lihat dengan perintah \l di psql.

1 $ psql −U ilham template1 −h lo alhost


2 psql (8.4.4)
3 Type " help " for help .
4
5 p o s t g r e s=# \ l
6 List of databases
7 Name | Owner | En oding | Collation |
8 −−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−+
9 postgres | p o s t g r e s | UTF8 | id_ID . UTF−8 |
10 template0 | p o s t g r e s | UTF8 | id_ID . UTF−8 |
11 template1 | p o s t g r e s | UTF8 | id_ID . UTF−8 |
12 totalindo | ilham | UTF8 | id_ID . UTF−8 |
13 totalindo_1 | ilham | UTF8 | id_ID . UTF−8 |
14 (5 rows )
BAB 7. DATABASE 55

Perhatikan di versi ini default en oding adalah UTF8. Jika Anda memba k-
up, perhatikanlah en oding ini. Misalkan menggunakan SQL_ASCII, maka di
database yang baru pun Anda sebaiknya tetap menggunakan en oding yang
sama. Sebagai latihan kembalilah ke konsole, lalu buat database totalindo_2
dengan en oding SQL_ASCII.

1 $ sudo su
2 # su − postgres
3 $ reatedb −O ilham −T template0 −E sql_as ii totalindo_2

Kembali ke psql dan lihat daftar database. Karena masih sebagai user post-
gres maka ukup ketik psql.

1 $ psql
2 psql (8.4.4)
3 Type " help " for help .
4
5 p o s t g r e s=# \ l
6 List of databases
7 Name | Owner | En oding | Collation |
8 −−−−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−+−−−−−−−−−−−−−+
9 postgres | p o s t g r e s | UTF8 | id_ID . UTF−8 |
10 template0 | p o s t g r e s | UTF8 | id_ID . UTF−8 |
11 template1 | p o s t g r e s | UTF8 | id_ID . UTF−8 |
12 totalindo | ilham | UTF8 | id_ID . UTF−8 |
13 totalindo_1 | ilham | UTF8 | id_ID . UTF−8 |
14 totalindo_2 | ilham | SQL_ASCII | id_ID . UTF−8 |
15 (6 rows )

Mengenai ara ba kup dan restore lainnya sama seperti sebelumnya.


Mengapa kita perlu memperhatikan en oding ?
Bila database yang Anda ba kup tidak mengandung karakter aneh (ASCII
> 126) maka bisa dengan nyaman di-restore dari ke UTF8. Namun bila men-
gandung ASCII > 126 maka restore ke UTF8 dari sumber SQL_ASCII bisa
menimbulkan masalah.

7.4 Fungsi

Sama seperti Python, PostgreSQL juga mengenal fungsi. Contoh fungsi bawaan
(built-in) adalah now().

1 t o t a l i n d o=> SELECT now ( ) ;


2 now
3 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
4 2010 − 08 − 24 1 6 : 0 6 : 5 8 . 6 7 8 0 5 6 + 0 7
5 (1 row )

Keunikan fungsi pada PostgreSQL adalah pada nama dan susunan masukan-
nya (input parameter). Perhatikan ontoh rata kanan berikut ini.
BAB 7. DATABASE 56

1 t o t a l i n d o=> SELECT l p a d ( ' A' , 5 ) ;


2 lpad
3 −−−−−−−
4 A
5 (1 row )

Fungsi lpad() berguna untuk memberi spasi di sebelah kiri. Jumlah spasi
ditambah jumlah karakter string 'A' tidak boleh melebihi 5. Jadi pada ontoh
di atas jumlah spasi di sebelah kiri 'A' sebanyak 4 buah. Untuk membuktikan
jumlah karakternya adalah 5 maka kita gunakan fungsi length().

1 t o t a l i n d o=> SELECT l e n g t h ( l p a d ( ' A' , 5 ) ) ;


2 length
3 −−−−−−−−
4 5
5 (1 row )

Sekarang kita membutuhkan awalan '0' pada sebuah nomor, misalnya '00001'.
Ini lazim kita temui pada beberapa laporan. Fungsi apa yang akan digunakan.
Jawabannya masih menggunakan fungsi lpad().

1 t o t a l i n d o=> SELECT l p a d ( ' 1 ' , 5 , ' 0 ' ) ;


2 lpad
3 −−−−−−−
4 00001
5 (1 row )

Di sinilah letak keunikan sebuah fungsi pada PostgreSQL. Fungsi lpad()


bisa menerima masukan dua buah atau tiga buah. Jika dua buah saja yang
digunakan maka lpad() akan mengawalinya dengan spasi. Namun jika tiga buah
masukan, maka lpad() akan mengawalinya sesuai dengan karakter pada masukan
ketiga. Cermatilah baik-baik.
Jadi bila kita ingin membuat beberapa fungsi dengan nama sama maka harus
dibedakan dengan:

1. Jumlah masukannya.

2. Jika jumlah masukannya sama maka bedakan tipe data setiap masukan
tersebut.

7.4.1 PL/pgSQL
Salah satu yang membuat PostgreSQL begitu mudah dikembangkan adalah
fungsi tersebut bisa ditulis dalam berbagai bahasa. Dimana Anda bisa menulis
fungsi dalam bahasa pgSQL, Python, Perl, hingga T l. Se ara default bahasa
yang didukungnya adalah plpgsql. Namun Anda perlu memasangnya terlebih
dahulu pada database yang dimaksud.

1 $ sudo su postgres − " reatelang plpgsql totalindo "


BAB 7. DATABASE 57

Selanjutnya siapkanlah dua konsole, yang pertama untuk

1 $ psql −U ilham totalindo −h lo alhost

sedangkan yang kedua untuk text editor vi. Tentu saja Anda bisa menggu-
nakan gedit. Text editor akan kita gunakan untuk membuat le-le *.sql.
Sekarang kita akan membuat fungsi sederhana hello(), tanpa masukan apapun,
disimpan dalam le hello.sql.

Listing 7.2: hello.sql

1 CREATE OR REPLACE FUNCTION h e l l o ( )


2 RETURNS text
3 LANGUAGE p l p g s q l
4 AS $$
5 BEGIN
6 RETURN ' Hello world . ' ;
7 END
8 $$ ;

Setelah disimpan jalankan di psql tadi:

1 t o t a l i n d o=> \ i hello . sql


2 CREATE FUNCTION

lalu obalah

1 t o t a l i n d o=> SELECT hello () ;


2 hello
3 −−−−−−−−−−−−−−
4 Hello world .
5 (1 row )

Transaksi Perbankan
Kita sudah punya tabel pegawai dimana setiap pegawai dianggap sebagai nasabah
pada perusahaan ini. Saat mendapat gaji saldonya bertambah. Saat ambil gaji
saldonya berkurang. Saat kas bon (pinjam) saldonya juga berkurang. Jadi saldo
juga bisa negatif yang berarti pegawai tersebut punya hutang ke perusahaan.
Pertama kita butuh eld saldo pada tabel pegawai.

1 ALTER TABLE pegawai ADD saldo float NOT NULL DEFAULT 0;

Kemudian untuk men atat aktivitas transaksi kita memerlukan tabel transak-
si berikut ini.

Listing 7.3: transaksi.sql

1 CREATE TABLE transaksi (


2 id PRIMARY KEY
serial ,
3 integer NOT NULL
pid REFERENCES p e g a w a i ,
4 timestamp NOT NULL DEFAULT
tgl now ( ) ,
BAB 7. DATABASE 58

5 ket var har NOT NULL


(100) ,
6 nominal float NOT NULL ,
7 saldo float NOT NULL
8 ) ;

Misalkan ID pegawai 1 bernama Bummi Dwi Putera mendapat gaji untuk


bulan Nopember 2010 sebesar Rp 3.000.000,- maka query-nya adalah:

1 UPDATE p e g a w a i SET s a l d o = s a l d o + 3 0 0 0 0 0 0 WHERE i d = 1 ;


2
3 INSERT INTO t r a n s a k s i ( pid , ket , nominal , s a l d o )
4 SELECT i d , ' GAJI 11 −2010 ' ,3000000 , s a l d o
5 FROM p e g a w a i
6 WHERE i d = 1 ;

Ya, kita butuh dua query untuk sebuah transaksi. Mungkin ada pertanyaan,
untuk apa eld saldo pada tabel transaksi ? Field ini digunakan untuk memu-
dahkan pen etakan buku tabungan yang biasanya men antumkan saldo pada
setiap transaksi.
Kalau diperhatikan, transaksi tersebut membutuhkan 3 parameter masukan:

1. ID pegawai

2. Keterangan transaksi

3. Nominal transaksi

Kalau transaksi ini dikemas dalam sebuah fungsi, lalu apa keluarannya ? Kelu-
aran atau output yang paling tepat adalah ID transaksi. Query-nya bisa kita
peroleh dengan ara berikut ini.

1 SELECT i d FROM t r a n s a k s i ORDER BY i d DESC LIMIT 1;

Artinya dapatkan re ord terakhir dari tabel transaksi.

1 id | pid | tgl |
2 −−−−+−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−+
3 1 | 1 | 2010 − 10 − 22 1 7 : 5 8 : 0 1 . 8 6 |
4
5 ket | nominal | saldo
6 −−−−−−−−−−−−−−+−−−−−−−−−+−−−−−−−−−
7 GAJI 11 − 2010 | 3 0 0 0 0 0 0 | 3 0 0 0 0 0 0

Selanjutnya kita buat fun transaksi.sql untuk fungsi dimaksud.

Listing 7.4: fun transaksi.sql

1 CREATE OR REPLACE FUNCTION t r a n s a k s i (


2 integer
p_pid ,
3 p_ket text ,
4 float
p_nominal )
5 RETURNS integer
BAB 7. DATABASE 59

6 LANGUAGE p l p g s q l
7 AS $$
8 DECLARE
9 re re ord ;
10 BEGIN
11 UPDATE pegawai
12 SET s a l d o = s a l d o + p_nominal
13 WHERE i d = p_pid ;
14
15 INSERT INTO transaksi (
16 id , pid , nominal , ket , saldo )
17 SELECT tid , p_pid , p_nominal , p_ket , saldo
18 FROM pegawai
19 WHERE i d = p_pid ;
20
21 SELECT id
22 INTO re
23 FROM transaksi
24 ORDER BY DESC id
25 LIMIT 1;
26
27 RETURN r e . i d ;
28 END
29 $$

Restore s ript ini.

1 t o t a l i n d o=> \ i fun transaksi . sql


2 CREATE FUNCTION

Misalkan ID pegawai 1 meminjam ( ash bon) sebesar Rp200.000,- maka:

1 t o t a l i n d o=> SELECT t r a n s a k s i ( 1 , 'BON' , −200000) ;


2 transaksi
3 −−−−−−−−−−−
4 2
5 (1 row )

Perhatikan nominal berisi nilai negatif yang artinya mengurangi saldo. Sekarang
lihat keseluruhan transaksi.

1 t o t a l i n d o=> SELECT * FROM t r a n s a k s i ;


2 id | pid | tgl | ket |
nominal | saldo
3 −−−−+−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−+−−−−−−−−−+−−−−−−−−−

4 1 | 1 | 2010 − 10 − 22 17:58:01.869139 | GAJI 11 − 2010 |


3000000 | 3000000
BAB 7. DATABASE 60

5 2 | 1 | 2010 − 10 − 22 18:20:08.845091 | BON |


− 200000 | 2800000
6 (2 rows )

Dilihat dari aspek ke epatan, query SELECT terhadap tabel transaksi bisa
dihindari. Maklumlah tabel transaksi ini tergolong epat pertumbuhan re ord-
nya. Jadi untuk mendapatkan ID transaksi kita perlu menggunakan sequen e
yang dimiliki tabel transaksi tersebut. Ubahlah fun transaksi.sql menjadi berikut
ini.

Listing 7.5: fun transaksi.sql

1 CREATE OR REPLACE FUNCTION t r a n s a k s i (


2 integer
p_pid ,
3 p_ket text ,
4 float
p_nominal )
5 RETURNS integer
6 LANGUAGE p l p g s q l
7 AS $$
8 DECLARE
9 integer
tid ;
10 BEGIN
11 UPDATE pegawai
12 SET s a l d o = s a l d o + p_nominal
13 WHERE i d = p_pid ;
14
15 t i d = nextval ( ' transaksi_id_seq ' ) ;
16
17 INSERT INTO transaksi (
18 id , pid , nominal , ket , saldo )
19 SELECT tid , p_pid , p_nominal , p_ket , saldo
20 FROM pegawai
21 WHERE i d = p_pid ;
22
23 RETURN t i d ;
24 END
25 $$

Restore.

1 t o t a l i n d o=> \ i transaksi . sql


2 CREATE FUNCTION

Kini kita oba ID pegawai 5 bernama Ilham untuk transaksi.

1 t o t a l i n d o=> SELECT t r a n s a k s i ( 5 , ' GAJI 11 −2010 ' ,1500000) ;


2 transaksi
3 −−−−−−−−−−−
4 3
5 (1 row )
BAB 7. DATABASE 61

Lalu lihat hasilnya.

1 t o t a l i n d o=> SELECT * FROM t r a n s a k s i ;


2 id | pid | tgl | ket |
nominal | saldo
3 −−−−+−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−+−−−−−−−−−+−−−−−−−−−

4 1 | 1 | 2010 − 10 − 22 17:58:01.869139 | GAJI 11 − 2010 |


3000000 | 3000000
5 2 | 1 | 2010 − 10 − 22 18:20:08.845091 | BON |
− 200000 | 2800000
6 3 | 5 | 2010 − 10 − 22 18:41:45.309451 | GAJI 11 − 2010 |
1500000 | 1500000
7 (3 rows )

7.4.2 PL/Python
Penulisan fungsi PostgreSQL bisa juga dalam bahasa Python. Biasanya saya
gunakan bahasa ini untuk algoritma yang tidak membutuhkan akses database.
Pasanglah terlebih dahulu.

1 $ sudo a p t −g e t install p o s t g r e s q l −p l p y t h o n −8.4


2 $ sudo su postgres − " reatelang plpythonu totalindo "

Masih ingat modul uang yang ditaruh di /usr/lo al/lib/python2.6/dist-pa kages


? Kali ini akan kita gunakan pada fungsi di PostgreSQL. Buatlah uang.sql
berikut ini.

Listing 7.6: uang.sql

1 CREATE OR REPLACE FUNCTION uang ( n float )


2 RETURNS text
3 LANGUAGE p l p y t h o n u
4 AS $$
5 from uang import uang
6 return uang ( n )
7 $$ ;
8
9 CREATE OR REPLACE FUNCTION uang ( n integer )
10 RETURNS text
11 LANGUAGE p l p y t h o n u
12 AS $$
13 from uang import uang
14 return uang ( n )
15 $$ ;

Tidak seperti plpgsql, fungsi yang ditulis menggunakan plpythonu harus


dibuat oleh user postgres.
BAB 7. DATABASE 62

1 $ sudo su postgres − "psql totalindo −f uang . s q l "


2 [ sudo ℄ password for sugiana :
3 CREATE FUNCTION
4 CREATE FUNCTION

Lalu obalah.

1 t o t a l i n d o=> SELECT uang ( 1 0 0 0 0 ) ;


2 uang
3 −−−−−−−−
4 10.000
5 (1 row )
Bab 8

Python Akses Database


Data yang ada di PostgreSQL dapat digunakan oleh aplikasi yang ditulis den-
gan bahasa Python menggunakan pustaka tambahan bernama SQLAl hemy.
Pustaka ini dipilih karena sifatnya yang luwes dimana ia juga bisa menangani
database lainnya, tidak hanya PostgreSQL.
Sekarang pasanglah terlebih dahulu.

1 $ sudo a p t −g e t install python −s q l a l h e m y


2 $ sudo a p t −g e t install python −p s y o p g 2

Selanjutnya masuk ke modus interaktif untuk men oba.

1 >>> i m p o r t sqlal hemy as sa


2 >>> u r l = ' p o s t g r e s q l : / / ilham :1234 lo alhost / t o t a l i n d o '
3 >>> db = s a . r e a t e _ e n g i n e ( u r l )
4 >>> db . o n n e t ( )
5 <s q l a l h e m y . e n g i n e . b a s e . C o n n e t i o n obje t at 0 x8b0872 >

Sampai di sini Python sudah terhubung ke PostgreSQL dan uji oba login
berhasil dengan perintah onne t(). Anda bisa lanjutkan dengan perintah query
untuk melihat re ord tabel pegawai.

1 >>> s q l = "SELECT * FROM p e g a w a i "


2 >>> q = db . e x e u t e ( s q l )
3 >>> f o r r in q:
4 ... print r
5 ...
6 (1 , ' Bummi Dwi Putera ' , datetime . date (1985 , 8, 17) , True )
7 (2 , ' Arief Setiadi ' , datetime . date (1972 , 5, 2) , True )
8 (3 , ' Ce ep Zahrudin ' , datetime . date (1972 , 6, 1) , True )
9 (4 , ' Nita Pandria ' , datetime . date (1976 , 9, 19) , False )

Lalu bagaimana kalau kita ingin melihat nilai berdasarkan nama eld-nya
? Untunglah variabel r di atas bisa dianggap sebagai di tionary yang keys-nya
berisi nama eld dari query bersangkutan.

63
BAB 8. PYTHON AKSES DATABASE 64

1 >>> q = db . e x e u t e ( s q l )
2 >>> f o r r in q:
3 ... print r [ ' id ' ℄ , r [ ' nama ' ℄
4 ...
5 1 Bummi Dwi Putera
6 2 Arief Setiadi
7 3 Ce ep Zahrudin
8 4 Nita Pandria

Bahkan eld id dan nama bisa dianggap variabel milik r:

1 >>> q = db . e x e u t e ( s q l )
2 >>> f o r r in q:
3 ... print r . id , r . nama
4 ...
5 1 Bummi Dwi Putera
6 2 Arief Setiadi
7 3 Ce ep Zahrudin
8 4 Nita Pandria

Mudah bukan ?
Fungsi exe ute() bisa juga digunakan untuk perintah query lainnya seperti
INSERT, UPDATE, dan DELETE. Contohnya mengganti huruf pada eld nama
dengan kapital.

1 >>> s q l = "UPDATE p e g a w a i SET nama = u p p e r ( nama ) "


2 >>> db . e x e u t e ( s q l )
3 <s q l a l h e m y . e n g i n e . b a s e . R e s u l t P r o x y obje t at 0 x b 7 4 8 a 9 a >
4 >>> s q l = "SELECT * FROM p e g a w a i "
5 >>> q = db . e x e u t e ( s q l )
6 >>> f o r r in q:
7 ... print r . nama
8 ...
9 BUMMI DWI PUTERA
10 ARIEF SETIADI
11 CECEP ZAHRUDIN
12 NITA PANDRIA

8.1 A tive Re ord

Anda memiliki data pegawai dalam sebuah le yang berformat CSV yang isinya
seperti ini:

Listing 8.1: pegawai. sv

1 1 ;BUMMI DWI PUTERA, ST; 1 9 8 5 − 0 8 − 1 7 ; t


2 2 ; ARIEF SETIADI ; 1 9 7 2 − 0 5 − 0 2 ; t
3 3 ;CECEP ZAHRUDIN; 1 9 7 2 − 0 6 − 0 1 ; t
BAB 8. PYTHON AKSES DATABASE 65

4 4 ; NITA PANDRIA; 1 9 7 6 − 0 9 − 1 9 ; f
5 5 ; ILHAM; 1 9 8 4 − 1 1 − 0 5 ; t

File ini men erminkan tabel pegawai dimana setiap eld dipisahkan dengan
titik koma ( ; ). Sedangkan identitas baris berupa ID pegawai yang berada di
kolom pertama, persis seperti tabel pegawai. Tugasnya adalah menyalin isi le
ini ke dalam tabel pegawai. Jika ID pegawai sudah ada maka lakukan UPDATE,
jika belum berarti INSERT.
Mari kita lihat terlebih dahulu isi tabel pegawai melalui psql.

1 $ psql −U ilham −h lo alhost totalindo


2 Password for user ilham :
3 psql (8.4.4)
4 SSL onne tion ( ipher : DHE−RSA−AES256−SHA, bits : 256)
5 Type " help " for help .
6
7 t o t a l i n d o=> SELECT * FROM p e g a w a i ;
8 id | nama | tgl_lahir | pria
9 −−−−+−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−+−−−−−−
10 1 | BUMMI DWI PUTERA | 1985 − 08 − 17 | t
11 2 | ARIEF SETIADI | 1972 − 05 − 02 | t
12 3 | CECEP ZAHRUDIN | 1972 − 06 − 01 | t
13 4 | NITA PANDRIA | 1976 − 09 − 19 | f
14 (4 rows )

Bandingkanlah dengan le pegawai. sv sebelumnya dimana perubahannya


nanti adalah:

1. ID 1 nama akan berubah dari BUMMI DWI PUTERA menjadi BUMMI


DWI PUTERA, ST (bergelar).

2. Jumlah baris tabel pegawai bertambah dengan adanya ID 5 bernama IL-


HAM.

Buatlah le pegawai. sv terlebih dahulu dengan isi seperti di atas. Kemudian
buatlah le updatepegawai.py.

Listing 8.2: updatepegawai.py

1 import sqlal hemy as sa


2
3 url = ' p o s t g r e s q l : / / ilham :1234 lo alhost / t o t a l i n d o '
4 db = s a . r e a t e _ e n g i n e ( u r l )
5 db . o n n e t ( )
6
7 filename = ' pegawai . sv '
8 f = open ( f i l e n a m e )
9 for line in f . readlines () :
10 pid , nama , tgl_lahir , pria = line . strip () . s p l i t ( ' ; ' )
BAB 8. PYTHON AKSES DATABASE 66

11 pid = i n t ( pid )
12 p r i a = p r i a == 't ' # Agar b o o l e a n True / F a l s e
13 sql = "SELECT * FROM p e g a w a i WHERE i d = %d " % p i d
14 q = db . e x e u t e ( s q l )
15 if q . row ount :
16 s q l = "UPDATE p e g a w a i SET " + \
17 "nama = '% s ' , " + \
18 " t g l _ l a h i r = '% s ' , " + \
19 " p r i a = %s " + \
20 "WHERE i d = %d "
21 s q l = s q l % ( nama , tgl_lahir , pria , pid )
22 else :
23 s q l = "INSERT INTO p e g a w a i " + \
24 " ( id , nama , tgl_lahir , pria ) " + \
25 "SELECT %d , '% s ' , '% s ' , %s "
26 s q l = s q l % ( pid , nama , tgl_lahir , pria )
27 db . e x e u t e ( s q l )

Jalankan.

1 $ python u p d a t e p e g a w a i . py

Kemudian ke psql, lihat tabel pegawai.

1 t o t a l i n d o=> SELECT * FROM p e g a w a i ORDER BY i d ;


2 id | nama | tgl_lahir | pria
3 −−−−+−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−+−−−−−−
4 1 | BUMMI DWI PUTERA, ST | 1985 − 08 − 17 | t
5 2 | ARIEF SETIADI | 1972 − 05 − 02 | t
6 3 | CECEP ZAHRUDIN | 1972 − 06 − 01 | t
7 4 | NITA PANDRIA | 1976 − 09 − 19 | f
8 5 | ILHAM | 1984 − 11 − 05 | t
9 (5 rows )

Perubahan sudah sesuai dengan yang diharapkan. Meski begitu sour e


updatepegawai.py tergolong sulit diba a, dan ini bisa menyulitkan debugging
(penelusuran kesalahan). Cara yang lebih nyaman adalah menggunakan teknik
yang disebut a tive re ord .
Terlebih dahulu pasang paket Elixir.

1 $ sudo a p t −g e t install python − e l i x i r

Agar proses UPDATE dan INSERT masih terasa, buatlah perubahan pada
pegawai. sv berikut ini.

Listing 8.3: pegawai. sv

1 1 ;BUMMI DWI PUTERA, ST; 1 9 8 5 − 0 8 − 1 7 ; t


2 2 ; ARIEF SETIADI ; 1 9 7 2 − 0 5 − 0 2 ; t
3 3 ;CECEP ZAHRUDIN , ST; 1 9 7 2 − 0 6 − 0 1 ; t
BAB 8. PYTHON AKSES DATABASE 67

4 4 ; NITA PANDRIA; 1 9 7 6 − 0 9 − 1 9 ; f
5 5 ; ILHAM; 1 9 8 4 − 1 1 − 0 5 ; t
6 6 ;MIRANDA; 1 9 7 8 − 1 0 − 0 1 ; f

Perubahannya adalah UPDATE pada CECEP ZAHRUDIN menjadi CE-


CEP ZAHRUDIN, ST, dan INSERT pada MIRANDA. Selanjutnya buat le
updatepegawai1.py.

Listing 8.4: updatepegawai1.py

1 from elixir import Entity , using_options , setup_all ,


metadata , \
2 session
3
4 lass Pegawai ( E n t i t y ) :
5 u s i n g _ o p t i o n s ( t a b l e n a m e= ' p e g a w a i ' , a u t o l o a d=True )
6
7 metadata . b i n d = ' p o s t g r e s : / / ilham :1234 lo alhost /
totalindo '
8 setup_all ()
9
10 filename = ' pegawai . sv '
11 f = open ( f i l e n a m e )
12 for line in f . readlines () :
13 pid , nama , tgl_lahir , pria = line . strip () . s p l i t ( ' ; ' )
14 pid = i n t ( pid )
15 p = P e g a w a i . q u e r y . f i l t e r _ b y ( i d=p i d )
16 if p . ount ( ) :
17 r = p . one ( )
18 else :
19 r = Pegawai ( )
20 r . id = pid
21 r . nama = nama
22 r . tgl_lahir = tgl_lahir
23 r . p r i a = p r i a == 't '
24 s e s s i o n . ommit ( )

Jalankanlah.

1 $ python u p d a t e p e g a w a i 1 . py

Lalu lihat hasilnya di psql.

1 t o t a l i n d o=> SELECT * FROM p e g a w a i ORDER BY i d ;


2 id | nama | tgl_lahir | pria
3 −−−−+−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−+−−−−−−
4 1 | BUMMI DWI PUTERA, ST | 1985 − 08 − 17 | t
5 2 | ARIEF SETIADI | 1972 − 05 − 02 | t
6 3 | CECEP ZAHRUDIN , ST | 1972 − 06 − 01 | t
BAB 8. PYTHON AKSES DATABASE 68

7 4 | NITA PANDRIA | 1976 − 09 − 19 | f


8 5 | ILHAM | 1984 − 11 − 05 | t
9 6 | MIRANDA | 1978 − 10 − 01 | f
10 (6 rows )

Hasil sudah sesuai harapan dengan sour e yang jauh lebih mudah diba a.
Pahamilah baik-baik mengenai konsep a tive re ord ini.
Lalu bagaimana menghapus salah satu re ord ? Buatlah le deletepegawai.py
berikut ini.

Listing 8.5: deletepegawai.py

1 from elixir import Entity , using_options , metadata ,


setup_all , \
2 session
3 import sys
4
5 lass Pegawai ( E n t i t y ) :
6 u s i n g _ o p t i o n s ( t a b l e n a m e= ' p e g a w a i ' , a u t o l o a d=True )
7
8 if not sys . argv [ 1 : ℄ :
9 s y s . e x i t ( ' Caranya : p y t h o n %s <i d > ' % s y s . a r g v [ 0 ℄ )
10
11 try :
12 pid = i n t ( sys . argv [ 1 ℄ )
13 ex ept ValueError :
14 s y s . e x i t ( ' ID pegawai harus angka ' )
15
16 metadata . b i n d = ' p o s t g r e s : / / ilham :1234 lo alhost /
totalindo '
17 setup_all ()
18
19 p = P e g a w a i . q u e r y . f i l t e r _ b y ( i d=p i d )
20 if not p . ount ( ) :
21 s y s . e x i t ( ' ID p e g a w a i %d tidak ada ' % p i d )
22
23 r = p . one ( )
24 r . delete ()
25 s e s s i o n . ommit ( )
26 print ' ID p e g a w a i %d sudah dihapus ' % pid

S ript ini membutuhkan parameter masukan (argument) saat dijalankan,


yaitu berupa ID pegawai yang akan dihapus. Kita oba menghapus ID pegawai
4 NITA PANDRIA.

1 $ python d e l e t e _ p e g a w a i . py 4
2 ID pegawai 4 sudah dihapus

Periksa hasilnya di psql.


BAB 8. PYTHON AKSES DATABASE 69

1 t o t a l i n d o=> SELECT * FROM p e g a w a i ORDER BY i d ;


2 id | nama | tgl_lahir | pria
3 −−−−+−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−+−−−−−−
4 1 | BUMMI DWI PUTERA, ST | 1985 − 08 − 17 | t
5 2 | ARIEF SETIADI | 1972 − 05 − 02 | t
6 3 | CECEP ZAHRUDIN , ST | 1972 − 06 − 01 | t
7 5 | ILHAM | 1984 − 11 − 05 | t
8 6 | MIRANDA | 1978 − 10 − 01 | f
9 (5 rows )

Bagaimana dengan SELECT ? Contoh sebelumnya menggunakan lter_by()


yang sama artinya dengan WHERE. Kini kita tampilkan semua re ord tabel pe-
gawai tanpa kondisi apapun yaitu mengganti lter_by() dengan all(). Buatlah
sele tpegawai.py.

Listing 8.6: sele tpegawai.py

1 from elixir import Entity , using_options , metadata ,


setup_all
2 import sys
3
4 lass Pegawai ( E n t i t y ) :
5 u s i n g _ o p t i o n s ( t a b l e n a m e= ' p e g a w a i ' , a u t o l o a d=True )
6
7 metadata . b i n d = ' p o s t g r e s : / / ilham :1234 lo alhost /
totalindo '
8 setup_all ()
9
10 for r in Pegawai . q u e r y . a l l ( ) :
11 print r . id , r . nama , r . tgl_lahir , r . pria

Jalankan.

$ python sele t_pegawai.py


1 BUMMI DWI PUTERA, ST 1985-08-17 True
2 ARIEF SETIADI 1972-05-02 True
3 CECEP ZAHRUDIN, ST 1972-06-01 True
5 ILHAM 1984-11-05 True
6 MIRANDA 1978-10-01 False

Butuh tampilan yang urut berdasarkan nama ? Kita biasa menggunakan OR-
DER BY pada query, disini bisa menggunakan order_by() sebagai pengganti
all().

Listing 8.7: sele tpegawai2.py

1 from elixir import Entity , using_options , metadata ,


setup_all
2 import sys
BAB 8. PYTHON AKSES DATABASE 70

3
4 lass Pegawai ( E n t i t y ) :
5 u s i n g _ o p t i o n s ( t a b l e n a m e= ' p e g a w a i ' , a u t o l o a d=True )
6
7 metadata . b i n d = ' p o s t g r e s : / / ilham :1234 lo alhost /
totalindo '
8 setup_all ()
9
10 for r in P e g a w a i . q u e r y . o r d e r _ b y ( ' nama ' ) :
11 print r . id , r . nama , r . tgl_lahir , r . pria

Jalankan.

1 $ python s e l e t _ p e g a w a i . py
2 2 ARIEF SETIADI 1972 − 05 − 02 True
3 1 BUMMI DWI PUTERA, ST 1985 − 08 − 17 True
4 3 CECEP ZAHRUDIN , ST 1972 − 06 − 01 True
5 5 ILHAM 1984 − 11 − 05 True
6 6 MIRANDA 1978 − 10 − 01 False

Ingin yang lebih rapi ? Ubahlah seperti ini.

Listing 8.8: sele tpegawai.py

1 from elixir import *


2 import sys
3
4 lass Pegawai ( E n t i t y ) :
5 u s i n g _ o p t i o n s ( t a b l e n a m e= ' p e g a w a i ' , a u t o l o a d=True )
6
7 metadata . b i n d = ' p o s t g r e s : / / ilham :1234 lo alhost /
totalindo '
8 setup_all ()
9
10 jenis = { True : ' Pria ' ,
11 False : ' Wanita ' }
12
13 p = P e g a w a i . q u e r y . o r d e r _ b y ( ' nama ' )
14 for r in p:
15 print str ( r . id ) . enter (3) , \
16 r . nama . l j u s t ( 2 0 ) , \
17 r . tgl_lahir , \
18 jeni s [ r . pria ℄

Jalankan.

1 $ python s e l e t _ p e g a w a i . py
2 2 ARIEF SETIADI 1972 − 05 − 02 Pria
3 1 BUMMI DWI PUTERA, ST 1985 − 08 − 17 Pria
BAB 8. PYTHON AKSES DATABASE 71

4 3 CECEP ZAHRUDIN , ST 1972 − 06 − 01 Pria


5 5 ILHAM 1984 − 11 − 05 Pria
6 6 MIRANDA 1978 − 10 − 01 Wanita

Elixir vs SQLAl hemy ?


Sebenarnya Elixir bukanlah menggantikan SQLAl hemy, karena Elixir sendiri
menggunakan engine SQLAl hemy. Ini bisa terlihat pada penjelasan paket
python-elixir.

1 $ dpkg −s python − e l i x i r
2 Pa kage : python − e l i x i r
3 Version : 0.7.1 −1
4 Depends : p y t h o n (>= 2.4) , python −s u p p o r t (>= 0.90.0) ,
python − s q l a l h e m y (>= 0.4.0)
5 Des ription : De larative Mapper for SQLAl hemy

8.2 Auto Commit

Masih ingat fungsi sql bernama transaksi() ? Kali ini akan kita buat transaksi
perbankan se ara interaktif. Buatlah transaksi.py berikut.

Listing 8.9: transaksi.py

1 import sqlal hemy as sa


2 import sys
3
4 url = ' p o s t g r e s q l : / / ilham :1234 lo alhost / t o t a l i n d o '
5 db = s a . r e a t e _ e n g i n e ( u r l )
6
7 print ' Transaksi '
8 p i d = r a w _ i n p u t ( ' ID pegawai : ')
9 try :
10 pid = i n t ( pid )
11 ex ept ValueError :
12 s y s . e x i t ( ' ID p e g a w a i %s tidak benar ' % pid )
13
14 sql = "SELECT nama FROM p e g a w a i WHERE i d = %d " % p i d
15 q = db . e x e u t e ( s q l )
16 if not q . row ount :
17 s y s . e x i t ( ' ID p e g a w a i %d tidak ada ' % p i d )
18 print ' Nama : ' , q . f e t h o n e ( ) . nama
19
20 k e t = raw_input ( ' Keterangan : ')
21 if not ket :
22 s y s . e x i t ( ' Keterangan harus diisi ')
BAB 8. PYTHON AKSES DATABASE 72

23
24 n o m i n a l = r a w _ i n p u t ( ' Nominal : ')
25 try :
26 nominal = f l o a t ( nominal )
27 ex ept ValueError :
28 s y s . e x i t ( ' Nominal %s tidak benar ' % nominal )
29
30 sql = "SELECT t r a n s a k s i (%d , ' % s ' , % . 2 f ) " % ( p i d , ket ,
nominal )
31 q = db . e x e u t e ( s q l )
32 print ' Transaksi berhasil , ID ' , q . fet hone () . transaksi

Jalankan.

1 $ python t r a n s a k s i . py
2 Transaksi
3 ID pegawai : 3
4 Nama : CECEP ZAHRUDIN , ST
5 Keterangan : GAJI 11 − 2010
6 Nominal : 4500000
7 Transaksi berhasil , ID 4

Untuk memastikan transaksi benar-benar berhasil, lihatlah di psql.

1 t o t a l i n d o=> SELECT * FROM t r a n s a k s i ;


2 id | pid | tgl | ket | nominal | saldo
3 −−−−+−−−−−+−−−−−−−−−−−−+−−−−−−−−−−−−−−+−−−−−−−−−+−−−−−−−−
4 1 | 1 | 2010 − 10 − 22 | GAJI 11 − 2010 | 3 0 0 0 0 0 0 | 3 0 0 0 0 0 0
5 2 | 1 | 2010 − 10 − 22 | BON | − 200000 | 2 8 0 0 0 0 0
6 3 | 5 | 2010 − 10 − 22 | GAJI 11 − 2010 | 1 5 0 0 0 0 0 | 1 5 0 0 0 0 0
7 (3 rows )

Perhatikan, tidak ada ID transaksi 4, padahal eksekusi transaksi.py berjalan


baik. Apa yang terjadi ?
SQL fun tion transaksi() yang dijalankan oleh transaksi.py dijalankan pada
modus transa tion . Ini bisa diartikan SQLAl hemy atau mungkin Psy opg2
yang digunakan SQLAl hemy otomatis menjalankan BEGIN sebelum SELECT
transaksi( ... ). Seperti kita ketahui BEGIN tanpa COMMIT sama artinya den-
gan ROLLBACK. Itu artinya semua aktitas DML seperti INSERT, UPDATE,
DELETE setelah BEGIN dibatalkan, seolah tidak terjadi.
Solusinya adalah memberitahukan SQLAl hemy untuk menjalankan auto
ommit . Ubahlah transaksi.py menjadi berikut ini.

Listing 8.10: transaksi.py

1 import sqlal hemy as sa


2 from sqlal hemy . s q l . expression import text
3 import sys
4
BAB 8. PYTHON AKSES DATABASE 73

5 url = ' p o s t g r e s q l : / / ilham :1234 lo alhost / t o t a l i n d o '


6 db = s a . r e a t e _ e n g i n e ( u r l )
7
8 print ' Transaksi '
9 p i d = r a w _ i n p u t ( ' ID pegawai : ')
10 try :
11 pid = i n t ( pid )
12 ex ept ValueError :
13 s y s . e x i t ( ' ID p e g a w a i %s tidak benar ' % pid )
14
15 sql = "SELECT nama FROM p e g a w a i WHERE i d = %d " % p i d
16 q = db . e x e u t e ( s q l )
17 if not q . row ount :
18 s y s . e x i t ( ' ID p e g a w a i %d tidak ada ' % p i d )
19 print ' Nama : ' , q . f e t h o n e ( ) . nama
20
21 k e t = raw_input ( ' Keterangan : ')
22 if not ket :
23 s y s . e x i t ( ' Keterangan harus diisi ')
24
25 n o m i n a l = r a w _ i n p u t ( ' Nominal : ')
26 try :
27 nominal = f l o a t ( nominal )
28 ex ept ValueError :
29 s y s . e x i t ( ' Nominal %s tidak benar ' % nominal )
30
31 sql = "SELECT t r a n s a k s i (%d , ' % s ' , % . 2 f ) " % ( p i d , ket ,
nominal )
32 q = db . e x e u t e ( t e x t ( s q l , a u t o o m m i t=True ) )
33 print ' Transaksi berhasil , ID ' , q . fet hone () . transaksi

Penambahan pada baris 2:

from sqlal hemy.sql.expression import text

dan perubahan pada baris 32 dari

q = db.exe ute(sql)

menjadi

q = db.exe ute(text(sql, auto ommit=True))

8.3 Syn hronizer

Pelanggan Anda memiliki usaha di bidang mini market dan telah memiliki be-
berapa outlet. Semua outlet itu telah terhubung ke Internet. Internet digunakan
BAB 8. PYTHON AKSES DATABASE 74

untuk mengambil data produk yang dikirim kantor pusat melalui email. Data
produk tersebut tersimpan dalam atta hment. User di outlet menyimpannya ke
folder tertentu untuk selanjutnya dimasukkan ke database outlet melalui menu
Restore yang telah disediakan di aplikasi. Begitu juga dengan data transak-
si. Data disimpan terlebih dahulu ke dalam sebuah le melalui menu Ba kup.
Selanjutnya le tersebut di-email ke kantor pusat.
Teknik ini sudah baik, namun lebih baik lagi jika pekerjaan itu dilakukan
oleh s ript yang disebut syn hronizer.
Kita membi arakan mekanisme otomatis penuh, dimana syn hronizer dipi u
oleh waktu, misalkan jam 9:00 dan jam 17:00 setiap harinya. Berbeda dengan
teknik sebelumnya, syn hronizer tidak menggunakan email untuk komunikasi
data. Ia bekerja langsung dengan database pusat dan database outlet.
Lalu bagaimana kedua host outlet dan pusat saling terhubung ?
Ya, kita memerlukan IP publik di kantor pusat agar syn hronizer di out-
let dapat mengakses database pusat. IP publik ini dapat dipesan ke ISP (In-
ternet Servi e Provider) bersangkutan. Setelah IP publik didapat, tambahkan
baris berikut ini di /et /postgresql/8.4/main/pg_hba. onf:

host all all 0.0.0.0/0 md5

Kongurasi ini artinya semua host dapat mengakses database pusat, tentunya
dengan otentikasi username dan password. Simpan dan restart daemon-nya:

1 $ sudo servi e postgresql −8.4 restart


2 * Restarting PostgreSQL 8.4 database server

Kini saatnya uji konektivitas database. Misalkan IP publiknya adalah 110.137.120.251,


maka jalankan di outlet :

1 $ psql −U ilham −h 110.137.120.251 totalindo

Di s ript Python gantilah lo alhost dengan IP publik tadi.

url = 'postgresql://ilham:1234110.137.120.251/totalindo'

Mudah bukan ?

8.3.1 Aspek Keamanan


Tapi nanti dulu. Meski outlet itu hanya mendapat akses terbatas di database
pusat, namun tetap saja ini masih menimbulkan resiko keamanan data. Alangkah
baiknya menggunakan teknik sebaliknya, yaitu syn hronizer berada di pusat .
Dengan kata lain pusat-lah yang memba a database outlet, sedangkan outlet
tidak mendapat hak akses apapun di database pusat.
Lalu bagaimana host pusat mengakses host outlet ? Apa perlu pesan IP
publik lagi ke ISP yang ada di outlet ?
Idealnya ya, namun tidak harus. Kita bisa menerapkan VPN alias Virtual
Private Network. Cukup pasang VPN server di pusat, dan pasang VPN lient
BAB 8. PYTHON AKSES DATABASE 75

di outlet. Dengan VPN ini terbentuk jaringan baru dengan IP pusat 10.8.0.1,
sedangkan IP outlet 10.8.0.6, 10.8.0.10, 10.8.0.14, dst. Baik VPN server maupun
VPN lient bisa kita gunakan OpenVPN. Untuk pemasangan keduanya silahkan
ba a url berikut ini:

http://jabber.rab. o.id/os/konfigurasi-openvpn

Apakah OpenVPN dapat bekerja di Windows mengingat masih banyak outlet


yang menggunakan sistem operasi ini ?
Ya, untungnya OpenVPN tersedia di untuk sistem operasi itu, dan tetap
dapat diatur agar otomatis aktif saat komputer dihidupkan.
Baik di pusat maupun di outlet jalankan perintah ini untuk mengetahi IP
VPN masing-masing:

1 $ if onfig tun0
2 tun0 Link e n a p : UNSPEC HWaddr
00−00−00−00−00−00−00−00−00−00−00−00−00−00−00−00
3 inet addr : 1 0 . 8 . 0 . 6 P−t −P : 1 0 . 8 . 0 . 5 Mask
:255.255.255.255
4 UP POINTOPOINT RUNNING NOARP MULTICAST MTU
:1500 Metri : 1
5 RX p a k e t s : 0 errors :0 dropped : 0 overruns :0
frame : 0
6 TX p a k e t s : 6 errors :0 dropped : 0 overruns :0
arrier :0
7 o l li s i on s :0 txqueuelen :100
8 RX b y t e s : 0 (0.0 B) TX b y t e s : 9 6 3 ( 9 6 3 . 0 B)

Tampak IP VPN di outlet adalah 10.8.0.6, sedangkan IP VPN di pusat


biasanya 10.8.0.1. Di host pusat, Anda juga bisa lihat IP masing-masing lient di
le /et /openvpn/ipp.txt. Jangan lupa untuk menguji konektivitas network
dengan perintah ping.
OpenVPN telah terpasang dan kedua host pusat dan outlet sudah bisa saling
ping. Selanjutnya apa yang harus dilakukan ?
Tambahkan baris berikut ini di /et /postgresql/8.4/main/pg_hba. onf
di outlet .

host all all 10.8.0.1/32 md5

Lalu restart daemon-nya.

1 $ sudo servi e postgresql −8.4 restart


2 * Restarting PostgreSQL 8.4 database server

Di pusat lakukan uji konektivitas dengan psql.

1 $ psql −U ilham −h 10.8.0.6 totalindo

Jika sudah terhubung baik, saatnya membuat s ript syn hronizer.


BAB 8. PYTHON AKSES DATABASE 76

8.3.2 Tambah, Perbaharui, Hapus


Adalah sebuah tabel produk dengan struktur sebagai berikut:

Listing 8.11: produk.sql

1 reate table produk (


2 id serial primary key ,
3 nama name not null unique ,
4 harga float not null
5 ) ;

Isilah dengan beberapa re ord berikut ini:

1 INSERT INTO p r o d u k ( nama , h a r g a ) SELECT ' Jeruk Pontianak '


,10500;
2 INSERT INTO p r o d u k ( nama , h a r g a ) SELECT ' Salak Pondoh '
,9250;
3 INSERT INTO p r o d u k ( nama , h a r g a ) SELECT ' Mangga Indramayu '
,14300;

Untuk menyamakan data produk, kita memerlukan dua perulangan (loop).


Yang pertama untuk INSERT dan UPDATE, sedangkan yang kedua untuk
DELETE. Berikut yang pertama:

1. Setiap re ord pusat diba a.

2. Field id menjadi a uan, karena dia primary key.

3. Jika id tidak ditemukan di outlet maka tambahkan.

4. Jika id ditemukan maka perbaharui.

Sedangkan untuk menghapus:

1. Setiap re ord outlet diba a.

2. Jika id tidak ditemukan di pusat maka hapus yang ada di outlet.

Lalu mulailah membuat syn .py berikut ini.

Listing 8.12: syn .py

1 import sqlal hemy as sa


2 from elixir import Entity , using_options , setup_all ,
metadata
3 from s q l a l h e m y . orm import s oped_session , sessionmaker
4 from s q l a l h e m y . s hema import ThreadLo alMetaData
5
6
7 es = sa . reate_engine ( ' p o s t g r e s q l : / / ilham :1234 lo alhost /
totalindo ' )
BAB 8. PYTHON AKSES DATABASE 77

8 et = sa . reate_engine ( ' p o s t g r e s q l : / / ilham :1234 lo alhost /


totalindo2 ' )
9
10 s s = s o p e d _ s e s s i o n ( s e s s i o n m a k e r ( b i n d=e s ) )
11 s t = s o p e d _ s e s s i o n ( s e s s i o n m a k e r ( b i n d=e t ) )
12
13 ms = m e t a d a t a
14 mt = T h r e a d L o a l M e t a D a t a ( )
15
16 ms . b i n d = e s
17 mt . b i n d = e t
18
19
20 lass ProdukS ( E n t i t y ) :
21 u s i n g _ o p t i o n s ( t a b l e n a m e= ' p r o d u k ' , a u t o l o a d=True ,
m e t a d a t a=ms , s e s s i o n=s s )
22
23 lass ProdukT ( E n t i t y ) :
24 u s i n g _ o p t i o n s ( t a b l e n a m e= ' p r o d u k ' , a u t o l o a d=True ,
m e t a d a t a=mt , s e s s i o n=s t )
25
26 setup_all ()
27
28 # INSERT & UPDATE
29
30 all_ps = [℄
31 for ps in ProdukS . q u e r y . a l l ( ) :
32 print ps . id , p s . nama , ps . harga ,
33 try :
34 p t = ProdukT . q u e r y . f i l t e r _ b y ( i d=p s . i d ) . o n e ( )
35 print ' diubah '
36 ex ept s a . orm . e x . NoResultFound , e:
37 print ' ditambah '
38 p t = ProdukT ( i d=p s . i d )
39 p t . nama = p s . nama
40 pt . harga = ps . harga
41 s t . ommit ( )
42 a l l _ p s . append ( p s . i d )
43
44 # DELETE
45
46 for pt in ProdukT . q u e r y . a l l ( ) :
47 if not in
pt . i d all_ps :
48 print pt . id , p t . nama , pt . harga , ' dihapus '
49 pt . d e l e t e ( )
50 s t . ommit ( )
BAB 8. PYTHON AKSES DATABASE 78

8.4 Migrasi dari Database Lain

Anda sudah memiliki aplikasi yang menggunakan MySQL, dan kini ingin beralih
ke PostgreSQL. Setidaknya dibutuhan penyalinan struktur tabel beserta isinya.
Terlebih dahulu pasanglah driver MySQL.

1 $ sudo a p t −g e t install python −mysqldb

Lalu buatlah dbmigration.py berikut ini.

Listing 8.13: dbmigration.py

1 import sqlal hemy as sa


2 from s q l a l h e m y . s hema import ThreadLo alMetaData
3 from s q l a l h e m y . orm import s oped_session , sessionmaker
4 from elixir import *
5 import sys
6
7
8 dbs = s a . r e a t e _ e n g i n e ( s y s . a r g v [ 1 ℄ ) # sour e
9 dbt = s a . r e a t e _ e n g i n e ( s y s . a r g v [ 2 ℄ ) # target
10 dbs . o n n e t ( )
11 dbt . o n n e t ( )
12 s e s s i o n _ s = s o p e d _ s e s s i o n ( s e s s i o n m a k e r ( b i n d=d b s ) )
13 s e s s i o n _ t = s o p e d _ s e s s i o n ( s e s s i o n m a k e r ( b i n d=d b t ) )
14 metadata_s = m e t a d a t a
15 metadata_t = T h r e a d L o a l M e t a D a t a ( )
16 metadata_s . b i n d = d b s
17 metadata_t . b i n d = d b t
18
19 for tablename in dbs . table_names ( ) :
20 lass Sour e ( Entity ) :
21 u s i n g _ o p t i o n s ( t a b l e n a m e=t a b l e n a m e , a u t o l o a d=True ,
22 m e t a d a t a=metadata_s , s e s s i o n=s e s s i o n _ s )
23
24 setup_all ()
25
26 lass Target ( Entity ) :
27 u s i n g _ o p t i o n s ( t a b l e n a m e=t a b l e n a m e ,
28 m e t a d a t a=metadata_t , s e s s i o n=s e s s i o n _ t )
29 for olumn in S o u r e . mapper . o l u m n s :
30 h a s _ f i e l d ( olumn . name , olumn . t y p e ,
31 p r i m a r y _ k e y= olumn . primary_key ,
32 r e q u i r e d= not olumn . n u l l a b l e ,
33 )
34
35 s e t u p _ a l l ( True )
36
BAB 8. PYTHON AKSES DATABASE 79

Database Paket

PostgreSQL python-psy opg2


MySQL python-mysqldb
SQLite python-sqlite2
Interbase python-kinterbasdb
MS SQL python-pymssql

Tabel 8.1: Driver database

37 for sour e in Sour e . query . a l l ( ) :


38 t a r g e t = Target ( )
39 t a r g e t . from_di t ( sour e . to_di t ( ) )
40 s e s s i o n _ t . ommit ( )

Contoh penggunaan:

1 python d b m i g r a t i o n . py m y s q l : / / r o o t : 6 7 8 9  l o a l h o s t / sumber
postgres :// j e f r i :1234 lo alhost / target

Proses migrasi ini sudah menyertakan pembuatan tabel berikut onstraint


seperti PRIMARY KEY dan NULL.
Untuk driver database lainnya Anda bisa lihat di informasi paket python-
sqlal hemy, dan perhatikan bagian Suggests.

1 $ dpkg −s python − s q l a l h e m y
2 ..
3 Suggests : python −s q l a l h e m y −do , python −p s y o p g 2 , python −
mysqldb (>= 1 . 2 . 1 − p2 − 2) , p y t h o n (>= 2.5) | python −
pysqlite2 (>= 2 . 3 . 0 − 1 ) | python − p y s q l i t e 1 . 1 (>=
1.1.7 −2) | python − s q l i t e (>= 1 . 0 . 1 − 5 ) , python −
kinterbasdb (>= 3.1.2 −0.3) , python −p y m s s q l
4 ..

Perhatikan bagian Suggests.


Bab 9

Lintas Sistem
Kita telah membahas mengenai manfaat modularitas dalam fungsi dan modul
dimana sebuah aplikasi disusun bagaikan sebuah lego. Jika keseluruhan sistem
semakin kompleks maka hindari konsep pemaksaan seperti semua harus dit-
ulis dengan Python atau semua harus menggunakan PostgreSQL. Kali ini kita
oba pahami bagaimana komunikasi antar sistem bisa terjadi tanpa pemaksaan
platform tertentu.

9.1 Command Line

S ript Python Anda membutuhkan informasi mengenai network devi e berikut


IP-nya. Anda tidak tahu modul apa yang bisa digunakan. Namun Anda tahu
betul bahwa ommand line if ong sanggup melakukannya.

1 $ if onfig
2 eth0 Link en ap : Ethernet HWaddr 0 0 : 2 5 : b3 : 7 7 : 3 e : 9 9
3 inet addr : 1 9 2 . 1 6 8 . 1 1 . 1 1 1 B ast : 1 9 2 . 1 6 8 . 1 1 . 2 5 5
Mask : 2 5 5 . 2 5 5 . 2 5 5 . 0
4 UP BROADCAST MULTICAST MTU: 1 5 0 0 Metri : 1
5 RX p a k e t s : 0 errors :0 dropped : 0 overruns :0
frame : 0
6 TX p a k e t s : 0 errors :0 dropped : 0 overruns :0
arrier :0
7 o l li s i on s :0 txqueuelen :1000
8 RX b y t e s : 0 (0.0 B) TX b y t e s : 0 (0.0 B)
9 Interrupt :17
10
11 lo Link en ap : Lo al Loopba k
12 inet addr : 1 2 7 . 0 . 0 . 1 Mask : 2 5 5 . 0 . 0 . 0
13 inet6 addr : ::1/128 S ope : Host
14 UP LOOPBACK RUNNING MTU: 1 6 4 3 6 Metri : 1

80
BAB 9. LINTAS SISTEM 81

15 RX p a k e t s : 5 6 2 errors :0 dropped : 0 overruns :0


frame : 0
16 TX p a k e t s : 5 6 2 errors :0 dropped : 0 overruns :0
arrier :0
17 o l li s i on s :0 txqueuelen :0
18 RX b y t e s : 5 4 0 8 4 8 ( 5 4 0 . 8 KB) TX b y t e s : 5 4 0 8 4 8
( 5 4 0 . 8 KB)
19
20 wlan0 Link en ap : Ethernet HWaddr 0 0 : 1 f : 3 : e0 : 6 6 : 5 6
21 inet addr : 1 9 2 . 1 6 8 . 1 . 4 B ast : 1 9 2 . 1 6 8 . 1 . 2 5 5
Mask : 2 5 5 . 2 5 5 . 2 5 5 . 0
22 inet6 addr : fe80 : : 2 1 f : 3 f f : f e e 0 :6656/64 S ope :
Link
23 UP BROADCAST RUNNING MULTICAST MTU: 1 5 0 0
Metri : 1
24 RX p a k e t s : 3 2 1 9 errors :0 dropped : 0 overruns :0
frame : 0
25 TX p a k e t s : 3 6 0 8 errors :0 dropped : 0 overruns :0
arrier :0
26 o l li s i on s :0 txqueuelen :1000
27 RX b y t e s : 1 5 8 6 2 9 7 ( 1 . 5 MB) TX b y t e s : 7 6 1 1 7 3
( 7 6 1 . 1 KB)

Bagaimana memanggil ommand line di s ript Python dan mengolah hasil-


nya ? Gunakan modul ommands. Buatlah netdev.py berikut ini.

Listing 9.1: netdev.py

1 import ommands
2 import re
3
4 def netdev ( ) :
5 r = {}
6 for line in ommands . g e t o u t p u t ( ' i f o n f i g ' ) . s p l i t l i n e s
() :
7 line = line . strip ()
8 mat h = r e . o m p i l e ( ' ( . * ) L i n k en ap ( . * ) ' ) . s e a r h (
line )
9 if mat h :
10 d e v i e = mat h . g r o u p ( 1 ) . s t r i p ( )
11 r [ devi e ℄ = {}
12 mat h = r e . o m p i l e ( ' HWaddr ( . * ) ' ) . sear h ( l i n e
)
13 if mat h :
14 r [ d e v i e ℄ [ ' addr ' ℄ = mat h . g r o u p ( 1 )
15 ontinue
16 mat h = r e . o m p i l e ( ' i n e t addr : ( . * ) ' ) . s e a r h ( l i n e )
BAB 9. LINTAS SISTEM 82

17 if mat h :
18 r [ devi e ℄ [ ' ip ' ℄ = mat h . g r o u p ( 1 ) . s p l i t ( ) [ 0 ℄
19 return r
20
21
22 if __name__ == '__main__ ' :
23 nd = n e t d e v ( )
24 for dev in nd :
25 print dev , nd [ d e v ℄

Jalankan.

1 $ python n e t d e v . py
2 wlan0 { ' ip ' : '192.168.1.4 ' , ' addr ' : ' 0 0 : 1 f : 3 : e0 : 6 6 : 5 6 ' }
3 lo { ' ip ' : '127.0.0.1 '}
4 eth0 { ' ip ' : '192.168.11.111 ' , ' addr ' : ' 0 0 : 2 5 : b3 : 7 7 : 3 e
:99 '}

Lintas sistem yang menggunakan ommand line ini tergolong lokal, artinya
netdev.py harus berada di komputer yang sama dengan if ong.

9.2 File

File bisa digunakan sebagai sarana pemersatu input dan output. Misalkan An-
da sudah membuat sebuah daemon yang dapat menerima dan mengirim SMS.
Daemon ini pengendali modem. Oh ya, daemon adalah program yang selalu
hidup untuk siap menerima perintah.
Di sisi lain Anda juga punya program penerjemah SMS yang masuk (SMS
parser) dan juga berfungsi untuk membalas ke si pengirim. Bagaimana kedua
program ini dapat berhubungan ?
Anda bisa menggunakan le sebagai perantara. Saat ada SMS masuk, dae-
mon pengendali modem menyimpannya dalam sebuah le di direktori /var/spool/-
modem/inbox. Kemudian SMS parser memba a direktori ini, menerjemahkan
lenya, dan membalas SMS tersebut dengan ara membuat le di direktori
/var/spool/modem/outbox. File tersebut diba a oleh daemon si modem untuk
kemudian mengirim SMS yang dimaksud.
Baik daemon modem maupun SMS parser bisa ditulis dengan bahasa yang
berbeda. Mungkin yang pertama dengan C++, sementara yang satunya di tulis
dengan Python. Namun keduanya bekerja menggunakan direktori yang sama.
Ini juga tergolong lintas sistem yang lokal, keduanya harus di komputer yang
sama.

Dengan teknik NFS atau Samba Anda bisa membuat direktori bersama
(sharing dire tory) di komputer lain (remote host).
BAB 9. LINTAS SISTEM 83

9.3 Database

Pelanggan Anda telah memiliki sebuah sistem pengisian pulsa dimana terdapat
fungsi yang berkaitan dengan GSM modem. Fungsi yang dimaksud adalah yang
berkaitan dengan SMS gateway yaitu mengirim dan menerima SMS.
Pelanggan ini telah membuat sistemnya menggunakan Borland Delphi (ba-
hasa Pas al) dan menggunakan database MySQL. Ia mengeluh pada Anda se-
laku developer outsour ing dimana komponen SMS gateway yang dibangun-
nya tidak stabil. Di sisi lain Anda telah membuat SMS gateway yang ditulis
dengan bahasa Python dan database PostgreSQL. Tidak seperti yang dimiliki
pelanggan tersebut, SMS gateway yang Anda buat sangat stabil dan telah teruji
bertahun-tahun. Masalah penyatuan semakin bertambah dimana SMS gateway
Anda berada di sistem operasi Linux, sementara pelanggan Anda menggunakan
Mi rosoft Windows.
Langkah apa yang diambil untuk membuat SMS gateway-nya stabil ? An-
da belajar Borland Delphi untuk menerjemahkan algoritma Python ? Atau
memaksa pelanggan Anda itu untuk belajar Python dan membangun ulang
sistem pengisian pulsanya ?
Langkah yang bijaksana tentu tidak keduanya, karena porsi tidak seimbang
yang mengakibatkan penyatuan menjadi sangat lama. Solusi sederhana adalah
menggunakan database sebagai perantara. Mintalah padanya untuk menyedi-
akan sebuah komputer lagi untuk SMS gateway Anda, sebut saja server SMS
gateway. Server ini terhubung melalui LAN (lo al area network) dengan server
pengisian pulsa yang berbasis Windows tadi.
Tanpa perubahan ? Tentu saja ada.
Ran angan SMS gateway yang Anda buat harus dapat mengirim SMS hanya
dengan menggunakan perintah INSERT. Contoh:

1 INSERT INTO im . a n t r i a n ( p e n e r i m a , pesan ) SELECT '


+628177654321 ' , ' Selamat bergabung ' ;

Lalu apa yang dilakukan oleh pelanggan Anda tadi ? Ia perlu mengubah
sour e Borland Delphi-nya, yaitu pada fungsi pengiriman SMS menggunakan
koneksi ke database PostgreSQL yang ada di server SMS gateway. Biasanya
driver ODBC dapat mengatasi hal ini.
Lho, bukankah ia menggunakan MySQL sebagai database ? Benar, MySQL
untuk komponen pengisian pulsa tetap berlaku. Jadi dalam aplikasi Borland
Delphi terdapat dua koneksi database, yaitu ke MySQL yang ada di lo alhost
Mi rosoft Windows, dan ke PostgreSQL yang ada di remote host Linux.
Lalu bagaimana untuk memba a SMS yang masuk ? Kembali, Anda diminta
untuk menyimpan SMS yang masuk ke dalam sebuah tabel, katakanlah bernama
inbox. Selanjutnya pelanggan Anda dapat memba anya menggunakan perintah
SELECT pada Borland Delphi.

1 SELECT * FROM im . a n t r i a n WHERE NOT k i r i m ;

Mudah bukan ? Lebih lanjut mengenai SMS gateway bisa lihat halaman115.
BAB 9. LINTAS SISTEM 84

Lintas sistem ini tergolong bisa beda komputer, karena baik PostgreSQL
maupun MySQL dapat diakses melalui jalur network.

9.4 XMLRPC

Database sebagai perantara bisa jadi ditolak dengan berbagai alasan. Salah
satunya adalah aspek tanggung jawab, atau biasa disebut aspek keamanan (se-
urity). Misalkan dalam sistem perbankan. Sistem utama sebuah bank diban-
gun oleh PT Software Aman Banget (SAB). Namanya juga sistem utama, ia
memuat data penting nasabah serta data yang menyangkut sistem.
Suatu saat bank ini ingin go Internet dimana nasabah dapat melakukan
transaksi melalui browser Firefox. Berarti dibutuhkan web developer dan dip-
ilihlah PT Web Perkasa (WP) untuk mengembangkannya. Karena mengem-
bangkan Internet banking, berarti ada proses login untuk nasabah. Ini berarti
ada algoritma pemeriksaan username dan password. Sampai disini tidaklah
menjadi masalah karena username dan password web bisa berada di web server
yang dibangun oleh WP.
Tibalah saatnya nasabah ingin melihat mutasi transaksinya. Apakah WP
melakukan SELECT tabel ke sistem utama bank tersebut yang dibangun oleh
SAB ?
Mayoritas jawabannya tidak. Mengapa ?
SELECT berarti kita bi ara koneksi ke database. Itu artinya WP menge-
tahui username dan password untuk login ke database sistem utama. Kalau
sudah begitu maka WP bisa melihat-lihat data nasabah lainnya, bahkan meli-
hat tabel-tabel yang menyangkut sistem. Jelas ini sudah terlalu jauh dan bisa
menimbulkan hal-hal yang tak perlu.
Untuk menghindari koneksi database ke sistem utama, maka digunakanlah
XMLRPC sebagai perantaranya. Makanan apakah ini ?
XMLRPC adalah XML Remote Pro edure Call, yaitu sebuah bahasa per-
tukaran data yang ditulis dalam format XML. Kita dapat memandang RPC
sebagai pemanggilan fungsi yang memiliki nilai masukan (input parameter) dan
nilai keluaran (output / return value). Sebagaimana fungsi sederhana ini.

1 def tambah ( a , b) :
2 return a + b

XMLRPC bisa juga disebut sebagai web servi e karena dokumen XML
tersebut dikirim menggunakan HTTP atau HTTPS dengan method POST.
Karena web servi e, maka kita bi ara koneksi lient - server, sehingga ada
penyebutan XMLRPC lient dan XMLRPC server. Penggunaannya tergolong
simple dan pustakanya (library) banyak tersedia untuk berbagai bahasa seperti
Python, PHP, Java, Borland Delphi, Visual Basi , dst.
Kembali pada web developer di atas. WP mengembangkan web-nya menggu-
nakan PHP, sementara SAB mengembangkan sistem bank menggunakan Python.
Database keduanya juga berbeda dimana WP menggunakan MySQL, sedangkan
SAB menggunakan PostgreSQL. Namun semuanya itu tidak lagi menjadi hal.
BAB 9. LINTAS SISTEM 85

Langkah apa yang harus dikembangkan terlebih dahulu ?


Jelas bahwa SAB harus mengembangkan XMLRPC server terlebih dahulu
yang berisi fungsi mutasi(). Mari kita mulai membuat le serverbank.py.

Listing 9.2: serverbank.py

1 from SimpleXMLRPCServer import SimpleXMLRPCServer


2 import sqlal hemy as sa
3
4
5 lass S e r v e r ( SimpleXMLRPCServer ) :
6 a l l o w _ r e u s e _ a d d r e s s = True
7
8 def verify_request ( self , request , lient_address ) :
9 server . ip_ lient = lient_address [ 0℄
10 print server . ip_ lient
11 return server . ip_ lient in [ ' 127.0.0.1 ' , '
192.168.0.1 ' , ' 192.168.1.5 ' ℄
12
13
14 def r e s p ( ode , msg ) :
15 return { ' kode ' : ode ,
16 ' pesan ' : msg }
17
18
19 lass Agent :
20 def _dispat h ( s e l f , method , params =() ) :
21 print method , params
22 try :
23 fun = g e t a t t r ( s e l f , ' e x p o r t _ ' + method )
24 ex ept AttributeError :
25 return r e s p ( −1 , ' F u n g s i %s tidak dikenal ' %
method )
26 return f u n ( * params )
27
28 def export_mutasi ( s e l f , p) :
29 s q l = "SELECT t g l : : date , ket , nominal , saldo " +
\
30 "FROM t r a n s a k s i WHERE p i d = %d " + \
31 "AND t g l : : d a t e BETWEEN '% s ' AND '% s ' " + \
32 "ORDER BY i d "
33 s q l = s q l % (p [ ' pid ' ℄ , p [ ' awal ' ℄ , p [ ' akhir ' ℄ )
34 q = db . e x e u t e ( s q l )
35 m = [℄
36 for r in q:
37 m. append ( [ s t r ( r . t g l ) , r . ket , r . nominal , r.
saldo ℄ )
BAB 9. LINTAS SISTEM 86

38 r = r e s p ( 0 , 'OK ' )
39 r [ ' mutasi ' ℄ = m
40 return r
41
42
43
44 url = ' p o s t g r e s q l : / / ilham :1234 lo alhost / t o t a l i n d o '
45 db = s a . r e a t e _ e n g i n e ( u r l )
46
47 port = 9303
48 s e r v e r = Server ( ( ' 0 . 0 . 0 . 0 ' , port ) )
49 server . register_introspe tion_fun tions ()
50 s e r v e r . r e g i s t e r _ i n s t a n e ( Agent ( ) )
51 print 'HTTP XMLRPC s e r v e r port ' , port
52 server . serve_forever ()

Jalankan.

1 $ python s e r v e r b a n k . py
2 HTTP XMLRPC s e r v e r port 9303

Proses seolah hang, tapi sebenarnya ia sedang menunggu permintaan (re-


quest) dari XMLRPC lient. Port 9303 hanya ontoh saja dimana Anda bisa
mengganti dengan nilai lainnya. Se urity yang diterapkan di sini adalah IP
lient yang hanya menerima permintaan dari 127.0.0.1 dan 192.168.0.1.
Selanjutnya membuat XMLRPC lient bernama lientbank.py.

Listing 9.3: lientbank.py

1 import xmlrp lib


2
3 url = ' http : / / 1 2 7 . 0 . 0 . 1 : 9 3 0 3 '
4 remote = x m l r p l i b . ServerProxy ( u r l )
5 d = { ' pid ' : 1,
6 ' awal ' : ' 20101022 ' ,
7 ' akhir ' : ' 20101023 ' }
8 r = remote . mutasi ( d )
9 if r [ ' k o d e ' ℄ == 0 :
10 for tgl , ket , nominal , saldo in r [ ' mutasi ' ℄ :
11 print tgl , ket . l j u s t (15) , \
12 s t r ( i n t ( nominal ) ) . r j u s t ( 1 0 ) , \
13 s t r ( int ( saldo ) ) . r j u s t (10)
14 else :
15 print r [ ' pesan ' ℄

Bukalah konsole lainnya, lalu jalankan le ini.

1 $ python l i e n t b a n k . py
2 2010 − 10 − 22 GAJI 11 − 2010 3000000 3000000
3 2010 − 10 − 22 BON − 200000 2800000
BAB 9. LINTAS SISTEM 87

Cermati baik-baik konsepnya. Juga perhatikan tipe data di tionary dan list
yang digunakan sebagai nilai keluaran (return value) dari fungsi mutasi.

9.4.1 PHP sebagai XMLRPC Client


Unduh xmlrp .in dari http://phpxmlrp .sour eforge.net. File itu berada di
xmlrp -2.2.2.tar.gz. Carilah. Versi lain sepertinya juga tidak masalah. Lalu
buatlah le lientbank.php.

Listing 9.4: lientbank.php

1 <?php
2 in lude ( ' xmlrp . i n ' ) ;
3 $params = new xmlrp val (
4 array (
5 ' p i d ' => new xmlrp val (1 , ' int ' ) ,
6 ' a w a l ' => new xmlrp val ( ' 20101022 ' ) ,
7 ' a k h i r ' => new xmlrp val ( ' 20101023 ' )
8 ) ,
9 ' stru t '
10 ) ;
11 $ f = new xmlrp msg ( ' m u t a s i ' , array ( $params ) ) ;
12 $ = new xmlrp _ lient( ' / ' , ' 127.0.0.1 ' , 9303) ;
13 $ r = $ −>s e n d ( $ f ) ;
14 $v = $ r −>v a l u e ( ) ;
15 if ( $ r −>f a u l t C o d e ( ) ) {
16 print − $r >f a u l t S t r i n g ( ) ;
17 } else {
18 $ r e s p = $ r >s a l a r v a l ( ) ;
if

19 ( $ r e s p [ ' k o d e ' ℄−> s a l a r v a l ( ) == 0 ) {
20 forea h ( $ r e s p [ ' m u t a s i ' ℄−> s a l a r v a l ( ) as $ i=>$m) {
21 $ f = $m−>s a l a r v a l ( ) ;
22 $ t g l = $ f [0℄ − > s a l a r v a l ( ) ;
23 $ k e t = $ f [0℄ − > s a l a r v a l ( ) ;
24 $ n o m i n a l = $ f [0℄ − > s a l a r v a l ( ) ;
25 $ s a l d o = $ f [0℄ − > s a l a r v a l ( ) ;
26 print $tgl . " ".
27 str_pad ( $ket , 20) . " ".
28 str_pad ( $nominal , 10) . " ".
29 str_pad ( $saldo , 1 0 ) . " \n" ;
30 }
31 } else {
32 print $ r e s p [ ' p e s a n ' ℄−> s a l a r v a l ( ) ;
33 }
34 }
35 ?>
BAB 9. LINTAS SISTEM 88

Karena s ript ini akan kita jalankan sebagai ommand line, maka pasang
dulu paket terkait.

1 $ sudo a p t −g e t install php5− l i

Lalu jalankan.

1 $ php l i e n t _ b a n k . php
2 2010 − 10 − 22 GAJI 11 − 2010 3000000 3000000
3 2010 − 10 − 22 BON − 200000 2800000

9.4.2 Drupal
Drupal
1 juga ditulis dengan PHP. Ia sudah memuat fun tion xmlrp , sehingga
Anda tidak perlu memasang modul tambahan. Cara penulisannya juga lebih
mudah. Contoh berikut ini untuk Drupal 6.
Buatlah le sites/all/modules/pegawai/pegawai.module berikut.

Listing 9.5: pegawai.module

1 <?php
2 fun tion pegawai_menu ( ) {
3 $items = array () ;
4 $ i t e m s [ ' p e g a w a i / t r x /%/%/% ' ℄ = array (
5 ' t i t l e ' => ' Transaksi ' ,
6 ' page a l l b a k ' => ' pegawai_trx ' ,
7 ' page a r g u m e n t s ' => array (2 , 3, 4) ,
8 ' a ess a l l b a k ' => ' user_a ess ' ,
9 ' t y p e ' => MENU_CALLBACK,
10 ) ;
11 return $items ;
12 }
13
14 fun tion pegawai_trx ( $pid , $awal , $akhir ) {
15 $url = ' http : / / 1 2 7 . 0 . 0 . 1 : 9 3 0 3 ' ;
16 $p = array ( ' p i d ' => intval ( $pid ) ,
17 ' a w a l ' => $ a w a l ,
18 ' a k h i r ' => $ a k h i r ) ;
19 $r = xmlrp ( $url , ' mutasi ' , $p ) ;
20 if ( ! $r [ ' mutasi ' ℄ ) {
21 return drupal_set_message ( ' Tidak ada data ' ) ;
22 }
23 $ = '<t a b l e ><th>T a n g g a l </th><th>K e t e r a n g a n</th> ' .
24 '<th>Nominal</th><th>S a l d o </th ></t r > ' ;
25 forea h ( $r [ ' mutasi ' ℄ as $ i=>$ f ) {
26 $tgl = $f [ 0 ℄ ;

1 http://drupal.org
BAB 9. LINTAS SISTEM 89

27 $ket = $f [ 1 ℄ ;
28 $nominal = $ f [ 2 ℄ ;
29 $saldo = $f [ 3 ℄ ;
30 $ .= '<t r ><td> ' . $ t g l . ' </td> ' ;
31 $ .= '<td> ' . $ k e t . ' </td> ' ;
32 $ .= '<t d a l i g n =" r i g h t "> ' . format_number ( $ n o m i n a l ) .
' </td> ' ;
33 $ .= '<t d a l i g n =" r i g h t "> ' . format_number ( $ s a l d o ) . '
</td> ' ;
34 $ .= ' </ t r > ' ;
35 }
36 return $ ;
37 }
38 ?>

Juga buat sites/all/modules/pegawai/pegawai.info.

Listing 9.6: pegawai.info

1 name = P e g a w a i
2 d e s r i p t i o n = Data pegawai
3 ore = 6. x
4 v e r s i o n = " 6 . x −1.0"

Setelah login di browser, masuklah ke menu admin/build/modules. Centang


modul pegawai dan klik Save. Lalu masukkan URL di browser seperti

pegawai/trx/1/20101022/20101023
Bab 10

Pengemasan

10.1 Paket Debian

Pada bab sebelumnya kita sudah membuat modul uang.py. Agar modul ini dap-
at digunakan oleh user lainnya maka diletakkanlah di direktori /usr/lo al/lib/python2.6/dist-
pa kages. Proses opy modul seperti ini memang sudah mudah, tapi ada lagi
yang lebih memudahkan, yaitu dengan mengemasnya dalam bentuk paket De-
bian.
Langkah kemudahan yang dimaksud adalah:

1. Tambahkan URL daftar paket dalam sebuah le /et /apt/sour es.list.d/ ustom.list
yang berisi
deb http://192.168.0.1/deb ./

2. Perbaharui daftar paket


$ sudo apt-get update

3. Pasang paket dimaksud


$ sudo apt-get install python-uang

Manfaat lain pemaketan adalah mudahnya pemasangan paket lainnya yang


dibutuhkan oleh paket utama, sering disebut sebagai dependen ies . Misalkan
paket python-uang tadi membutuhkan python-sqlal hemy, maka pada saat

1 $ sudo a p t −g e t install python −uang

otomatis python-sqlal hemy juga ikut dipasang.

Penamaan python-uang dimana ada awalan python- dikarenakan


uang.py adalah modul Python yang umum. Dengan kata lain bisa
digunakan di aplikasi apa saja. Tidak ada koneksi database di
sana. Juga tidak ada perintah akses database seperti SELECT dkk.
Awalan ini juga meniru dari paket umum lainnya seperti python-
sqlal hemy, python-psy opg2, python-serial, dst.

90
BAB 10. PENGEMASAN 91

Mulailah membuat direktori kerja, yaitu /usr/lo al/sr /python-uang.

1 $ sudo mkdir −p / u s r / l o a l / s r / python −uang /DEBIAN

Perintah ini otomatis membuat dua buah direktori yaitu

1. /usr/lo al/sr /python-uang

2. /usr/lo al/sr /python-uang/DEBIAN

Direktori DEBIAN digunakan untuk meletakkan le-le yang berkaitan dengan


sistem paket seperti

ontrol berisi informasi seputar paket.

postinst s ript yang dijalankan saat pemasangan berlangsung, yaitu saat apt-
get install atau dpkg -i. S ript ini harus exe utable yang bisa diset dengan
hmod 755.

prerm s ript yang dijalankan saat penghapusan berlangsung, yaitu saat apt-
get remove atau dpkg -r. S ript ini juga harus exe utable.

onles berisi daftar nama le kongurasi yang digunakan paket ini. Misalnya
berisi /et /uang. onf. File kongurasi ini berisi format negara yang di-
gunakan oleh fungsi uang(). Jadi tidak hard- ode menggunakan lo ale
id_ID.UTF-8. Dengan begitu python-uang semakin umum (general).
Dengan didaftarkannya /et /uang. onf di dalam onles, maka terhin-
dar dari penibanan (timpa / overwrite) saat upgrade berlangsung. Mis-
alkan kini python-uang versi 0.1. Kemudian dibuatlah versi 0.2 yang juga
memuat /et /uang. onf. Jika di dalam versi 0.2 tidak ada perubahan
apa-apa pada /et /uang. onf maka apt-get install tidak akan melakukan
timpa pada /et /uang. onf yang sudah terpasang . Karena siapa tahu
Anda sudah mengganti isi /et /uang. onf terpasang dengan de_DE.ISO-
8859-1. Dengan begitu kita terhindar dari mengubah ulang kongurasi.
Mudah-mudahan paham maksudnya.

Mulailah membuat le python-uang/DEBIAN/ ontrol.

Listing 10.1: DEBIAN/ ontrol

1 Pa kage : python −uang


2 Priority : optional
3 Se tion : python
4 Maintainer : Owo S u g i a n a <s u g i a n a  r a b . o . i d >
5 Ar hite ture : all
6 Version : 0.1
7 Depends : python − e n t r a l (>= 0.6.7)
8 Python− V e r s i o n : all
9 Des ription : Format uang

Lanjutkan dengan membuat direktori modulnya.


BAB 10. PENGEMASAN 92

1 $ d / usr/ l o a l / sr
2 $ sudo mkdir −p python −uang / u s r / s h a r e / p y e n t r a l / python −
uang / s i t e −p a k a g e s
Perhatikanlah direktori setelah /usr/lo al/sr /python-uang. Semua direk-
tori tersebut nantinya akan dipasang di root dire tory ( / ), ke uali direktori
DEBIAN.
Lalu mengapa menggunakan /usr/share ? Padahal sebelumnya kita mele-
takkan uang.py di /usr/lo al ? Direktori /usr/lo al yang kita gunakan sebelum-
nya bermakna bahwa uang.py belum menjadi bagian dari paket Debian. Bila
sudah menjadi bagian dari paket Debian, maka diletakkan di /usr/share. Begi-
tulah ketentuan umumnya.

1 $ sudo p / u s r / l o a l / l i b / p y t h o n 2 . 6 / d i s t −p a k a g e s / uang . py
python −uang / u s r / s h a r e / p y e n t r a l / python −uang / s i t e −
pa kages/

Karena akan menggunakan /et /user. onf, lakukan perubahan pada uang.py
menjadi berikut ini.

Listing 10.2: usr/share/py entral/python-uang/site-pa kages/uang.py

1 import lo ale
2 from ConfigParser import ConfigParser
3
4 onf = ConfigParser ()
5 o n f . r e a d ( ' / e t / uang . o n f ' )
6
7 l o a l e . s e t l o a l e ( l o a l e . LC_ALL, onf . get ( ' default ' , '
lo ale '))
8
9 DECIMAL = o n f . g e t i n t ( ' d e f a u l t ' , ' d e i m a l ' )
10
11
12 def uang ( n i l a i , p e a h a n=None ) :
13 if pe ahan is None :
14 if t y p e ( n i l a i ) == t y p e ( 0 ) :
15 pe ahan = 0
16 else :
17 p e a h a n = DECIMAL
18 return l o a l e . f o r m a t ( '%%.%d f ' % p e a h a n , nilai , True )
19
20
21 if __name__ == '__main__ ' :
22 n = 10000.5
23 print uang ( n )
24 print uang ( i n t ( n ) )
25 print uang ( n , 3 )
BAB 10. PENGEMASAN 93

Buat direktori et .

1 $ sudo mkdir −p python −uang / e t

Selanjutnya buat python-uang/et /uang. onf.

Listing 10.3: et /uang. onf

1 [ default ℄
2 l o a l e = id_ID . UTF−8
3 de imal = 2

Lalu buat python-uang/DEBIAN/ onles berisi satu baris berikut.

Listing 10.4: DEBIAN/ onles

1 / e t / uang . o n f

Kemudian buat python-uang/DEBIAN/postinst yang berisi perintah untuk


mendaftarkan uang.py agar dikenal sebagai modul.

Listing 10.5: DEBIAN/postinst

1 #!/ b i n / s h
2 py entral pkginstall python −uang

Juga python-uang/DEBIAN/prerm.

Listing 10.6: DEBIAN/prerm

1 #!/ b i n / s h
2 py entral pkgremove python −uang

Buat keduanya exe utable.

1 $ sudo hmod 7 5 5 python −uang /DEBIAN/ p o s t i n s t


2 $ sudo hmod 7 5 5 python −uang /DEBIAN/ prerm

Pastikan semua le dimiliki root.

1 $ sudo hown −R root . root python −uang

Lihat lagi apa yang sudah dibuat.

1 $ find python −uang


2 python −uang /
3 python −uang /DEBIAN
4 python −uang /DEBIAN/ o n t r o l
5 python −uang /DEBIAN/ prerm
6 python −uang /DEBIAN/ o n f f i l e s
7 python −uang /DEBIAN/ p o s t i n s t
8 python −uang / u s r
9 python −uang / u s r / s h a r e
10 python −uang / u s r / s h a r e / p y e n t r a l
11 python −uang / u s r / s h a r e / p y e n t r a l / python −uang
12 python −uang / u s r / s h a r e / p y e n t r a l / python −uang / s i t e −p a k a g e s
BAB 10. PENGEMASAN 94

13 python −uang / u s r / s h a r e / p y e n t r a l / python −uang / s i t e −p a k a g e s


/ uang . py
14 python −uang / e t
15 python −uang / e t / uang . o n f

Kemas.

1 $ sudo dpkg−deb −− b u i l d python −uang .


2 dpkg−deb : peringatan : ' python −uang /DEBIAN/ o n t r o l '
ontains u s e r −d e f i n e d field ' Python−V e r s i o n '
3 dpkg−deb : membuat paket ` python −uang ' di dalam ` . / python −
uang_0 . 1 _ a l l . deb ' .
4 dpkg−deb : peringatan : ignoring 1 warnings about the
ontrol file (s)

Perhatikan ada titik diakhirnya yang berarti letakkan di urrent dire tory.
Abaikan saja peringatan itu. Karena Python-Version memang bukan standar
Debian, tapi digunakan oleh py entral. Sampai di sini pembuatan paket selesai.
Kini telah terbentuk python-uang_0.1_all.deb yang siap dipasang.

1 $ sudo dpkg −i python −uang_0 . 1 _ a l l . deb


2 Memilih paket python −uang yang sebelumnya tidak dipilih .
3 ( S e d a n g memba a basis data ...213458 berkas dan direktori
telah terpasang . )
4 S e d a n g membuka paket python −uang ( dari python −uang_0 . 1
_ a l l . deb ) ...
5 Sedang menyetel python −uang (0.1) ...
6 Pro essing triggers for python − e n t r a l ...

Untuk menghindari keran uan karena ada dua modul uang yang terpasang,
sebaiknya buang yang ada di /usr/lo al.

1 $ s u d o mv / u s r / l o a l / l i b / p y t h o n 2 . 6 / d i s t −p a k a g e s / uang . py
/tmp

Lalu ujilah di modus interaktif.

1 $ python
2 Python 2.6.5 ( r265 : 7 9 0 6 3 , Apr 16 2010 , 13:09:56)
3 [GCC 4 . 4 . 3 ℄ on linux2
4 Type " help " , " opyright " , " redits" or " li ense " for more
information .
5 >>> f r o m uang import uang
6 >>> uang ( 1 0 0 0 0 )
7 '10.000 '

Ujian terakhir hapuslah paket ini untuk memastikan s ript DEBIAN/prerm


berfungsi dengan baik.

1 $ sudo a p t −g e t remove python −uang


2 S e d a n g memba a daftar paket . . . Selesai
BAB 10. PENGEMASAN 95

3 Membangun pohon ketergantungan


4 Memba a informasi yang tersedia . . . Selesai
5 Paket berikut akan DIHAPUS :
6 python −uang
7 0 dimutakhirkan , 0 baru terinstal , 1 akan dihapus dan 192
tidak akan dimutakhirkan .
8 Setelah operasi ini , 0B r u a n g kosong harddisk akan
digunakan .
9 Anda ingin melanjutkan [ Y/ t ℄ ?
10 ( S e d a n g memba a basis data ...213460 berkas dan direktori
telah terpasang . )
11 S e d a n g membuang python −uang ...

10.2 Debian Repository

Kini saatnya membuat repository agar bisa di-apt-get dari komputer lain. Pasanglah
paket yang dibutuhkan untuk memba a le-le *.deb.

1 $ sudo a p t −g e t install dpkg−d e v

Letakkan paketnya di tempat yang sudah ditentukan web server Apa he.

1 $ sudo mkdir / v a r /www/ deb


2 $ sudo p / u s r / l o a l / s r / python −uang_0 . 1 _ a l l . deb / v a r /www
/ deb

Lalu buatlah /var/www/deb/update-list.sh. File ini digunakan untuk mem-


perbaharui daftar paket yang tersedia.

Listing 10.7: updatelist.sh

1 rm −f Pa kages . gz
2 dpkg−s a n p a k a g e s −−a r h all . >/d e v / n u l l > P a k a g e s
3 gzip −− b e s t Pa kages

Setiap ada paket baru jalankan le ini.

1 $ d / v a r /www/ deb
2 $ sudo sh u p d a t e l i s t . sh

Akan terbentuk le Pa kages.gz. File inilah yang akan diba a saat apt-get
update.
Selanjutnya kita uji repository ini dengan membuat le /et /apt/sour es.list.d/ ustom.list.

Listing 10.8: /et /apt/sour es.list.d/ ustom.list

1 deb h t t p : / / 1 9 2 . 1 6 8 . 0 . 1 / deb ./

Perbaharui daftar paket.

1 $ sudo a p t −g e t update
BAB 10. PENGEMASAN 96

Pasang paket yang dimaksud.

1 $ sudo a p t −g e t install python −uang

10.3 Remastering Ubuntu

Untuk semakin memudahkan pemasangan, ada baiknya pasang paket-paket


yang dimaksud ke dalam sebuah le ISO. Bukan hanya memasang, bahkan An-
da bisa mengkongurasi se ara manual untuk memastikan pemasangan Linux
Ubuntu dan aplikasi yang dimaksud berlangsung lan ar dan mudah .
Mulailah pasang paket yang dibutuhkan.

1 $ sudo a p t −g e t install s q u a s h f s −t o o l s mkisofs

Buat le onf.

Listing 10.9: remaster/ onf

1 SOURCE=" /home/ s u g i a n a /Unduhan/ b l a n k o n − 6.0 − d l i v e − i 3 8 6 . i s o


"
2 TARGET=" b l a n k o n − 6.0 − d l i v e −s o h o − i 3 8 6 . i s o "
3 LABEL=" BlankOn 6 SOHO"

Sesuaikanlah ketiganya. Kemudian buat le 1-extra t.sh:

Listing 10.10: remaster/1-extra t.sh

1 . ./ onf
2 mkdir −p /tmp / drom /tmp / r o o t
3 mount −o l o o p $SOURCE /tmp / drom
4 rsyn −− e x l u d e ' f i l e s y s t e m . s q u a s h f s ' −a /tmp / drom /
drom /
5 mount −o loop −t squashfs /tmp / drom / a s p e r / f i l e s y s t e m .
squashfs /tmp / r o o t
6 p −a /tmp / r o o t .
7 umount /tmp / r o o t
8 umount /tmp / drom

Lalu buat le 2- hroot.sh.

Listing 10.11: remaster/2- hroot.sh

1 p / et / r e s o l v . onf root / et
2 hroot root mount −t pro none / pro
3 hroot root mount −t sysfs none /sys
4 hroot root
5 rm −f root / et / r e s o l v . onf
6 hroot root a p t −g e t lean
7 hroot root umount sys
8 hroot root umount pro
BAB 10. PENGEMASAN 97

9 hroot root rm −r f /tmp / * / root / . bash_history


10 rm −r f drom / p r o g r a m s
11 hmod +w drom / a s p e r / f i l e s y s t e m . m a n i f e s t
12 hroot root dpkg−q u e r y −W −−s h o w f o r m a t = ' $ { P a k a g e } ${
V e r s i o n } \n ' > drom / a s p e r / f i l e s y s t e m . m a n i f e s t
13 p drom / a s p e r / f i l e s y s t e m . m a n i f e s t drom / a s p e r /
f i l e s y s t e m . m a n i f e s t −d e s k t o p
14 sed − ie ' / u b i q u i t y /d ' drom / a s p e r / f i l e s y s t e m . m a n i f e s t −
desktop

Terakhir buat le 3-pa k.sh.

Listing 10.12: remaster/3-pa k.sh

1 . ./ onf
2 rm −f drom / a s p e r / f i l e s y s t e m . s q u a s h f s
3 awal=` date `
4 mksquashfs root drom / a s p e r / f i l e s y s t e m . s q u a s h f s
5 d drom
6 find . − t y p e f − p r i n t 0 | x a r g s −0 md5sum > md5sum . t x t
7 mkisofs − r −V " $ {LABEL} " − a h e − i n o d e s −J − l −b i s o l i n u x /
i s o l i n u x . b i n − i s o l i n u x / b o o t . at
−no−emul−b o o t −b o o t −
l o a d − s i z e 4 −b o o t − i n f o − t a b l e −o . . / $TARGET .
8 e ho " Awal $awal "
9 e ho " Akhir " ` date `
10 e ho " Sour e " ` ls −l $SOURCE | awk '{ print $5 } ' `
11 e ho " Target " ` ls −l . . / $TARGET | awk '{ print $5 } ' `

Jalankan s ript pertama.

1 $ sudo s h 1− e x t r a t . s h

Dia akan mengekstrak le iso menjadi root dire tory. Kemudian jalankan
s ript kedua:

1 $ sudo s h 2− h r o o t . s h

S ript ini untuk masuk ke sistem Linux yang lain, yaitu root dire tory tadi.

1 r o o t  l a p t o p :/#

Di sini Anda bisa melakukan perubahan sebagaimana biasa. Contoh:

1 r o o t  l a p t o p :/# d / e t / apt / s o u r e s . l i s t . d
2 r o o t  l a p t o p :/# wget http : / / debian . rab . o . i d / rab . l i s t
3 r o o t  l a p t o p :/# a p t −g e t update
4 r o o t  l a p t o p :/# a p t −g e t install internet −s h a r i n g dh p3−
server squid vim

Kalau sudah selesai keluarlah dari hroot dengan menekan Ctrl-D atau ketik
exit:
BAB 10. PENGEMASAN 98

1 r o o t  l a p t o p :/# exit
2 exit
3 sugianalaptop :~ $

Root dire tory kini telah berisi aplikasi yang dibutuhkan. Saatnya membuat
iso dengan menjalankan s ript ketiga.

1 $ s u d o 3− p a k . s h

Tunggu sekitar 5 menit.

1 Parallel mksquashfs : Using 2 pro essors


2 Creating 4.0 filesystem on drom / a s p e r / f i l e s y s t e m .
squashfs , blo k size 131072.
3 [==========================| ℄ 15063/84258 17%

Terakhir s ript akan memberikan informasi ukuran iso yang dihasilkan berikut
iso aslinya.

1 357433 extents written ( 6 9 8 MB)


2 Awal Sen Agu 2 0 9 : 4 5 : 3 9 WIT 2 0 1 0
3 Akhir Sen Agu 2 0 9 : 5 0 : 5 2 WIT 2 0 1 0
4 Sour e 731869184
5 Target 732022784

Jika media yang Anda tuju nanti adalah CDROM, pastikan ukurannya
dibawah 700MB. Lebih mudahnya bandingkan dengan ukuran ISO aslinya. Pa-
da ontoh di atas terlihat ukuran Target masih lebih besar dari Sour e. Jika
masih terlalu besar jalankan lagi s ript kedua untuk menghapus paket yang tak
perlu.

1 $ sudo s h 2− h r o o t . s h

Setelah selesai jalankan lagi s ript ketiga:

1 $ sudo s h 3− p a k . s h

File ISO yang dihasilkan bisa Anda oba terlebih dahulu di VirtualBox .
1
Anda juga bisa memasangnya di ashdisk menggunakan usb- reator-gtk. Jika
sudah yakin barulah membakarnya (burn) ke CD-ROM.

1 virtualbox.org
Bab 11

Graphi al User Interfa e


Bab-bab sebelumnya kita mempelajari bagaimana membuat aplikasi dalam lingkun-
gan teks (text mode), beberapa menyebutnya lingkungan konsole. Contohnya
fungsi raw_input() yang meminta masukan user dari konsole. Lingkungan yang
dimaksud ber irikan tidak membutuhkan mouse, ukup dengan keyboard saja
sebagai alat masukan (input devi e).
Kali ini kita masuk pemrograman berbasis gras dimana mouse bisa digu-
nakan sebagai alat masukan untuk klik tombol, opy paste, dsb. Graphi al Uset
Interfa e (GUI) tidaklah wajib di Python, ia hanya sebagai modul. Berbeda
dengan Visual Basi atau Borland Delphi yang mewajibkan GUI.
Modul berbasis GUI tidak hanya satu di Python, ada Qt, Wx, GTk, T l, dst.
Di sini kita akan membahas Qt sebagai pustaka antarmuka gras. Pasanglah
paketnya.

1 $ sudo a p t −g e t install python −q t 4

Juga dokumentasinya, meski tidak wajib.

1 $ sudo a p t −g e t install q t 4 −do −h t m l

Seperti biasa, mulailah dari yang sederhana, yaitu membuat aplikasi Hello
world dalam le hello.py.

Listing 11.1: hello.py

1 import sys
2 from PyQt4 import Qt
3 from PyQt4 . QtGui import *
4
5 lass FormUtama ( QMainWindow) :
6 def __init__ ( s e l f ) :
7 QMainWindow . __init__ ( s e l f )
8 s e l f . setWindowTitle ( ' Hello world ' )
9
10

99
BAB 11. GRAPHICAL USER INTERFACE 100

Gambar 11.1: Hello world

11 app = Qt . Q A p p l i a t i o n ( s y s . a r g v )
12 fm = FormUtama ( )
13 fm . show ( )
14 #app . exe _ ( )
Butuh tampilan penuh ? Gantilah

fm.show()

menjadi

fm.showMaximized()

11.1 Orientasi Objek

Di sini teknik pemrograman semakin terstruktur dimana pemrograman beror-


ientasi objek (Obje t Oriented Programming / OOP) diterapkan. Mari kita
rin i lagi pembahasan sour e hello.py tersebut.
Class bisa dianggap sebuah tipe data, disejajarkan dengan tipe string, inte-
ger, oat, list, di tionary, datetime, dst. Dengan demikian FormUtama meru-
pakan tipe data. Perhatikan baris 5

lass FormUtama(QMainWindow):

itu artinya FormUtama merupakan turunan (inheritan e) dari lass QMain-


Window. Itu artinya variabel dan fungsi yang dimiliki lass QMainWindow
juga dimiliki oleh lass FormUtama. Bahasa lainnya FormUtama mewarisi sifat
QMainWindow.
Selanjutnya ada fungsi __init__(). Fungsi ini merupakan fungsi khusus
yang dijalankan saat pembentukan sehingga disebut sebagai onstru tor. Saat
pembentukan ? Ya, perhatikan baris 12

fm = FormUtama()

Itu adalah pembentukan variabel fm yang bertipe FormUtama. Disinilah fungsi


__init__() dipanggil.
BAB 11. GRAPHICAL USER INTERFACE 101

Dalam istilah OOP, fm disebut sebagai instan e atau variabel bertipe


lass. Namun di Python rasanya semua tipe data adalah lass. Mis-
alnya tipe string. Ia tidak hanya memuat data seperti 'ab d' saja,
melainkan juga memuat fungsi seperti repla e(), rjust(), dst. Hal ini
bisa dibuktikan dengan print dir('ab d'). Sehingga boleh dikatakan
di Python semua variabel adalah objek. Bagi programmer PHP An-
da bisa ermati bahwa string 'ab d' hanya sekedar data.

Sekarang perhatikan baris 7

QMainWindow.__init__(self)

Fungsi __init__() yang dimiliki QMainWindow perlu dipanggil lagi. Mengapa


? Karena FormUtama mendenisikan ulang fungsi __init__().
Lalu apa itu self ? self adalah variabel yang mewakili FormUtama itu sendiri.
Setiap fungsi yang dimiliki oleh suatu lass setidaknya memiliki satu masukan
(input parameter) yaitu self.
Selanjutnya lihat baris 13

fm.show()

dimana kita tidak pernah mendenisikan fungsi show() di dalam lass FormU-
tama. Kenyataannya variabel fm memiliki fungsi show(). Darimana ia berasal
? Seperti dijelaskan tadi, FormUtama mewarisi sifat QMainWindow, jadi fungsi
show() itu berasal darinya. Fungsi ini digunakan untuk menampilkan form.
Lalu apa itu form ? Kotak Hello world itulah yang disebut form seperti pada
gambar 11.1.
Sekarang lihat baris 11

app = Qt.QAppli ation(sys.argv)

dimana QAppli ation dibutuhkan untuk loop. Loop yang dimaksud adalah baris
terakhir

app.exe _()

tanpa loop, alur langsung berakhir. Form bisa banyak, tapi QAppli ation ukup
satu saja.
Pahami lagi baik-baik konsep OOP ini agar semakin mudah untuk membuat
aplikasi yang lebih besar.

11.2 Daftar Pegawai

Mari kita buat form yang lebih lengkap. Form ini untuk memasukkan data
pegawai, terinspirasi dari tabel pegawai yang pernah kita buat. Namun disini
belum menggunakan database, semuanya tersimpan sementara saja.
BAB 11. GRAPHICAL USER INTERFACE 102

Listing 11.2: gui/pegawai.py

1 import sys
2 from PyQt4 import Qt
3 from PyQt4 . QtGui import *
4 from PyQt4 . QtCore import QDate , SIGNAL
5
6 lass FormUtama ( QMainWindow) :
7 def __init__ ( s e l f ) :
8 QMainWindow . __init__ ( s e l f )
9 s e l f . s e t W i n d o w T i t l e ( ' Pegawai ' )
10 s e l f . r e s i z e (550 ,550)
11 s e l f . l a b e l N a m a = QLabel ( s e l f )
12 s e l f . l a b e l A l a m a t = QLabel ( s e l f )
13 s e l f . l a b e l T g l L a h i r = QLabel ( s e l f )
14 sel f . labelJenis = QLabel ( s e l f )
15 s e l f . editNama = Q L i n e E d i t ( s e l f )
16 s e l f . e d i t A l a m a t = QTextEdit ( s e l f )
17 s e l f . e d i t T g l L a h i r = QDateEdit ( s e l f )
18 s e l f . e d i t J e n i s = QComboBox ( s e l f )
19 s e l f . b u t t o n S i m p a n = QPushButton ( s e l f )
20 s e l f . listPegawai = QTableWidget ( s e l f )
21 s e l f . l a b e l N a m a . s e t T e x t ( ' Nama ' )
22 s e l f . l a b e l A l a m a t . s e t T e x t ( ' Alamat ' )
23 s e l f . l a b e l T g l L a h i r . s e t T e x t ( ' Tgl Lahir ' )
24 s e l f . l a b e l J e n i s . setText ( ' Jenis Kelamin ' )
25 s e l f . e d i t T g l L a h i r . s e t D i s p l a y F o r m a t ( ' dd−MM−yyyy ' )
26 s e l f . e d i t T g l L a h i r . s e t D a t e ( QDate ( 2 0 1 0 , 1 0 , 2 3 ) )
27 s e l f . e d i t J e n i s . a d d I t e m s ( [ ' P r i a ' , ' Wanita ' ℄ )
28 s e l f . b u t t o n S i m p a n . s e t T e x t ( ' Simpan ' )
29 s e l f . l i s t P e g a w a i . setColumnCount ( 5 )
30 s e l f . listPegawai . setHorizontalHeaderLabels ( [
31 ' ID ' , ' Nama ' , ' Alamat ' , ' T g l L a h i r ' , ' Kelamin ' ℄ )
32 s e l f . l i s t P e g a w a i . setColumnWidth ( 0 , 2 0 )
33 s e l f . l i s t P e g a w a i . setColumnWidth ( 1 , 1 5 0 )
34 s e l f . editNama . r e s i z e ( 2 0 0 , 3 0 )
35 s e l f . editAlamat . r e s i z e (200 ,100)
36 s e l f . listPegawai . r e s i z e (500 ,200)
37 s e l f . l a b e l N a m a . move ( 1 0 , 1 0 )
38 s e l f . l a b e l A l a m a t . move ( 1 0 , 4 0 )
39 s e l f . l a b e l T g l L a h i r . move ( 1 0 , 1 4 0 )
40 s e l f . l a b e l J e n i s . move ( 1 0 , 1 7 0 )
41 s e l f . editNama . move ( 1 0 0 , 1 0 )
42 s e l f . e d i t A l a m a t . move ( 1 0 0 , 4 0 )
43 s e l f . e d i t T g l L a h i r . move ( 1 0 0 , 1 4 0 )
44 s e l f . e d i t J e n i s . move ( 1 0 0 , 1 7 0 )
BAB 11. GRAPHICAL USER INTERFACE 103

45 s e l f . b u t t o n S i m p a n . move ( 1 0 0 , 2 0 0 )
46 s e l f . l i s t P e g a w a i . move ( 1 0 , 3 0 0 )
47 s e l f . o n n e t ( s e l f . buttonSimpan , SIGNAL ( ' l i k e d ( )
') , s e l f . simpan )
48
49 def simpan ( s e l f ) :
50 row = s e l f . l i s t P e g a w a i . rowCount ( )
51 p i d = row+1
52 s e l f . l i s t P e g a w a i . setRowCount ( p i d )
53 s e l f . l i s t P e g a w a i . s e t I t e m ( row , 0 , QTableWidgetItem (
s t r ( pid ) ) )
54 s e l f . l i s t P e g a w a i . s e t I t e m ( row , 1 , QTableWidgetItem (
s e l f . editNama . t e x t ( ) ) )
55 s e l f . l i s t P e g a w a i . s e t I t e m ( row , 2 , QTableWidgetItem (
s e l f . editAlamat . toPlainText ( ) ) )
56 s e l f . l i s t P e g a w a i . s e t I t e m ( row , 3 , QTableWidgetItem (
s e l f . editTglLahir . text () ) )
57 s e l f . l i s t P e g a w a i . s e t I t e m ( row , 4 , QTableWidgetItem (
s e l f . e d i t J e n i s . urrentText ( ) ) )
58 s e l f . editNama . l e a r ( )
59 s e l f . editAlamat . l e a r ( )
60 s e l f . e d i t J e n i s . setCurrentIndex (0)
61 s e l f . editNama . s e t F o u s ( )
62
63
64 app = Qt . Q A p p l i a t i o n ( s y s . a r g v )
65 fm = FormUtama ( )
66 fm . show ( )
67 app . exe _ ( )

Bagaimana, panjang bukan ?


Ya, ontoh kali ini menyertakan lass yang kerap digunakan. Berikut ini
ulasan masing-masing lass tersebut.

QLabel Menampilkan tulisan saja, tidak bisa diedit user.

QLineEdit Untuk memasukkan tulisan, satu baris saja.

QTextEdit Untuk memasukkan tulisan juga, tapi bisa lebih dari satu baris.

QDateEdit Untuk mengisi tanggal.

QComboBox Untuk menetapkan pilihan.

QPushButton Tombol yang bila di-klik menjalankan suatu fungsi. Dalam hal
ini menyimpan data pegawai ke QTableWidget yang ada di bawahnya.

QTableWidget Menampilkan data berbentuk tabel.


BAB 11. GRAPHICAL USER INTERFACE 104

Gambar 11.2: Daftar Pegawai


BAB 11. GRAPHICAL USER INTERFACE 105

Dari sour e tersebut dan menganalisa tampilan form, rasanya Anda bisa mema-
hami ara penggunaan lass di atas.

Untuk mengetahui lass lainnya beserta fungsi yang ada di dalam-


nya Anda bisa lihat di /usr/share/qt4/do /html/ lasses.html. Gu-
nakanlah browser untuk melihatnya.
Bab 12

Obje t Oriented
Programming
Kita membuat fungsi dengan tujuan esiensi sour e, agar proses-proses yang
sama dapat diwakili dengan memanggil fungsi tertentu. Begitu juga pada pem-
buatan objek. Mari mulai pada kasus.
Ada sebuah le teks bernama barang.txt dengan isi seperti berikut ini.

Listing 12.1: barang.txt

1 1 Jeruk 34 9000
2 2 Mangga 8000
3 3 Pisang 7 10000

Pembuat le itu memastikan data barang tersimpan dengan lebar kolom
tetap . Kolom kode barang 3 karakter, nama barang 10 karakter, stok 2 karak-
ter, dan harga barang 8 karakter atau sisanya. Anda diminta memindahkan
data ini ke sebuah tabel di database. Mari mulai mempertimbangkan langkah-
langkah yang bisa ditempuh.
Andai saja kita bisa menggunakan split() yang bisa mengubah string menjadi
list, sehingga dengan mudah kolom pertama ada kode barang, kolom kedua
nama barang, dan seterusnya. Sayang sekali hal ini tidak dapat dilakukan.
Mengapa ?
Perhatikan baris Mangga dimana nilai stok kosong. Ini artinya kolom ketiga
menjadi harga barang. Tentu saja tidak konsisten dengan baris Jeruk dimana
kolom ketiga adalah stok. Idealnya pembuat le itu mengubah programnya
agar kalau stok kosong diberi angka 0. Namun posisi kita sedang tidak bisa
memaksa.
Baik, kita ikuti saja petunjuk pembuatnya dimana lebar kolom menjadi
a uan. Sementara ini kita tidak perlu terlalu jauh bagaimana struktur tabelnya.
Dari sudut pandang Python saja dulu, tipe data apa yang o ok untuk mewakili
le ini. Untuk sementara anggap saja tipe data list yang sesuai karena ini
merupakan bentuk tabel.

106
BAB 12. OBJECT ORIENTED PROGRAMMING 107

Mulailah membuat s ript barang1.py.

Listing 12.2: barang1.py

1 import sys
2
3 f i l e n a m e = sys . argv [ 1 ℄
4 f = open ( f i l e n a m e )
5 for line in f . readlines () :
6 kode = l i n e [ : 3 ℄ . s t r i p ( )
7 nama = l i n e [ 3 : 3 + 1 0 ℄ . s t r i p ( )
8 stok = l i n e [3+10:3+10+2℄. s t r i p ( )
9 harga = l i n e [3+10+2:℄. s t r i p ( )
10 print [ kode , nama , stok , harga ℄
11 f . lose ()

Jalankan.

1 $ python b a r a n g 1 . py barang . t x t
2 [ '1 ' , ' Jeruk ' , '34 ' , '9000 '℄
3 [ '2 ' , ' Mangga ' , ' ' , '8000 '℄
4 [ '3 ' , ' Pisang ' , '7 ' , '10000 '℄

Tahap ini sudah baik, dimana setiap nilai sudah dapat diwakili dalam vari-
abel kode, nama, stok, dan harga. Namun barang1.py masih kurang modular
karena masukannya berupa nama le yang diberikan melalui ommand line.

12.1 Lebih Terstruktur

Kita perlu meningkatkan kadar modularitas dengan membuat fungsi. Buatlah


barang2.py berikut.

Listing 12.3: barang2.py

1 def barang ( f i l e n a m e ) :
2 f = open ( f i l e n a m e )
3 rows = [℄
4 for line in f . readlines () :
5 kode = l i n e [ : 3 ℄ . s t r i p ( )
6 nama = l i n e [ 3 : 3 + 1 0 ℄ . s t r i p ( )
7 stok = l i n e [3+10:3+10+2℄. s t r i p ( )
8 harga = l i n e [3+10+2:℄. s t r i p ( )
9 row = [ kode , nama , s t o k , h a r g a ℄
10 r o w s . append ( row )
11 f . lose ()
12 return rows
13
14
15 if __name__ == '__main__ ' :
BAB 12. OBJECT ORIENTED PROGRAMMING 108

16 import sys
17 f i l e n a m e = sys . argv [ 1 ℄
18 for in
row barang ( f i l e n a m e ) :
19 print row

Jalankan.

1 $ python b a r a n g 2 . py barang . t x t
2 [ '1 ' , ' Jeruk ' , '34 ' , '9000 '℄
3 [ '2 ' , ' Mangga ' , ' ' , '8000 '℄
4 [ '3 ' , ' Pisang ' , '7 ' , '10000 '℄

Hasil tetap sama, namun kini s ript tidak hanya mengandung fungsi tetapi
juga bisa digunakan sebagai modul.

12.2 Lebih Umum

Sekarang aspek generalitas, atau tingkat ke-umum-an fungsi, dimana lebar se-
tiap kolom sudah ditetapkan di dalam fungsi (hard ode). Bisakah ditingkatkan
generalitasnya ?
Kebutuhannya adalah ada le lain selain barang.txt dengan lebar setiap
kolom berbeda dengan barang.txt, namun sifatnya masih sama yaitu setiap
kolom memiliki lebar tertentu . Kalau barang.txt menggunakan lebar kolom
masing-masing 3, 10, 2, dan 8, mungkin pegawai.txt menggunakan 5, 30, 10,
50, dan 20. Jadi bukan hanya lebar kolomnya berbeda, jumlah kolomnya pun
berbeda.
Karena sudah bersifat umum sebaiknya nama fungsi dan nama lenya pun
umum. Buatlah xtable.py berikut.

Listing 12.4: xtable.py

1 def f i x t a b l e ( filename , widths ) :


2 f = open ( f i l e n a m e )
3 rows = [℄
4 for line in f . readlines () :
5 awal = 0
6 row = [℄
7 for width in widths :
8 a k h i r = awal + width
9 field = l i n e [ awal : a k h i r ℄ . s t r i p ( )
10 row . append ( f i e l d )
11 awal = a k h i r
12 r o w s . append ( row )
13 f . lose ()
14 return rows
15
16
17 if __name__ == '__main__ ' :
BAB 12. OBJECT ORIENTED PROGRAMMING 109

18 import sys
19 f i l e n a m e = sys . argv [ 1 ℄
20 for in
row f i x t a b l e ( filename , [3 ,10 ,2 ,8℄) :
21 print row

Jalankan.

1 $ python f i x t a b l e . py barang . t x t
2 [ '1 ' , ' Jeruk ' , '34 ' , '9000 '℄
3 [ '2 ' , ' Mangga ' , ' ' , '8000 '℄
4 [ '3 ' , ' Pisang ' , '7 ' , '10000 '℄

Perhatikan lagi, hasil masih sama. Anda bisa uji dengan membuat pe-
gawai.txt.

Listing 12.5: pegawai.txt

1 1BUMMI DWI PUTERA, ST 1985 − 08 − 17L


2 2ARIEF SETIADI 1972 − 05 − 02L
3 3CECEP ZAHRUDIN , ST 1972 − 06 − 01L
4 4NITA PANDRIA 1976 − 09 − 19P
5 5ILHAM 1984 − 11 − 05L
6 6MIRANDA 1978 − 10 − 01P

Lalu xpegawai.py.

Listing 12.6: xpegawai.py

1 from fixtable import fixtable


2 import sys
3
4 f i l e n a m e = sys . argv [ 1 ℄
5
6 for row in f i x t a b l e ( filename , [2 ,22 ,10 ,1℄) :
7 print row

Jalankan.

1 $ python f i x p e g a w a i . py pegawai . t x t
2 [ '1 ' , 'BUMMI DWI PUTERA, ST ' , '1985 −08 −17 ' , 'L ' ℄
3 [ '2 ' , ' ARIEF SETIADI ' , '1972 −05 −02 ' , 'L ' ℄
4 [ '3 ' , 'CECEP ZAHRUDIN , ST ' , '1972 −06 −01 ' , 'L ' ℄
5 [ '4 ' , ' NITA PANDRIA' , '1976 −09 −19 ' , 'P ' ℄
6 [ '5 ' , 'ILHAM' , '1984 −11 −05 ' , 'L ' ℄
7 [ '6 ' , 'MIRANDA' , '1978 −10 −01 ' , 'P ' ℄

Fungsi xtable teruji.

12.3 Tingkat Kerumitan

Kompleksitas masalah kian bertambah. Kini Anda membutuhkan hasil yang


memperhatikan tipe data . Perhatikan lagi barang.txt dimana:
BAB 12. OBJECT ORIENTED PROGRAMMING 110

ˆ kolom pertama, kode barang, bertipe integer

ˆ kolom kedua, nama barang, bertipe string

ˆ kolom ketiga, stok, bertipe integer

ˆ kolom keempat, harga, bertipe integer

Lalu apa nilai yang o ok untuk stok Mangga yang tidak tertulis apapun alias
string hampa ? Apa tetap diisi sebagai string hampa ? Sebaiknya tidak, karena
kita akan menetapkan eld stok bertipe integer. Maka nilai yang o ok untuk
string hampa adalah None, alias objek hampa. Buatlah le FixTableType.py
berikut ini.

Listing 12.7: FixTableType.py

1 from types import IntType , StringType


2
3
4 def f i x t a b l e ( filename , ftypes ) :
5 f = open ( f i l e n a m e )
6 rows = [℄
7 for line in f . readlines () :
8 awal = 0
9 row = [℄
10 for width , ftype in ftypes :
11 a k h i r = awal + width
12 field = l i n e [ awal : a k h i r ℄ . s t r i p ( )
13 if not field :
14 field = None
15 elif f t y p e == I n t T y p e :
16 field = int ( f i e ld )
17 row . append ( f i e l d )
18 awal = a k h i r
19 r o w s . append ( row )
20 f . lose ()
21 return rows
22
23
24 if __name__ == '__main__ ' :
25 import sys
26 f i l e n a m e = sys . argv [ 1 ℄
27 fields = [
28 [ 3 , IntType ℄ ,
29 [ 1 0 , StringType ℄ ,
30 [ 2 , IntType ℄ ,
31 [ 8 , IntType ℄
32 ℄
BAB 12. OBJECT ORIENTED PROGRAMMING 111

33 for row in f i x t a b l e ( filename , fields ) :


34 print row

Jalankan.

1 $ python F i x T a b l e T y p e . py barang . t x t
2 [1 , ' Jeruk ' , 34 , 9000℄
3 [2 , ' Mangga ' , None , 8000℄
4 [3 , ' Pisang ' , 7, 10000℄

Perhatikan, tidak ada lagi kutip di kolom pertama, ketiga, dan keempat.
Selanjutnya ada kebutuhan untuk menyimpan kembali data tersebut ke se-
buah le sejenis, meski tidak harus ke barang.txt lagi. Fitur semakin bertambah
dimana:

ˆ Tipe integer
Bab 13

Kerja Sampingan
Anda diminta membuat sebuah program yang bertugas mengendalikan sebuah
GSM modem. Program ini bersifat daemon yang artinya selalu berjalan seolah
tanpa akhir. Tugas utamanya adalah mengirim SMS yang berasal dari seluruh
le yang ada di direktori /tmp/job. Hasil pengiriman SMS (berhasil / tidak)
dikirim ke SMS gateway induk melalui XMLRPC, inilah kerja sampingannya
atau sering disebut sebagai multi-thread .
Mengapa kita perlu multi-thread ?
Modem tersebut hanya bisa mengirim sebuah SMS pada satu saat yang
membutuhkan waktu 10 detik. Di sisi lain daemon ini harus mengabari status
pengiriman ke SMS gateway induk melalui XMLRPC yang membutuhkan waktu
5 detik. Bahkan kalau terkena masalah bandwidth XMLRPC lient ini bisa
membutuhkan waktu 60 detik. Bayangkan kalau hanya single-thread.
Saat Thread 1

1 Mengirim SMS 1 selama 10 detik


2 Mengabari status SMS 1 selama 5 detik
3 Mengirim SMS 2 selama 10 detik
4 Mengirim status SMS 2 selama 5 detik
Total waktu yang dibutuhkan untuk mengirim dua SMS adalah 30 detik.
Sekarang bandingkan bila menggunakan multi-thread.
Saat Thread 1 Thread 2

1 Mengirim SMS 1 10 detik


2 Mengirim SMS 2 10 detik Mengabari status SMS 1 5 detik
3 Mengabari status SMS 2 5 detik
Total waktu yang dibutuhkan adalah 10+10+5 = 25 detik, selisih 5 detik
dari single-thread. Bagi SMS gateway itu merupakan jeda yang ukup berarti
mengingat banyaknya SMS yang dikirim.
Mari kita mulai simulasinya dengan membuat test_thread.py.

Listing 13.1: testthread.py

1 from threading import Thread

112
BAB 13. KERJA SAMPINGAN 113

2 import time
3 import os
4 from glob import glob
5
6
7 lass K i r i m ( Thread ) :
8 def __init__ ( s e l f , k) :
9 s e l f . k e r j a = True
10 s e l f . kabar = k
11 Thread . __init__ ( s e l f )
12
13 def run ( s e l f ) :
14 print t i m e . s t r f t i m e ( '%H:%M:%S ' ) , ' Kerja sampingan
dimulai '
15 while s e l f . kerja :
16 time . s l e e p ( 1 )
17 if not s e l f . kabar :
18 ontinue
19 hasil = s e l f . kabar [ 0 ℄
20 del s e l f . kabar [ 0 ℄
21 #s e l f . kabar = s e l f . kabar [ 1 : ℄
22 print '%s KABARI %s ' % ( t i m e . s t r f t i m e ( '%H:%M
:%S ' ) , hasil )
23
24 def join ( sel f ) :
25 print ' Kerja sampingan berakhir '
26 s e l f . kerja = False
27 Thread . j o i n ( s e l f )
28
29
30 job_dir = ' /tmp / j o b '
31 kabar = [℄
32
33 sampingan = Kirim ( kabar )
34 sampingan . s t a r t ( )
35
36 print t i m e . s t r f t i m e ( '%H:%M:%S ' ) , ' Pekerjaan utama dimulai
'
37 while True :
38 time . s l e e p ( 1 )
39 if not os . path . e x i s t s ( job_dir ) :
40 ontinue
41 filenames = g l o b ( '%s / * ' % j o b _ d i r )
42 if not filenames :
43 ontinue
44 filename = filenames [ 0 ℄
BAB 13. KERJA SAMPINGAN 114

45 f = open ( f i l e n a m e )
46 job = f . read ( )
47 f . lose ()
48 o s . remove ( f i l e n a m e )
49 print '%s KERJAKAN %s ' % ( t i m e . s t r f t i m e ( '%H:%M:%S ' ) ,
job )
50 k a b a r . append ( j o b )
51
52 print ' Pekerjaan utama berakhir '
53 sampingan . j o i n ( )

Jalankan.

1 $ python t e s t t h r e a d . py
2 04:56:54 Pekerjaan utama dimulai
3 04:56:54 Kerja sampingan dimulai

Sampai di sini ia menunggu keberadaan le di direktori /tmp/job. Buka


konsole lain dan buatlah direktori /tmp/job.

1 $ mkdir /tmp / j o b

Lalu buatlah le apa saja.

1 $ e ho h e l l o > /tmp / j o b / h e l l o . t x t

Kemudian lihat konsole testthread.py tadi.

1 0 4 : 5 6 : 5 6 KERJAKAN hello
2 04:56:57 KABARI hello

Pointer

Perlu diperhatikan variabel kabar yang bertipe list (baris 30). Ini adalah vari-
abel bersama , artinya dapat diolah baik oleh thread 1 maupun thread 2. Di
sini berlaku apa yang disebut pointer yang artinya alokasi memori pada baris
30 dengan baris 10

1 s e l f . kabar = k

adalah sama . Perhatikan juga penghapusan antrian pertama di baris 20

1 del s e l f . kabar [ 0 ℄

dimana pada program biasa bisa saja Anda membuatnya menjadi

1 s e l f . kabar = s e l f . kabar [ 1 : ℄

Namun teknik ini akan membuat alokasi memori yang baru dimana thread 2
tidak lagi menggunakan variabel kabar sebagaimana yang digunakan oleh thread
1.
Mudah-mudahan Anda paham apa yang dimaksud dengan multi-thread ini.
Bab 14

SMS Gateway
SMS Gateway adalah salah satu produk RAB yang memanfaatkan Python dan
PostgreSQL. Akses ke database menggunakan SQLAl hemy dan Elixir. Diran-
ang semodular mungkin agar mudah dipakai oleh sistem lainnya yang bukan
Python, bukan PostgreSQL, bahkan bukan Linux.
Produk ini juga menerapkan teknik event driven dan plug-in.

14.1 Pemasangan

1 $ sudo a p t −g e t install im−gw

Proses instalasi akan meminta Anda menyesuaikan le /et /im/gw/ on-
g.py. File ini perlu diisi dengan otentikasi ke database yang sudah dibuat
tadi.

1 db_url = ' p o s t g r e s : / / ilham :1234 lo alhost :5432/ t o t a l i n d o '

Kemudian jalankan:

1 $ sudo dpkg− r e o n f i g u r e im−gw

Proses ini akan membuat tabel yang dibutuhkan ke database totalindo.


Paket im-gw digunakan untuk hal yang berkaitan dengan database seperti
menyimpan dan mengirim pesan. Daemonnya bisa Anda stop dan start dengan
ara:

1 $ sudo / e t / i n i t . d / im−gw restart

im-gw juga otomatis hidup saat komputer dihidupkan. Anda bisa memantau
log-nya dengan ara:

1 $ sudo tail −f / v a r / l o g / im /gw . l o g


2 2011 − 01 − 18 05:12:20 ,883 INFO Start result dir / var / s p o o l /
im / r e s u l t /
3 2011 − 01 − 18 05:12:20 ,886 INFO Start job at pid 1202

115
BAB 14. SMS GATEWAY 116

4 2011 − 01 − 18 05:12:20 ,928 INFO Start result xmlrp server


on port 9317

Tekan Ctrl-C untuk mengakhiri. Tapi sebaiknya tetap terpantau, dan Anda
bisa gunakan konsole lain untuk aktivitas berikutnya.
Untuk mengirim dan menerima SMS yang sebenarnya dibutuhkan pengen-
dali modem:

1 $ sudo a p t −g e t install im−modem

Paket ini juga akan membuat tabel, menggunakan kongurasi yang sama
dengan im-gw.
Pasanglah modem GSM atau CDMA. Merk yang sudah teruji adalah Wave-
om, iTegno, dan Multite h. USB devi e lebih disarankan karena mendukung
hotplug, dimana saat modem ditan apkan pengendalinya otomatis aktif. Anda
bisa periksa dengan perintah:

1 $ ps ax | g r e p modem
2 5627 ? SN 0:06 / u s r / b i n / python / u s r / b i n /modem−h o t p l u g
3 28464 ? Sl 0:01 python / u s r / b i n /modem / d e v / ttyUSB0

Perhatikan /usr/bin/modem-hotplug, dialah yang memantau aktivitas pe-


masangan perangkat USB. Lalu ada juga /usr/bin/modem, daemon inilah yang
dipanggil oleh modem-hotplug saat USB modem ditan apkan. Lalu bagaimana
jika perangkatnya ditan apkan di serial port ?
Anda pastikan dulu modem itu terpasang di serial port berapa. Keberadaan
serial port bisa dilihat dengan perintah berikut:

1 $ dmesg | grep ttyS


2 [ 25.972197℄ serial8250 : ttyS0 at I /O 0 x 3 f 8 ( i r q = 4) is
a 1 6 5 5 0A
3 [ 25.973141℄ 00:07: ttyS0 at I /O 0 x 3 f 8 ( i r q = 4) is a
1 6 5 5 0A
4 [ 42.442528℄ 0000:05:01.0: ttyS4 at I /O 0 x d 1 0 0 ( i r q = 17)
is a 1 6 5 5 0A
5 [ 42.442750℄ 0000:05:01.0: ttyS5 at I /O 0 x d 2 0 0 ( i r q = 17)
is a 1 6 5 5 0A
6 [ 42.538359℄ 0000:05:02.0: ttyS6 at I /O 0 x d 7 0 0 ( i r q = 19)
is a 1 6 5 5 0A
7 [ 42.538574℄ 0000:05:02.0: ttyS7 at I /O 0 x d 8 0 0 ( i r q = 19)
is a 1 6 5 5 0A

Anda bisa menyebutkan semua serial port yang ada pada le /et /im/-
modem/modem. onf:

1 [ devi e ℄
2 ; devi e di / dev / t t y
3 p o r t = USB0 USB1 USB2 USB3 USB4 USB5 USB6 USB7 S0 S4 S5
S6 S7

Lalu restart semua modem:


BAB 14. SMS GATEWAY 117

1 $ sudo / e t / i n i t . d /modem restart

Tunggu sekitar 30 detik, lalu jalankan

1 $ ps ax | g r e p modem
2 11211 ? Rl 10:29 python / u s r / b i n /modem / d e v /
ttyS0

untuk mengetahui serial port mana yg digunakan. Anda bisa mengesienkan


modem. onf diatas dengan hanya men antumkan S0 saja, namun tidak diubah
pun tidak menjadi masalah.
Sedangkan untuk melihat log-nya, terlebih dahulu Anda periksa direktori
/var/log/modem, ada le apa di sana:

1 $ sudo ls / v a r / l o g /modem
2 510012541218911. l o g

Selanjutnya mulailah memantau:

1 $ sudo tail −f / v a r / l o g /modem/ 5 1 0 0 1 2 5 4 1 2 1 8 9 1 1 . l o g −n 30


2 2011 − 01 − 18 01:45:22 ,304 INFO −> AT+CSQ
3 2011 − 01 − 18 01:45:24 ,307 INFO <− AT+CSQ
4 2011 − 01 − 18 01:45:24 ,308 INFO <− +CSQ : 20 ,0
5 2011 − 01 − 18 01:45:24 ,308 INFO <− OK
6 2011 − 01 − 18 01:45:24 ,309 INFO −> AT+CLIP=1
7 2011 − 01 − 18 01:45:26 ,312 INFO <− AT+CLIP=1
8 2011 − 01 − 18 01:45:26 ,312 INFO <− OK
9 2011 − 01 − 18 01:45:26 ,312 INFO −> AT+CGMM
10 2011 − 01 − 18 01:45:27 ,326 INFO <− AT+CGMM
11 2011 − 01 − 18 01:45:27 ,326 INFO <− MULTIBAND 9 0 0E 1800
12 2011 − 01 − 18 01:45:27 ,327 INFO <− OK
13 2011 − 01 − 18 01:45:27 ,327 INFO −> AT+CNMI= 0 , 1 , 1 , 1 , 0
14 2011 − 01 − 18 01:45:29 ,330 INFO <− AT+CNMI= 0 , 1 , 1 , 1 , 0
15 2011 − 01 − 18 01:45:29 ,330 INFO <− OK
16 2011 − 01 − 18 01:45:29 ,330 INFO −> AT+CMGF=1
17 2011 − 01 − 18 01:45:31 ,332 INFO <− AT+CMGF=1
18 2011 − 01 − 18 01:45:31 ,333 INFO <− OK
19 2011 − 01 − 18 01:45:31 ,333 INFO −> AT+CMGL="ALL"
20 2011 − 01 − 18 01:45:32 ,346 INFO <− AT+CMGL="ALL"
21 2011 − 01 − 18 01:45:32 ,346 INFO <− OK
22 2011 − 01 − 18 01:45:32 ,352 INFO S e r v i n g / d e v / ttyUSB1 and /
v a r / s p o o l / im / j o b /modem/ 5 1 0 0 1 2 5 4 1 2 1 8 9 1 1 / at pid 28464

Bila Anda sudah berjumpa kalimat yang berawalan Serving seperti di atas,
maka modem sudah siap.

14.1.1 IMEI Chip


Lalu apa yang dimaksud dengan angka 510012541218911 pada nama le log ?
Mengapa tidak USB0.log atau S0.log saja ?
BAB 14. SMS GATEWAY 118

Angka itu disebut dengan IMEI alias identitas hip / SIM ard. Jika kom-
puter membutuhkan informasi devi e port untuk mengendalikan modem, maka
manusia / user membutuhkan IMEI sebagai identitas hip yang ada di dalam
modem. Aktivitas menerima dan mengirim SMS tentu melekat pada hip, bukan
pada modem. Karena itu penggunaan IMEI pada nama log adalah yang paling
tepat untuk menjaga konsistensi history.
Lagi pula devi e port yang digunakan modem USB kadang berubah. Saat
ini mungkin modem dikenali di USB0. Coba Anda lepas dan pasang lagi di
tempat yang sama, bisa jadi kini USB1 yang digunakannya.

14.1.2 Database
Saat /usr/bin/modem mulai mengendalikan sebuah modem, ia melaporkan ke
/usr/bin/im-gw bahwa IMEI 510012541218911 baru saja hidup. Kejadian ini
disebut sebagai startup. Saat itulah im-gw memeriksa keberadaan IMEI terse-
but di tabel im.agent. Kalau belum ada ia tambahkan, dan kalau sudah ada ia
perbaharui statusnya.

1 $ psql −U ilham −h lo alhost totalindo


2 Password for user ilham :
3 psql (8.4.4)
4 SSL onne tion ( ipher : DHE−RSA−AES256−SHA, bits : 256)
5 Type " help " for help .
6 t o t a l i n d o=> SELECT i d , s t a t u s FROM im . a g e n t ;
7 id | status
8 −−−−−−−−−−−−−−−−−+−−−−−−−−
9 510012541218911 | 0
10 (1 row )

Status 0 berarti modem siap, status negatif berarti sebaliknya. Alasan untuk
status negatif bisa Anda lihat di tabel im.status.

14.2 Hello world!

Mari mulai mengirim SMS ke handphone Anda, masih di psql.

1 t o t a l i n d o=> INSERT INTO im . a n t r i a n ( p e n e r i m a , p e s a n )


2 t o t a l i n d o −> SELECT '+628179140068 ' , ' Hello world ! ' ;
3 INSERT 0 1

Untuk penerima sesuaikanlah dengan nomor handphone Anda.


Status pengiriman bisa Anda lihat di tabel im.selesai.

1 t o t a l i n d o=> SELECT i d , status , pengirim , penerima , pesan


2 t o t a l i n d o −> FROM im . s e l e s a i ORDER BY 1 DESC LIMIT 1;
3 id | status | pengirim | penerima |
pesan
BAB 14. SMS GATEWAY 119

4 −−−−−−+−−−−−−−−+−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−

5 1065 | 0 | 510012541218911 | +628179140068 | Hello


world !
6 (1 row )

Status 0 berarti telah terkirim, negatif sebaliknya, sedangkan positif berarti


sedang diproses. Penjelasannya bisa dilihat di tabel im.status.
Setelah Anda menerima SMS di handphone, balaslah SMS itu dengan:

Diterima

Tunggu sekitar 30 detik, dan lihat tabel im.antrian.

1 t o t a l i n d o=> SELECT i d , kirim , pengirim , penerima , pesan


2 t o t a l i n d o −> FROM im . a n t r i a n ;
3 id | kirim | pengirim | penerima | pesan
4 −−−−−−+−−−−−−−+−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−+−−−−−−−−−−

5 1071 | f | +628179140068 | 510012541218911 |


Diterima
6 (1 row

Mungkin Anda bertanya-tanya, saat mengirim pesan tabel im.antrian yang


digunakan, begitu juga saat menerima pesan. Lalu apa pembedanya ?
Perhatikan eld kirim di atas. Jika eld kirim = f (False), itu berarti re ord
pesan masuk. Jika bernilai t (True) berarti pengiriman pesan. Defaultnya
adalah True (pengiriman pesan).

14.3 Instant Messenger Gateway

Ada dua paket utama di sini, yaitu im-gw dan im-modem. Keduanya terhubung
sebagaimana pada gambar 14.1. Lalu mengapa harus ada dua paket ?
Meski judul tulisan ini adalah SMS Gateway, namun pada konsepnya sistem
ini dapat disanding dengan paket instant messenger seperti Yahoo! Messenger
dan XMPP (Jabber, GTalk). Keduanya ada di paket im-ym dan im-xmpp.
Jadi im-modem, im-ym, dan im-xmpp sejajar kedudukannya. Kalau im-modem
memerlukan sik modem, maka im-ym dan im-xmpp membutuhkan koneksi
Internet.
Jadi bila Anda ingin men oba sistem ini namun belum memiliki modem,
maka bisa gunakan im-ym dan im-xmpp.

14.3.1 Yahoo! Messenger


Sebelum pemasangan, sebaiknya Anda siapkan Yahoo! a ount yang baru yang
akan digunakan oleh /usr/bin/ym (daemon dari paket im-ym). Selanjutnya
pasang paketnya.
BAB 14. SMS GATEWAY 120

Gambar 14.1: Alur IM gateway


BAB 14. SMS GATEWAY 121

1 $ sudo a p t −g e t install im−ym

Kemudian sesuaikan /et /im/ym/ ong.py, seperti ontoh berikut:

1 users = { ' inforab ' : ' 1234 ' }

dimana inforab adalah Yahoo! a ount dan 1234 adalah passwordnya.


Setelah disimpan tunggu satu menit dan periksa keberadaannya.

1 $ ps ax | g r e p ym
2 2339 ? Sl 24:44 python / u s r / b i n /ym i n f o r a b

Log-nya juga tersedia.

1 $ sudo tail −f / v a r / l o g /ym/ i n f o r a b . l o g


2 2011 − 02 − 25 14:24:46 ,729 INFO S t a r t u p { ' status ' : 0}

Sekarang oba add buddy dari Yahoo! Messenger lient seperti Pidgin. Ten-
tu saja gunakan Yahoo! a ount yang lain. Daemon ym se ara otomatis akan
menambahkannya ke dalam daftar.
Selanjutnya kirim pesan seperti biasa, lalu lihat log-nya:

1 2011 − 02 − 25 15:10:43 ,885 INFO I n b o x { ' tgl_operator ' :


'2011 − 02 − 25 15:10:43+7 ' , ' pesan ' : ' hello world ' , '
pengirim ' : ' info_rab ' }

dan lihat juga tabel im.antrian.

1 t o t a l i n d o=> SELECT i d , kirim , jalur , pengirim , penerima ,


pesan
2 t o t a l i n d o −> FROM im . a n t r i a n ;
3 id | kirim | jalur | pengirim | penerima | pesan
4 −−−−−−+−−−−−−−+−−−−−−−+−−−−−−−−−−+−−−−−−−−−−+−−−−−−−−−−−−−

5 2074 | f | 5 | info_rab | inforab | hello world


6 (1 row )

Sekarang perhatikan kolom jalur yang berisi 5. Itu artinya jalur ym. Sedan-
gkan jalur modem berisi 1 (default). Daftar jalur ini ada di tabel jalur.

14.3.2 XMPP
Jika Anda punya a ount di Gmail maka Anda dapat hatting dengan user
Gmail lainnya. Namun sebenarnya Anda dapat hatting dengan user dari server
lain yang menggunakan protokol XMPP seperti jabber.org atau jabber.rab. o.id.
Ya, seperti email, protokol XMPP memungkinkan user dari server berbeda da-
pat saling mengirim pesan.
Jika Anda berminat menggunakan XMPP untuk hatting dengan server,
pasang paket im-xmpp.

1 $ sudo a p t −g e t install im−xmpp

Lalu sesuaikan /et /im/xmpp/ ong.py.


BAB 14. SMS GATEWAY 122

1 u s e r s = { ' i n f o r a b  g m a i l . om ' :
2 { ' password ' : ' 1234 ' , ' sasl ' : True ,
3 ' port ' : 5223 , ' server ' : ' t a l k . g o o g l e . om ' }
4 }

Sesuaikan inforab dan 1234. Setelah disimpan tunggu satu menit hingga
daemon-nya up. Setelah hidup, Anda bisa lakukan pengujian yang serupa seper-
ti ym.
Jika Anda ingin menggunakan server lokal, bisa oba daftar ke jabber.rab. o.id
menggunakan Pidgin. Lalu sesuaikan /et /im/xmpp/ ong.py seperti ontoh
berikut.

1 u s e r s = { ' i n f o r a b  g m a i l . om ' :
2 { ' password ' : ' 1234 ' , ' sasl ' : True ,
3 ' port ' : 5223 , ' server ' : ' t a l k . g o o g l e . om ' } ,
4 ' i n f o  j a b b e r . rab . o . i d ' : ' 1234 '
5 }

Ya, im-xmpp juga dapat menghidupkan lebih dari satu a ount. Kebetulan
jabber.rab. o.id menggunakan kongurasi yang lebih sederhana sebagaimana
ontoh di atas.

14.4 Broad ast

Anda telah memiliki banyak pelanggan dan ingin mengirim pesan yang sama
ke mereka. Dengan mudah lakukan query berikut.

1 INSERT INTO im . a n t r i a n ( p e n e r i m a , pesan )


2 SELECT no_hp , ' Selamat t r a n s a k s i ' FROM p e l a n g g a n ;

Sayangnya untuk jumlah penerima yang sangat banyak tidak bisa semudah
itu, karena /usr/bin/modem memiliki nilai job timeout yang default-nya 420 de-
tik alias 7 menit. Jika setiap pesan membutuhkan waktu 10 detik untuk dikirim,
maka hanya 42 pesan saja yang akan dikirim. Selebihnya akan dilaporkan oleh
/usr/bin/modem sebagai status -9 alias Timeout.
Menaikkan nilai timeout di /et /im/modem/modem. onf bisa juga jadi so-
lusi, namun tidak disarankan. Teknik yang paling pas adalah menyiapkan dae-
mon baru yang memantau nilai eld job. Jika job lebih besar dari 5 maka tidak
dilakukan INSERT ke im.antrian.
Untuk kebutuhan ini sudah disiapkan paket im-broad ast.

1 $ sudo a p t −g e t install im− b r o a d a s t

Untuk mengirim pesan kita perlu melakukan INSERT ke dua tabel, yaitu
im.broad ast dan im.broad ast_penerima. Tabel pertama berisi pesan, sedan-
gkan tabel kedua berisi penerimanya. Kedua tabel ini akan diproses oleh daemon
/usr/bin/im-broad ast untuk disalin ke tabel im.antrian.
Pertama kita memerlukan nilai ID untuk broad ast yang baru.
BAB 14. SMS GATEWAY 123

1 t o t a l i n d o=> SELECT n e x t v a l ( ' im . b r o a d a s t _ i d _ s e q ' ) ;


2 nextval
3 −−−−−−−−−
4 8
5 (1 row )

Kemudian tambahkan pesannya.

1 t o t a l i n d o=> INSERT INTO im . b r o a d a s t ( i d , j u d u l , p e s a n )


2 t o t a l i n d o −> SELECT 8, ' Uji broad ast ' , ' Selamat transaksi
';
3 INSERT 0 1

Field judul hanya untuk keterangan saja. Field pesan-lah yang nanti akan
dikirim. Berikutnya tambahkan penerima pesan.

1 t o t a l i n d o=> INSERT INTO im . b r o a d a s t _ p e n e r i m a ( i d ,


penerima )
2 t o t a l i n d o −> SELECT 8, '+628179140068 ';
3 INSERT 0 1

Jalur default yang digunakan adalah 1 (modem). Untuk jalur lainnya ser-
takan eld jalur.

1 t o t a l i n d o=> INSERT INTO im . b r o a d a s t _ p e n e r i m a ( i d , p e n e r i m a


, jalur )
2 t o t a l i n d o −> SELECT 8 , ' info_rab ' , 5 ;
3 INSERT 0 1

Dimana jalur 5 adalah ym.


Bab 15

Web

15.1 Django

15.2 Webpy

124
Bab 16

Hosting

16.1 Virtualmin

Ingin berbisnis web hosting ? Terbentur biaya untuk pengadaan CPanel ? Saat-
1
nya menggunakan Virtualmin . Ingin membidik pangsa developer Python se-
lain pangsa PHP ? Anda masih bisa mengubah kemampuan Virtualmin. Tidak
punya IP publik statik ? Hanya dapat IP publik dinamik ? Jangan ragu, tetap
gunakan Virtualmin.
Virtualmin merupakan antarmuka web untuk mengatur berbagai hal terkait
dengan bisnis web hosting Anda. Ia memberikan kemudahan dalam pendaf-
taran domain, pemberian hak akses, dan juga kuota. Ia merupakan produk open
sour e yang mengatur berbagai aplikasi standar lainnya seperti Apa he, PHP,
Postx, Dove ot, PostgreSQL, dst. Namun begitu, ia menghindari "sentuhan
sihir" alias tetap mengikuti aturan-aturan yang ditetapkan masing-masing ap-
likasi tersebut.

16.1.1 Pemasangan Ubuntu


Ya, kita akan gunakan Ubuntu
2 di sini. Kebiasaan Virtualmin adalah meng-
gunakan Ubuntu jenis LTS (Long Term Support), seperti Hardy (8.04) atau
Lu id (10.04). Kali ini kita akan gunakan versi 10.04 dimana Anda bisa pilih
untuk prosesor 32 bit (i386) atau 64 bit (amd64). Paling aman gunakan i386,
tapi prosesor terbaru rata-rata sudah mendukung versi amd64, bahkan yang
dikeluarkan Intel sekalipun.
Oh iya, ada lagi pengkategorian lainnya, yaitu versi desktop atau server. Jika
server sering berada di depan Anda - misalkan server ada di rumah - sebaiknya
3
pilih yang desktop, karena telah dilengkapi GUI , sehingga Firefox tersedia.
Namun jika server diletakkan nun jauh di sana, pilihlah versi server agar Anda
tidak berlama-lama saat melakukan upgrade.

1 http://virtualmin. om
2 http://ubuntu. om
3 Graphi al User Interfa e

125
BAB 16. HOSTING 126

Amannya pilih yang mana ? Pilihlah Ubuntu 10.04 i386 Desktop Edition .
4
ISO bisa di-burn ke CD-ROM 700 MB. Rata-rata motherboard sekarang su-
dah mendukung boot melalui ashdisk. Jadi ada baiknya burn ISO ke ashdisk
menggunakan aplikasi Unetbootin, tersedia untuk sistem operasi Windows dan
Linux.
Setelah di-burn, boot, dan ikuti langkah-langkah petunjuk pemasangannya.
Sebaiknya pilihlah Bahasa Indonesia agar default format sesuai dengan Indone-
sia seperti format tanggal (dmy), pemisah ribuan (thousand separator), dsb.
Setelah pemasangan selesai dan server sudah di-boot, ubahlah hak akses
pada home dire tory Anda agar user lain tidak bisa melihat isinya.

$ hmod 750 /home/sugiana

Anda tidak perlu melakukan ini jika membuat user baru melalui Virtualmin
nanti.

16.1.2 Kongurasi Network


Untuk menetapkan IP, Anda bisa menggunakan menu System, Preferen es, Net-
work Conne tions. Jika Anda tidak memasang GUI, bisa lakukan kongurasi
melalui le /et /network/interfa es seperti ini:

1 ifa e eth0 inet stati


2 address 202.59.201.67
3 netmask 255.255.255.192
4 gateway 203.130.231.65

Lalu reboot server untuk memastikan kongurasi dijalankan saat server


hidup. Kemudian ujilah dengan mengunjungi salah satu IP yang Anda kenal:

$ telnet 203.130.231.120 80

Jika Anda mendapati baris "Es ape hara ter is" berarti gateway berfungsi
dengan baik:

Trying 203.130.231.120...
Conne ted to 203.130.231.120.
Es ape hara ter is '^℄'.

Oh iya, juga sesuaikan /et /resolv. onf agar Anda bisa memanggil dengan nama
(DNS), misalnya:

nameserver 203.130.231.120

Lalu ujilah DNS ini dengan memanggil nama:

4 http://openstorage.gunadarma.a .id/linux/iso/ubuntu/lu id/ubuntu-10.04-desktop-


i386.iso
BAB 16. HOSTING 127

$ telnet google. om 80
Trying 74.125.235.20...
Conne ted to google. om.
Es ape hara ter is '^℄'.
Sesuaikanlah gateway dan DNS ini dengan menanyakan ke Internet Servi e
Provider Anda.
Server Anda terhubung dengan modem ADSL ? Biasanya IP sudah dis-
et se ara otomatis melalui mekanisme DHCP. Meski begitu sebaiknya Anda
memastikan IP LAN tetap statik. Bisa diset melalui menu tadi, atau melalui
modem ADSL-nya dimana biasanya modem akan menentukan MAC address
00:1f:3 :e0:66:56 mendapat IP 192.168.1.2 ( ontoh).

16.1.3 Pemasangan Virtualmin


Sudah terhubung ke Internet ? Selanjutnya unduh s ript instalasinya:

$ wget http://software.virtualmin. om/gpl/s ripts/install.sh


Lalu jalankan:

$ sudo sh install.sh
Saat ia menanyakan hostname, jawablah sesuai nama domain hosting yang Anda
kelola:

Please enter a fully qualied hostname (for example, example. om):


sabilawebhosting. om
Lalu saat ia menanyakan network interfa e, periksalah di konsole lain dengan
if ong, interfa e apa yang digunakan. Kalau terhubung dengan kabel biasanya
eth0, kalau wireless biasanya wlan0:

Please enter the name of your primary network interfa e: eth0


Selanjutnya ia mengunduh aplikasi yang diperlukan dan melakuan kongurasi.
Tunggulah, ini memerlukan waktu beberapa lama. Jika berhasil, pesan ter-
akhirnya adalah:

INFO - Rule updates done

Namun ada kalanya Anda mendapatkan pesan ini:

FATAL - in /root/virtualmin-install.log

Kadang selama proses unduh terjadi " onne tion refused". Mungkin server
Virtualmin sedang di-restart. Tunggulah beberapa saat, dan jalankan lagi s ript
instalasi seperti tadi.

$ sudo sh install.sh
Biasanya ia mengerti untuk tidak melakukannya dari awal.
BAB 16. HOSTING 128

16.1.4 Text Editor


Jika Anda menggunakan GUI, gedit bisa digunakan untuk text editor:

$ sudo gedit

Namun jika Anda terbiasa dengan konsole, vi dan nano sudah tersedia. Bagi
yang terbiasa dengan vi ada baiknya pasang vim (vi improved) untuk kenya-
manan:

$ sudo apt-get install vim

Lalu sesuaikan beberapa kongurasi pada /et /vim/vimr . Kongurasi berikut


ini untuk mengingat posisi kursor pada le yang pernah Anda buka:

1 " Un omment the following to h a v e Vim jump to the last


position when
2 " reopening a file
3 if h a s ( " auto md " )
4 au BufReadPost * if l i n e ( " ' \ " " ) > 1 && l i n e ( " ' \ " " ) <=
l i n e (" $ ") | exe " normal ! g '\"" | endif
5 endif

Terkait dengan penulisan sour e, pastikan auto-indent bekerja. Gunakan


karakter spasi untuk indent ketimbang karakter tab:

1 " Un omment the following to h a v e Vim load indentation


rules and plugins
2 " a ording to the dete ted filetype .
3 if h a s ( " auto md " )
4 filetype plugin indent on
5 set smartindent
6 set expandtab
7 set t a b s t o p=4
8 set s o f t t a b s t o p =4
9 set s h i f t w i d t h =4
10 endif

Aktifkan pen arian pintar dimana kalau Anda menuliskan huruf ke il semua
saat pen arian maka tidak mempedulikan huruf ke il ataupun besar (in ase-
sensitive). Namun jika Anda menyertakan huruf besar maka ase-sensitive
berlaku.

1 set ignore ase " Do ase insensitive mat hing


2 set smart ase " Do s m a r t ase mat hing

Selesai dan simpanlah. Kongurasi ini se ara otomatis juga berlaku bagi
user Anda nantinya. Sehingga kenyamanan programmer makin bertambah.
BAB 16. HOSTING 129

16.1.5 Kongurasi PHP


Ya, kita atur dulu urusan PHP sebagai bahasa yang umum digunakan oleh
pengembang web. Pasang modul suphp agar setiap s ript PHP dijalankan oleh
pemiliknya:

$ sudo apt-get install libapa he2-mod-suphp

Pastikan direktori /home sebagai basis suphp, ubah /et /suphp/suphp. onf,
ganti baris

do root=/var/www:${HOME}/publi _html

menjadi

do root=/home

Non-aktif-kan modul php5 karena sudah diganti dengan modul suphp:

$ sudo a2dismod php5

Kemudian pasang modul untuk PostgreSQL, MySQL, dan grak:

$ sudo apt-get install php5-pgsql php5-mysql php5-gd

Ubahlah /et /php5/ gi/php.ini agar pengunjung web nyaman unggah video:

1 m a x _ e x e u t i o n _t i m e = 1 0 0 0
2 max_input_time = 1 0 0 0
3 memory_limit = 1 2 8M
4 p o s t _ m a x _ s i z e = 1 0 0M
5 u p l o a d _ m a x _ f i l e s i z e = 1 0 0 0M

Lalu restart web server:

$ sudo servi e apa he2 restart

Kongurasi PHP selesai.

16.1.6 Mail Server


Postx perlu diatur agar boleh menerima relay dari network lain. Misalkan user
mengirim email dari notebook menggunakan Thunderbird. Ubah /et /postx/-
master. f, aktifkan baris submission dan smtps :
1 submission inet n − − − − smtpd
2 smtps inet n − − − − smtpd
Karena user a ount menggunakan Linux user, ubahlah /et /default/saslau-
thd, dari baris:
BAB 16. HOSTING 130

MECHANISMS="pam"

menjadi

MECHANISMS="shadow"

Restart daemon-nya:

$ sudo servi e saslauthd restart


$ sudo servi e postfix restart

16.1.7 PostgreSQL
Sebaiknya Anda periksa default en oding yang digunakan PostgreSQL.

$ sudo su postgres - "psql - '\l'"

Kalau en oding masih SQL_ASCII berarti Anda harus menggantinya ke UTF8.


Mengapa ? Karena SQL_ASCII bisa berarti "kalau ada karakter sampah,
biarkan saja". Berikut ini ara mengubahnya:

$ sudo pg_drop luster --stop 8.4 main


$ sudo pg_ reate luster --start -e UTF-8 8.4 main

16.1.8 Kongurasi Awal Virtualmin


Berikutnya kongurasi awal melalui web. Jika Anda memasang desktop, bisa
langsung ke url:

https://127.0.0.1:10000

Namun jika server sudah berada di remote, Anda bisa gunakan IP publiknya
sehingga url menjadi ( ontoh):

https://202.59.201.67:10000

Selanjutnya web Virtualmin meminta kita untuk login menggunakan superuser,


dalam hal ini user saat pemasangan Ubuntu pertama kali.
Pada awal login, Anda dihadapkan pada wizard untuk kongurasi. Se ara
umum Anda ukup memilih Yes dan klik Next hingga selesai. Setelah Next
terakhir di-klik, Anda diminta untuk klik:

Re- he k and refresh onguration

Jika lan ar, Anda akan menemui pesan ini:

.. your system is ready for use by Virtualmin.

Jika server berada di belakang rewall, misalnya Anda menggunakan modem


ADSL sebagai gateway, biasanya akan menemui pesan berikut ini:
BAB 16. HOSTING 131

Default IP address is set to 192.168.1.2, but the dete ted external


address is a tually 180.252.150.215. This is typi ally the result of
being behind a NAT rewall, and should be orre ted on the module
onguration page.

Jika IP publik server adalah statik, maka lanjutkan klik module onguration
yang dimaksud. Atau se ara menu melalui System Settings, Virtualmin Con-
guration. Pada pilihan Conguration Category, pilih Network settings, lalu:
Default IP address for DNS re ords: Automati ally dete t ex-
ternal address
Klik Save. Jangan lupa mengatur modem ADSL untuk mengarahkan seluruh
permintaan dari luar ke server 192.168.1.2. Mekanisme ini sering disebut sebagai
port forwarding, atau ada juga yang bilang DMZ.
Jika Anda tidak pernah memesan IP publik statik pada ISP, hampir di-
pastikan Anda hanya mendapat IP publik dinamik. Dengan demikian abaikan
saja urusan DNS di atas, karena DNS yang Anda butuhkan perlu ditangani
server lain yang memiliki IP publik statik, misalnya dyndns.org.
Yang lebih mengkhawatirkan lagi bila server tidak mendapatkan IP publik.
Ini artinya server tidak bisa disentuh (ba a: di- route ) dari luar. Praktis Anda
tidak bisa berbisnis hosting. Untuk memastikannya, oba minta teman Anda
yang ada di "seberang" sana untuk mengakses http://180.252.150.215.
Sesuaikanlah IP-nya sebagaimana yang dilaporkan Virtualmin di atas. Jika
ia mendapatkan pesan:

It works!

maka server Anda telah memiliki IP publik.

16.1.9 Mail A ount


Se ara default, Virtualmin menggunakan format user.domain untuk IMAP lo-
gin. Akan lebih nyaman bila formatnya menggunakan userdomain, agar sama
dengan emailnya. Ikuti langkah berikut ini:

1. Masuk ke menu System Settings, Server Templates, Default Settings.


2. Pada bagian Edit template se tion, pilihlah Mail for domain.
3. Pada bagian Format for usernames that in lude domain pilihlah user-
namedomain.
4. Klik Save.

Khusus administrator domain bersangkutan, IMAP login tidak memerlukan


domain. Lebih jelasnya Anda bisa lihat di menu Edit Mail and FTP users
kolom IMAP/FTP login, setelah Anda membuat domain nanti.
BAB 16. HOSTING 132

16.1.10 Hak Akses


Berikanlah user hak untuk membuat virtual server. Ini artinya jika user Anda
memiliki domain reymanx.web.id, maka ia dapat membuat subdomain blog.reymanx.web.id,
download.reymanx.web.id, dst. Atur melalui menu System Settings, A ount
Plans, Default Plan :
Limit on number virtual servers: Unlimited
Klik Save.

16.1.11 Berikan Bash


Bila nanti user login menggunakan ssh (se ure shell), ia akan mendapat shell
sederhana, yaitu /bin/sh. Terus terang, shell ini kurang nyaman, dimana tidak
memiliki history dan auto ompletion. Sebaiknya Anda memberikan /bin/bash.
Klik menu System Customization, Custom Shell, Custom shells below. Gantilah
/bin/sh menjadi /bin/bash, lalu klik Save.
Aktifkan auto ompletion di /et /bash.bashr :

1 # enable bash ompletion in intera tive shells


2 if [ −f / e t / bash_ ompletion ℄ && ! shopt −oq posix ; then
3 . / e t / bash_ ompletion
4 fi

Agar lebih nyaman dalam memasang berbagai aplikasi dari GitHub dan
Bitbu ket, pasanglah aplikasi pengunduhnya:

$ sudo apt-get install git- ore mer urial

16.1.12 Kongurasi Python


Ya, akhirnya kita sampai ke bagian ini, dimana user se ara default menggunakan
Python untuk membuat web. Pasanglah modul WSGI untuk Apa he:

$ sudo apt-get install libapa he2-mod-wsgi

Juga Virtual Environment agar user dimudahkan dalam memasang modul Python
lainnya tanpa perlu memanggil Anda sebagai pengelola hosting.

$ sudo apt-get install python-virtualenv

Driver untuk akses database juga perlu disiapkan:

$ sudo apt-get install python-psy opg2 python-mysqldb

Virtualmin sudah menyediakan apa yang disebut Server Template. Saat pendaf-
taran domain, admin diberikan kesempatan memilih bahasa apa yang akan di-
gunakan pelanggannya. Default-nya adalah PHP, dan alternatif lain adalah
BAB 16. HOSTING 133

Python. Create Virtual Server, Server ongu-


Pilihan ini terdapat di menu
ration template. Default Settings yang berarti PHP yang
Di sana ada pilihan
digunakan dengan direktori publi _html sebagai Do umentRoot.
Lalu dimana pilihan Python ? Seharusnya ada di bawahnya, namun saat ini
belum ada. Inilah yang akan kita buat sekarang.
Masuklah ke menu System Settings, Server Templates, Create a template
from the default settings. Isilah:
Template name: Python (bebas)

For use by: Sub-servers ( entang)

Klik Create and Next. Pada bagian Edit template se tion, pilih Apa he website.
Ini untuk mengganti form isian dengan hal-hal yang bersifat Apa he. Pada
bagian Dire tives and settings for new websites, dan pada radio button Apa he
dire tives below tambahkan baris-baris WSGI berikut ini (paling bawah):

WSGIS riptAlias / ${HOME}/wsgi/wsgi_handler.py


WSGIDaemonPro ess ${DOM} user=${USER} group=${GROUP} threads=15
WSGIPro essGroup ${DOM}

Klik Save.

16.1.13 Mengubah Sifat Virtualmin


Se ara default Virtualmin menyiapkan direktori $HOME/publi _html untuk
sour e PHP, dimana bila URL yang dimaksud dipanggil melalui browser - mis-
alkan http://sabilawebhosting. om - maka sour e PHP yang ada di direktori
itulah yang dijalankan Apa he. Istilahnya root do ument. Karena kita juga
akan membangun Python hosting, maka root do ument akan diganti dengan
s ript $HOME/wsgi/wsgi_handler.py.
Sebenarnya dengan apa yang Anda sudah pasang tadi sudah ukup bagi
user untuk menyiapkan segala sesuatunya. Namun sebagai pengelola hosting
yang memahami kebutuhan pelanggan, sebaiknya Anda menyiapkan s ript yang
dimaksud, lengkap dengan Python virtual environment pada home dire tory.
Untunglah Virtualmin memberi kesempatan pada kita untuk menyisipkan
s ript yang dijalankan setelah sebuah domain dibuat. Praktis ini mengurangi
sentuhan manual saat pendaftaran domain.
Masuklah ke menu System Settings, Virtualmin Conguration. Pada Con-
guration ategory, pilihlah A tions upon server and user reation. Lalu pada
Command to run after making hanges to a server isilah:
/usr/lo al/bin/virtualmin

Klik Save. Selanjutnya buatlah s ript berikut ini.

Listing 16.1: /usr/lo al/bin/virtualmin

1 #! / usr / b i n / python
BAB 16. HOSTING 134

2
3 import os
4 import sys
5
6 if o s . e n v i r o n [ 'VIRTUALSERVER_ACTION ' ℄ == 'CREATE_DOMAIN' :
7 o s . system ( ' p −r / u s r / l o a l / e t / v i r t u a l m i n / w s g i %s ' % (
8 o s . e n v i r o n [ 'VIRTUALSERVER_HOME' ℄ ) )
9 o s . s y s t e m ( ' d %s / w s g i ; ln −s . wsgi ' % os . environ [ '
VIRTUALSERVER_HOME' ℄ )
10 o s . s y s t e m ( ' v i r t u a l e n v %s / e n v ' % o s . e n v i r o n [ '
VIRTUALSERVER_HOME' ℄ )
11 o s . s y s t e m ( ' hown −R %s .% s %s / w s g i %s / e n v ' % (
12 o s . e n v i r o n [ 'VIRTUALSERVER_USER ' ℄ ,
13 o s . e n v i r o n [ 'VIRTUALSERVER_GROUP ' ℄ ,
14 o s . e n v i r o n [ 'VIRTUALSERVER_HOME' ℄ ,
15 o s . e n v i r o n [ 'VIRTUALSERVER_HOME' ℄ ) )

Pastikan exe utable:

$ sudo hmod 755 /usr/lo al/bin/virtualmin

Lalu siapkan direktori /usr/lo al/et /virtualmin/wsgi yang nantinya akan di-
taruh di $HOME/ :
$ sudo mkdir -p /usr/lo al/et /virtualmin/wsgi

Buatlah monitoring s ript yang berguna untuk autoreload daemon Python.


Daemon Python ?
Ya. Setiap s ript Python yang dibuat oleh user akan dijalankan oleh Apa he
sebagai daemon, dalam sebuah sub-pro ess. Monitoring s ript berguna untuk
memantau perubahan le pada direktori $HOME/wsgi. Bila s ript ini menda-
pati ada le yang berubah, se ara otomatis ia akan mengakhiri dirinya sendiri,
dan pada saat URL situs dipanggil lagi melalui browser, Apa he - se ara otoma-
tis pula - menghidupkan kembali daemon ini.
5

Listing 16.2: /usr/lo al/et /virtualmin/wsgi/monitor.py

1 import os
2 import sys
3 import time
4 import signal
5 import threading
6 import atexit
7 import Queue
8
9 _interval = 1.0

5 Interpreter Python mengizinkan kita untuk mengubah le *.py selama s ript sedang ber-
jalan (runtime ). Namun perubahan itu berfungsi saat s ript itu dijalankan ulang.
BAB 16. HOSTING 135

10 _times = {}
11 _files = [℄
12
13 _running = F a l s e
14 _queue = Queue . Queue ( )
15 _ l o k = t h r e a d i n g . Lo k ( )
16
17 def _ r e s t a r t ( path ) :
18 _queue . p u t ( True )
19 prefix = ' monitor ( p i d=%d ) : ' % o s . g e t p i d ( )
20 print >> s y s . s t d e r r , '%s Change dete ted to \ '% s \ ' . '
% ( prefix , path )
21 print >> s y s . s t d e r r , '%s Triggering pro ess restart . '
% prefix
22 os . k i l l ( os . getpid ( ) , s i g n a l . SIGINT )
23
24 def _modified ( path ) :
25 try :
26 # I f path doesn ' t denote a f i l e and were
previously
27 # t r a k i n g i t , then i t has been removed or t h e
f i l e type
28 # has hanged so f o r e a r e s t a r t . I f not
previously
29 # t r a k i n g t h e f i l e then we an i g n o r e i t as
probably
30 # pseudo r e f e r e n e su h as when f i l e e x t r a t e d
from a
31 # o l l e t i o n o f modules o n t a i n e d in a z i p f i l e .
32
33 if not os . path . i s f i l e ( path ) :
34 return path in _times
35
36 # Che k f o r when f i l e l a s t m o d i f i e d .
37
38 mtime = o s . s t a t ( p a t h ) . st_mtime
39 if path not in _times :
40 _ t i m e s [ p a t h ℄ = mtime
41
42 # For e r e s t a r t when m o d i f i a t i o n time has
hanged , even
43 # i f time now o l d e r , as t h a t o u l d i n d i a t e o l d e r
file
44 # has been r e s t o r e d .
45
46 if mtime != _times [ path ℄ :
BAB 16. HOSTING 136

47 return True
48 ex ept :
49 # I f any e x e p t i o n o ured , l i k e l y t h a t f i l e has
been
50 # been removed j u s t b e f o r e s t a t ( ) , so f o r e a
restart .
51
52 return True
53
54 return False
55
56 def _monitor ( ) :
57 while 1:
58 # Che k m o d i f i a t i o n times on a l l f i l e s in s y s .
modules .
59
60 for module in s y s . modules . v a l u e s ( ) :
61 if not h a s a t t r ( module , ' __file__ ' ) :
62 ontinue
63 p a t h = g e t a t t r ( module , ' __file__ ' )
64 if not path :
65 ontinue
66 if os . path . s p l i t e x t ( path ) [ 1 ℄ in [ ' . py ' , '.
pyo ' , ' . pyd ' ℄ :
67 path = path [ : −1℄
68 if _modified ( path ) :
69 return _ r e s t a r t ( path )
70
71 # Che k m o d i f i a t i o n times on f i l e s whi h have
72 # s p e i f i a l l y been r e g i s t e r e d f o r monitoring .
73
74 for path in _files :
75 if _modified ( path ) :
76 return _ r e s t a r t ( path )
77
78 # Go t o s l e e p f o r s p e i f i e d i n t e r v a l .
79
80 try :
81 return _queue . g e t ( t i m e o u t=_ i n t e r v a l )
82 ex ept :
83 pass
84
85 _ t h r e a d = t h r e a d i n g . Thread ( t a r g e t=_monitor )
86 _ t h r e a d . setDaemon ( True )
87
88 def _exiting () :
BAB 16. HOSTING 137

89 try :
90 _queue . p u t ( True )
91 ex ept :
92 pass
93 _thread . j o i n ( )
94
95 a t e x i t . r e g i s t e r ( _exiting )
96
97 def t r a k ( path ) :
98 if not path in _files :
99 _ f i l e s . append ( p a t h )
100
101 def s t a r t ( i n t e r v a l =1.0) :
102 global _interval
103 if i n t e r v a l < _interval :
104 _interval = i n t e r v a l
105
106 global _running
107 _lo k . a q u i r e ( )
108 if not _running :
109 prefix = ' monitor ( p i d=%d ) : ' % o s . g e t p i d ( )
110 print >> s y s . s t d e r r , '%s Starting hange monitor .
' % prefix
111 _ r u n n i n g = True
112 _thread . s t a r t ( )
113 _lo k . r e l e a s e ( )

Anda bisa salin dari situs aslinya:

http:// ode.google. om/p/modwsgi/wiki/ReloadingSour eCode

Selanjutnya buat root do ument.


Listing 16.3: wsgi_handler.py

1 def a p p l i a t i o n ( environ , start_response ) :


2 status = ' 2 0 0 OK '
3 output = ' Hello World ! '
4 response_headers = [ ( ' C o n t e n t −t y p e ' , ' text / plain ' ) ,
5 ( ' C o n t e n t −L e n g t h ' , s t r ( l e n ( output
))) ℄
6 start_response ( status , response_headers )
7 return [ output ℄
8
9
10 import os , sys
11
12 sys . stdout = sys . stderr
BAB 16. HOSTING 138

13 s y s . p a t h . append ( o s . p a t h . d i r n a m e ( o s . p a t h . a b s p a t h ( __file__ )
))
14 env_ver = ' . ' . j o i n ( map ( lambda x: str (x) , sys . version_info
[:2℄) )
15 env_path = o s . p a t h . d i r n a m e ( o s . p a t h . d i r n a m e ( o s . p a t h .
a b s p a t h ( __file__ ) ) ) + \
16 ' / e n v / l i b / p y t h o n%s / s i t e −p a k a g e s ' % env_ver
17 s y s . p a t h . append ( env_path )
18
19 #os . e n v i r o n [ 'DJANGO_SETTINGS_MODULE ' ℄ = ' myproje t .
settings '
20 #import django . ore . h a n d l e r s . wsgi
21 #a p p l i a t i o n = django . ore . h a n d l e r s . wsgi . WSGIHandler ( )
22
23 import monitor
24 monitor . s t a r t ( i n t e r v a l =1.0)

Selesai sudah kongurasi server. Kini saatnya produ tion.

16.1.14 Pendaftaran Domain


Mari dimulai dengan membuat domain perusahaan hosting Anda sendiri, dalam
hal inisabilawebhosting. om. Masih di Virtualmin, masuk ke menu Create Vir-
tual Server. Isilah:
Domain name: sabilawebhosting. om
Administration password: ****

Server onguration template: Python

Klik Create Server. Sekarang obalah kunjungi:

http://sabilawebhosting. om

Kalau Anda menjumpai:

Hello world!

berarti pendaftaran sudah berlangsung dengan baik. Bila Anda menjumpai:

Server not found

hampir dipastikan domain tersebut belum sepenuhnya dikenal oleh para ISP.
Jika Anda browsing di server pastikan baris berikut ini ada di urutan teratas
/et /resolv. onf :
nameserver 127.0.0.1

Namun jika Firefox Anda berada di mesin berbeda, pastikan DNS teratas adalah
IP server, masih di /et /resolv. onf dimana Firefox berada:
BAB 16. HOSTING 139

nameserver 202.59.201.67

Anda bisa membuka Virtualmin dengan subdomain admin, yaitu dengan url:

http://admin.sabilawebhosting. om

Hal serupa dapat dilakukan oleh pelanggan Anda sesuai domain mereka masing-
masing.
Sedangkan untuk mail, mereka bisa mengunjungi subdomain webmail, dalam
hal ini ontohnya adalah:

http://webmail.sabilawebhosting. om.

16.1.15 User Spa e


User diperkenankan melakukan SSH ke server dengan username awalan nama
domain (default). Jadi jika Anda membuat reymanx.web.id maka Virtualmin
se ara otomatis akan membuat user reymanx.
Katakanlah user reymanx ingin memasang Django , maka setelah ia SSH ke
6
server, ia bisa gunakan pip yang tersedia di virtual environment 7 :
$ env/bin/pip install django

Setelah selesai mulailah membuat proje t:

$ d wsgi
$ ../env/bin/django-admin.py startproje t myproje t

Lalu ubahlah $HOME/wsgi/wsgi_handler.py menjadi seperti ini:

Listing 16.4: wsgi_handler.py untuk Django

1 import os , sys
2
3 sys . stdout = sys . stderr
4 s y s . p a t h . append ( o s . p a t h . d i r n a m e ( o s . p a t h . a b s p a t h ( __file__ )
))
5 env_ver = ' . ' . j o i n ( map ( lambda x: str (x) , sys . version_info
[:2℄) )
6 env_path = o s . p a t h . d i r n a m e ( o s . p a t h . d i r n a m e ( o s . p a t h .
a b s p a t h ( __file__ ) ) ) + \
7 ' / e n v / l i b / p y t h o n%s / s i t e −p a k a g e s ' % env_ver
8 s y s . p a t h . append ( env_path )
9
10 o s . e n v i r o n [ 'DJANGO_SETTINGS_MODULE' ℄ = ' myproje t .
settings '
11 import django . ore . handlers . wsgi

6 http://djangoproje t. om
7 Python virtual environment otomatis terbentuk saat pembuatan domain.
BAB 16. HOSTING 140

12 a p p l i a t i o n = d j a n g o . o r e . h a n d l e r s . w s g i . WSGIHandler ( )
13
14 import monitor
15 monitor . s t a r t ( i n t e r v a l =1.0)

Kembali ke Firefox url http://reymanx.web.id, seharusnya tampil:

It worked!

Beberapa hal lain yang biasa digunakan user adalah:

ˆ Untuk pembuatan alias, misalnya untuk path /site_media/, bisa melalui


Virtualmin, yaitu menu Servi es, Congure Website, Aliases and Redi-
re ts. Isilah pada bagian Do ument dire tory aliases. Misalkan From diisi
/site_media/, dan To diisi /home/reymanx/wsgi/myproje t/site_media/.
Klik Save. Perubahan baru tersimpan saja, belum dilaksanakan. Untuk
pelaksanaannya klik Apply Changes di kanan atas.

ˆ Untuk mendaftarkan ron job (s heduler), masuk ke menu Webmin Mod-


ules, S heduled Cron Jobs.
ˆ Pendaftaran subdomain melalui menu Create Virtual Server.
Oh iya, sebenarnya juga tersedia Installer Django di sini. Namun tidak dis-
arankan karena masih menggunakan Fast CGI (konon yang terbaik menggu-
nakan WSGI seperti yang sudah diulas).
Template telah siap. Kini obalah mendaftarkan domain baru pada menu
Create Virtual Server. Setelah memasukkan Domain name dan Administration
password, pilih Python pada Server onguration template. Klik Create Server.
Kini obalah mengunjungi domain baru tersebut, seharusnya dijumpai pe-
san:

Hello World!

yang berasal dari le wsgi/wsgi_handler.py. Jika tadi Anda pilih Default Set-
tings pada Server onguration template, seharusnya Anda menjumpai pesan:
Forbidden

yang artinya Apa he mengharapkan le publi _html/index.php.

16.2 Google Apps


Bibliogra
[1℄ http://jabber.rab. o.id/os/web-admin-dengan-virtualmin

[2℄ http://jabber.rab. o.id/os/pas a-instalasi-linux

[3℄ http://ja obian.org/writing/pg-en oding-ubuntu

[4℄ https:// onvore. om/id-python/gathering-online-22-july-2011

[5℄ http:// ode.google. om/p/modwsgi/wiki/ReloadingSour eCode

141
Indeks
__name__, 35 integer, 11

ALTER TABLE, 50, 51 KDE, 6, 7


Android, 5 konsole, 6
apt-get install, 6
apt-get update, 6 length(), 56

autoin rement eld, 46 Linux, 5


lo ale-gen, 38
BlankOn, 6 lo altime(), 28
break, 14 lower(), 9
lpad(), 56
ontinue, 15
CREATE TABLE, 44 Ma , 5
CREATE VIEW, 52 mktime(), 29
reatedb, 43 modul datetime, 30
reateuser, 42 modul lo ale, 37
modul time, 28
Data Denition Language, 51
Data Manipulation Language, 51 nextval(), 47
date(), 30 None, 39
datestyle, 48 NOT NULL, 44
datetime(), 30
DEFAULT, 44 objek hampa, 39

DELETE FROM, 50 ORDER BY, 48

DROP TABLE, 51 ORDER BY, DESC, 49

dropdb, 43
pg_dump, 54
dropuser, 42
pg_restore, 54

epo h, 29 plpgsql, 6

eval(), 20 plpython, 6
postgresql. onf, 48
oat, 11 PRIMARY KEY, 44
for, 16 print, 9, 20
formatting, 17, 19 psql, 6, 43
fullpath, 54
rata kanan, 55
Gnome, 7 raw_input(), 10, 27

int(), 19, 27 sequen e, 46

142
INDEKS 143

serial, 46
sisa pembagian, 18
SQLAl hemy, 6
string, 9, 11
sudo, 42
Symbian, 5

text editor, 7
time(), 29
tipe data di tionary, 26
tipe data oat, 18
tipe data integer, 18
tipe data list, 20
transa tion, 72
transa tion, auto ommit, 72
type(), 17

Ubuntu, 6
Unix, 5
Unix time, 29
UPDATE, 50
upper(), 9

variabel, 11
vi, 7

while, 15

Anda mungkin juga menyukai