#08-Django CRUD

Tahapan

  1. Buat Project myapp
  2. Buat App orders
  3. Buat Model order
  4. Buat View(Controller)
  5. Buat Url(Route)

Masuk ke PowerShell/cmd/shellscript, masuk ke folder project myapp

Windows Powershell

Buat App orders

python manage.py startapp orders
├── myapp
├── orders
│   └── migrations
│   ├── _init_.py
│   └── admin.py
│   └── apps.py
│   └── models.py
│   └── tests.py
│   └── urls.py
│   └── views.py

Buat Model

from django.db import models

class Customer(models.Model):
	fullname = models.CharField(max_length=200)
	created_date = models.DateTimeField('created at')
	updated_at = models.DateTimeField('updated at')
	def __str__(self):
		return self.customer_name
	
class Order(models.Model):
    customer_id = models.ForeignKey(Customer, on_delete=models.CASCADE)
    price = models.IntegerField(max_length=200)
    created_date = models.DateTimeField('created at')
    updated_at = models.DateTimeField('updated at')
    def __str__(self):
        return self.price

Aktivasi Model

#mysite/settings.py
INSTALLED_APPS = [
    'orders.apps.OrdersConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

#07-Django Auth Login

Penjelasan

Sebelum nya kita telah membuat App “polls” menggunakan AdminLte, sekarang kita akan membuat App “pages” menggunakan AdminLTE. App akan berisi halaman Login, Welcome(harus dalam posisi login), dan Logout.

Sekenario

Jika authentikasi tidak terpenuhi, app akan mengarahkan ke page login, jika terpenuhi akan masuk ke halaman index, dan jika tombol logout di klik maka session akan direset dan user akan kembali ke halaman login

Membuat App pages:

python manage.py startapp pages

Views

pages/views.py

from django.shortcuts import get_object_or_404, render, redirect
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.contrib.auth import get_user_model

@login_required(login_url='/login')
def index(request):
	return render(request, 'pages/index.html')

def login_view(request):
	if request.method=='POST':
		User = get_user_model()
		email = request.POST['email']
		username = User.objects.get(email=email).username
		password =  request.POST['password']
		user = authenticate(username=username, password=password)
		if user is not None:
			login(request, user)
			return redirect("/")
		else:
			return render(request, 'pages/login.html', {})
	return render(request, 'pages/login.html')
def logout_view(request):
	logout(request)
	return redirect('/login')

Perhatikan baris def login_view dan logout_view yang ditandai, penamaan tidak boleh sama dengan lib login dan logout yang diimport karena akan bentrok dengan fungsi login dan logout.

Fungsi @login_required(login_url=’/login’) sebelum def index menandakan halaman tersebut dapat dibuka hanya jika kondisi authenticate terpenuhi.

Route

Edit file pages/urls.py

from django.urls import path
from . import views

urlpatterns = [
	path('', views.index, name='index'),
	path('login', views.login_view, name='login'),
	path('logout', views.logout_view, name='logout'),
]

Template Login:

buat file pages/templates/pages/login.html

<!DOCTYPE html>
<html>
<head>
    {% load static %}
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>AdminLTE 3 | Log in</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="{% static '/plugins/fontawesome-free/css/all.min.css">
  <link rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css' %}">
  <link rel="stylesheet" href="{% static '/plugins/icheck-bootstrap/icheck-bootstrap.min.css' %}">
  <link rel="stylesheet" href="{% static '/css/adminlte.min.css' %}">
  <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700" rel="stylesheet">
</head>
<body class="hold-transition login-page">
<div class="login-box">
  <div class="login-logo">
    <a href="login"><b>Admin</b>LTE</a>
  </div>
  <div class="card">
    <div class="card-body login-card-body">
      <p class="login-box-msg">Sign in to start your session</p>

      <form action="login" method="post">
         {% csrf_token %}
        <div class="input-group mb-3">
          <input type="email" name="email" class="form-control" placeholder="Email">
          <div class="input-group-append">
            <div class="input-group-text">
              <span class="fas fa-envelope"></span>
            </div>
          </div>
        </div>
        <div class="input-group mb-3">
          <input type="password" name="password" class="form-control" placeholder="Password">
          <div class="input-group-append">
            <div class="input-group-text">
              <span class="fas fa-lock"></span>
            </div>
          </div>
        </div>
        <div class="row">
          <div class="col-8">
            <div class="icheck-primary">
              <input type="checkbox" id="remember">
              <label for="remember">
                Remember Me
              </label>
            </div>
          </div>
          <div class="col-4">
            <button type="submit" class="btn btn-primary btn-block">Sign In</button>
          </div>
        </div>
      </form>

      <p class="mb-1">
        <a href="forgot-password.html">I forgot my password</a>
      </p>
      <p class="mb-0">
        <a href="register.html" class="text-center">Register a new membership</a>
      </p>
    </div>
  </div>
</div>
<script src="{% static '/plugins/jquery/jquery.min.js' %}"></script>
<script src="{% static '/plugins/bootstrap/js/bootstrap.bundle.min.js' %}"></script>
<script src="{% static '/js/adminlte.min.js' %}"></script>
</body>
</html>

Template Welcome

buat file pages/templates/pages/index.html

{% extends "base.html" %}
{% load static %} 
{% block content %}
<h1>Welcome</h1>
{% endblock %}

Struktur

├── myapp
├── pages
│   └── migrations
│   └── templates
|       ├── pages
│           ├── index.html
│           ├── login.html
│   ├── _init_.py
│   └── admin.py
│   └── apps.py
│   └── models.py
│   └── tests.py
│   └── urls.py
│   └── views.py

Testing

http://localhost:8000

Welcome Page

#06-Django Global Template & Static Folder

Jika sebelumnya kita membuat MTV dengan tampilan ala kadarnya, kali ini kita akan membuat tampilan yang menarik menggunakan AdminLTE3

Base Template merupakan html static yang nantinya akan digunakan untuk semua app, supaya tidak perlu ditulis berulang-ulang pada setiap app, kita akan menggunakan metode Base Template.

Buat folder static sesuai struktur sbb:

myapp/
├── myapp/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
│
├── polls
│   ├── migrations
│   ├── templates
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── static/ #static folder untuk staticfiles
├── templates/ #tempates folder untuk global templates
└── manage.py
Global templates folder

templates folder adalah folder untuk menyimpan template umum pada project, misal : base.html, sidebar.html, dll

Supaya nantinya base.html dapat dibaca melalui app, maka kita harus menambahkan setting berikut pada setting.py

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
Global Static Folder

static folder pada django adalah folder yang berisi file-file public yang kita gunakan untuk styling, di antaranya: js, css, images, dll.

Download AdminLTE3 disini

copy dist/* ke folder static
copy plugins ke folder static
copy index.html ke templates/base.html

lalu buka localhost/polls hasilnya seperti di bawah ini

Untuk memberi tahu kepada django bahwa kita akan menggunakan staticfiles yang ada pada folder static, maka kita harus merubah setting pada settings.py yang ada pada project django_blog kita.

Tambahkanlah setting berikut ini pada bagian bawah settings.py yang kita miliki

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'

# Extra places for collectstatic to find static files.
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

Selanjutnya, kita akan memanggil file-file static tersebut tersebut dalam template kita dengan cara:

{% static 'path/to/static/files' %}

Contoh :

<link rel="stylesheet" href="{% static '/plugins/fontawesome-free/css/all.min.css' %}">

Pada file base.html cari bagian section Main Content ubah isinya sbb :

<!-- Main content -->
    <section class="content">
        {% block content %}
            <!-- main content -->
        {% endblock %}
    </section>
    <!-- /.content -->

Hasilnya sbb :

AdminLTE3

Ganti Sidebar sesuai aplikasi Polls

Buat templates/sidebar.html

<nav class="mt-2">
    <ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">
      <!-- Add icons to the links using the .nav-icon class
           with font-awesome or any other icon font library -->
      <li class="nav-item has-treeview menu-open">
        <a href="#" class="nav-link active">
          <i class="nav-icon fas fa-tachometer-alt"></i>
          <p>
            Dashboard
            <i class="right fas fa-angle-left"></i>
          </p>
        </a>
        <ul class="nav nav-treeview">
          <li class="nav-item">
            <a href="{% url 'polls:index' %}" class="nav-link">
              <i class="far fa-circle nav-icon"></i>
              <p>Question</p>
            </a>
          </li>
        </ul>
      </li>
    </ul>
</nav>

Cari Sidebar Menu ubah baris sbb :

<!-- Sidebar Menu -->
   {% include "sidebar.html" %}
<!-- /.sidebar-menu -->

Hasilnya sbb :

Sidebar Question

#05-Django MTV

Kalau anda pernah menggunakan Framework MVC biasanya metode ini disebut Controller, tetapi kalau di sini fungsi Controller diletakan pada file views.py, mungkin ini perbedaan konsep MVC dengan MTV pada Django.

Contoh sederhana

View

Buat fungsi View pada polls/views.py, lalu tambahkan baris berikut :

def detail(request, question_id):
    return HttpResponse("You're looking at question %s." % question_id)

def results(request, question_id):
    response = "You're looking at the results of question %s."
    return HttpResponse(response % question_id)

def vote(request, question_id):
    return HttpResponse("You're voting on question %s." % question_id)

Buka file polls/ulrls.py, lalu tambahkan baris berikut :

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
    # ex: /polls/5/
    path('<int:question_id>/', views.detail, name='detail'),
    # ex: /polls/5/results/
    path('<int:question_id>/results/', views.results, name='results'),
    # ex: /polls/5/vote/
    path('<int:question_id>/vote/', views.vote, name='vote'),
]

Buka browser seperti gambar di bawah ini:

details
results
vote

Gambar di atas menunjukan bahwa views menampilkan text sesuai kode pada route urls.py dan views.py

Memanggil Model

Buka views.py Edit def index sbb:

from django.http import HttpResponse

from .models import Question

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    output = ', '.join([q.question_text for q in latest_question_list])
    return HttpResponse(output)

# Biarkan def di bawahnya (detail, results, vote)

Lalu lihat hasilnya

Memanggil Template

ubah def index polls/views.py

from django.http import HttpResponse
from django.template import loader

from .models import Question

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    template = loader.get_template('polls/index.html')
    context = {
        'latest_question_list': latest_question_list,
    }
    return HttpResponse(template.render(context, request))

# Biarkan def di bawahnya (detail, results, vote)

polls/templates/polls/index.html

{% if latest_question_list %}
    <ul>
    {% for question in latest_question_list %}
        <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>No polls are available.</p>
{% endif %}

Lihat hasilnya

view + template html
Shortcut: render() juga dapat dipersingkat sbb :
from django.shortcuts import render

from .models import Question

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    context = {'latest_question_list': latest_question_list}
    return render(request, 'polls/index.html', context)

Error Exeption

Buka kembali polls/template/detail.html lalu ubah isinya sbb :

<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>

choice in question.choice_set.all digunakan untuk memanggil keselurah isi Choice dengan question_id=question.id

Buka kembali polls/views.py lalu ubah fungsi detail sbb :

def detail(request, question_id):
    try:
        question = Question.objects.get(pk=question_id)
    except Question.DoesNotExist:
        raise Http404("Question does not exist")
    return render(request, 'polls/detail.html', {'question': question})

Perhatikan kode di atas, fungsi akan mencoba mendapatkan object yg dicari, jika object kosong maka akan menampilkan halaman error 404.

Error 404
Shortcut: get_object_or_404()

Selain menggunakan Exeption kita juga dapat menggunakan get_object_or_404()

Buka kembali polls/views.py lalu ubah fungsi detail sbb :

from django.shortcuts import get_object_or_404, render

from .models import Question
# ...
def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/detail.html', {'question': question})

Jika object kosong maka akan tampil Error 404

Trik menuliskan nama url pada template

Buka polls/urls.py tambahkan baris berikut:

from django.urls import path

from . import views

app_name="polls"
urlpatterns = [
    path('', views.index, name='index'),
    # ex: /polls/5/
    path('<int:question_id>/', views.detail, name='detail'),
    # ex: /polls/5/results/
    path('<int:question_id>/results/', views.results, name='results'),
    # ex: /polls/5/vote/
    path('<int:question_id>/vote/', views.vote, name='vote'),
]

Panggil dari polls/template/detail.html

{% if latest_question_list %}
    <ul>
    {% for question in latest_question_list %}
        <!--<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>-->
        <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>No polls are available.</p>
{% endif %}

Perhatikan kode yang di tandai di atas

#04-Django Dashboard Admin

Membuat user admin

python manage.py createsuperuser
Create super user

Menjalankan Development Server

python manage.py runserver

Buka http://localhost:8000/admin, lalu login menggunakan akun superuser yang telah dibuat

Halaman Login
Halaman Utama

Membuat poll app dapat dimodifikasi di dashboard admin

Buka polls/admin.py file, lalu edit seperti di bawah ini :

from django.contrib import admin

from .models import Question

admin.site.register(Question)

lalu buka kembali browser anda

Polls Question

Anda dapat melakukan fungsi CRUD pada module Question langsung pada dashboard admin

Saat membuka module Question anda akan mendapatkan tampilan sbb:

Untuk menampilkan nilai kolom tambahkan kode berikut pada class Question file model.py

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    def __str__(self):
        return self.question_text

Lihat kembali hasilnya:

Lakukan hal yang sama pada model Choice

#03-Django Membuat Aplikasi

Sebelumnya anda harus tau  perbedaan antara projek dan aplikasi? Sebuah aplikasi adalah aplikasi Jaringan yang melakukan sesuatu — misalnya, sebuah sistem Polls yang akan dibuat nanti. Sebuah proyek adalah kumpulan dari konfigurasi dan aplikasi-aplikasi untuk situs jaringan tertentu. Sebuah projek dapat mengandung banyak aplikasi. Sebuah aplikasi dapat di beberapa proyek.

Kondisi

  • Project myapp sudah dibuat

Aplikasi Polls(pooling)

Masih di direktori virtualenv sebelumnya new_version/myapp. Buat app polls dengan mengetikan perintah berikut :

python manage.py startapp polls
polls/
    __init__.py
    admin.py
    apps.py
    migrations/
        __init__.py
    models.py
    tests.py
    urls.py
    views.py

View

Buka file polls/views.py masukan kode python sbb:

from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world. You're at the polls index.")

Route

Buka file myapp/polls/urls.py masukan kode sbb:

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
]

Pada file myapp/urls.py masukan kode sbb :

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('polls/', include('polls.urls')),
    path('admin/', admin.site.urls),
]

Test

Kembali ke folder myapp Jalankan project dengan mengetik perintah sbb:

python manage.py runserver
Web Browser

Model

Pada Aplikasi Polls kita akan membuat 2 model yaitu Question dan Choice

  • Question memiliki 2 kolom question dan pub_date.
  • Choice memiliki 2 kolom choise dan vote

Buka file polls/model.py, masukan kode sbb:

from django.db import models

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

Activating Model

Tambahkan baris berikut pada myapp/settings.py

INSTALLED_APPS = [
    'polls.apps.PollsConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

Jalankan perintah berikut pada terminal

python manage.py makemigrations polls
polls/migrations/0001_initial.py
python manage.py sqlmigrate polls 0001

Migrate Model

python manage.py migrate

Buka database anda akan ada table baru seperti gambar berikut :

polls_choice & polls_question

Shell API

Masuk ke shell interactive python untuk berinteraksi dengan aplikasi polls

python manage.py shell
Python interactive shell

Create/Update

>>> from polls.models import Choice, Question  # Import model classes yang sudah dibuat.

# table Question kosong.
>>> Question.objects.all()
<QuerySet []>

# Membuat object Question baru.
# Import timezone untuk digunakan pada pub_date.
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

# Menyimpan object Question ke database menggunakan command save().
>>> q.save()

# Setelah disimpan q.akan memiliki id(auto increment).
>>> q.id
1

# Membaca kolom lain pada object yang disimpan.
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)

# Mengubah isi kolom, lalu ketik command save().
>>> q.question_text = "What's up?"
>>> q.save()

# objects.all() menampilkan isi keseluruhan table question.
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>
isi table polls_question

#02-Django Setting Database Mysql

Disini kita akan menggunakan database pada umumnya yaitu Mysql.

Kondisi:

  • Mysql server sudah diinstall
  • Database sudah dibuat dengan nama myapp_db
  • Dijalankan di Virtual Environment new_version yg sudah dibuat pada tutorial #01

Install Mysql Client

Buka terminal Masuk ke venv new_version lalu ketik perintah

pip install mysqlclient

Note: untuk pengguna Windows jika ada error “cl.exe” saat installasi ikuti langkah pada link berikut atau link berikut

Edit file new_version/myapp/myapp/setting.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'myapp_db',
        'USER': 'ombagoes',
        'PASSWORD': 'passwordanda',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}

Migrate Database Bawaan Django

Untuk menggunakan user auth bawaan Django, ketik perintah berikut

python manage.py migrate
Generate Table
Table di Database

Sampai disini setting database mysql sudah berhasil…

#01-Django Perkenalan & Installasi

Version List

OS Windows 10 Home 64bit
Python 3.8.2
Django 3.0.5

Mengapa Python??

Python merupakan bahasa pemrograman yang sangat populer saat ini, jika anda mengetik Programing Language terpopuler 2020, maka Python akan menempati peringkat nomer 1.

Django

Django merupakan salah satu Web Framework terpopuler untuk Python saat ini.

Installasi

Sebelum menginstall Django pastinya harus menginstall Python terlebih dahulu silakan masuk ke website nya install berdasarkan panduan OS masing-masing.

Setelah Python diinstal kita akan menyiapkan alat tambahan yaitu:

  1. Pip adalah sebuah tool yang akan kita gunakan untuk manajemen paket python. Termasuk juga menginstall Django
  2. Virtual Environment adalah sebuah tools yang digunakan untuk membuat sebuah wadah yang terisolasi dari dunia luar, sehingga masing-masing project dapat memiliki environment nya sendir-sendiri misal: Project A(Python 2.7, Django 1.7, Mysql 5.0) dan Project B( Python 3.8.2, Django 1.8, Mysql 5.5 )

Install Pip & Virtual Environment

Buka terminal (linux/Mac) atau command prompt (windows) dan ketikkan perintah dibawah ini.

easyinstall pip

Setelah pip terinstall, lalu install virtualenv

pip install virtualenv

Setelah selesai menginstal venv , buatlah direktori baru dan masuk ke direktori tersebut. Misal untuk contoh kasus diatas saya buat direktori seperti di bawah ini:

mkdir new_version

Inisialisasi venv ke folder new_version

python -m venv new_version
ls new_version

Akan ada file/foder env baru pada folder tsb(Include, Lib, Scripts, pyvenv.cfg).

Aktifkan venv untuk folder tsb:

new_version/Sripts/activate

Jika menggunakan Windows Powershell(“Run as Administrator”) lalu ketik command Set-ExecutionPolicy RemoteSigned.

venv new_version sedang aktif

Install Django

pip install django

Membuat Project

masuk ke direktori new_version, lalu buat project

cd new_version
django-admin startproject myapp

masuk ke direktori myapp, lalu Test jalankan program

cd myapp
python manage.py runserver

Buka web browser anda http://localhost:8000