---
Judul: ' PYTHON WEBDEV '
disqus: hackmd
---
{%hackmd @themes/dracula %}
# PYTHON WEB DEVELOPMENT
# NETDEV 2024
**Oleh Muhammad Alfian Alfarizi**
# Tentang Django
Django merupakan salah satu web frameworks yang berbasis pada python. Django merupakan sebuah inovasi alternatif dalam membuat aplikasi web dengan cepat dan efektif.Contoh aplikasi yang menggunakan Django diantaranya Pinterest, Instagram, Spotify, dan Dropbox.
# Mengapa Django?
- Menggunakan bahasa python yang mudah dimengerti.
- Pada pythonnya sendiri sudah ada packet handling yang memudahkan melakukan import modul dan package.
- Dapat melakukan development dengan cepat karena fungsi pada django sudah dihandle dan templatenya sudah tersedia, sehingga hanya butuh setup dan setting database sesuai keinginan.
- Mudah diterapkan untuk web sederhana maupun web yang kompleks
# Eksekusi Modul
# Modul 1 (Getting Started with Django)
**Install Semua tools yang diperlukan beserta dependensinya**
```bash!
alfiann@ubuntu:~ sudo apt install python3-virtualenv python3.8-venv python3-pip libreadline-gplv2-dev libncursesw5-dev libpq-dev python3-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev
```

**Memastikan python yang diinginkan sudah terinstall**
```bash!
alfiann@ubuntu:~ which python3
```

```bash!
alfiann@ubuntu:~ which pip
```

**Menampilkan paket python yang terinstall**
```bash!
alfiann@ubuntu:~ pip list
```

**Membuat directory untuk virtual environment**
```bash!
alfiann@ubuntu:~ mkdir Dev && cd Dev
```
![Uploading file..._csppijs40]()
**Membuat virtual environment**
```bash!
alfiann@ubuntu:~ python3 -m venv trydjango-1.11
```
**Masuk ke directory virtual environment**
```bash!
alfiann@ubuntu:~ cd trydjango-1.11/
```
**Aktivasi virtual environment**
```bash!
alfiann@ubuntu:~ source bin/activate
```
**Menampilkan paket python yang terinstall di Virtual Environment**
```bash!
(trydjango-1.11)$ pip list
```

Python yang terinstall di dalam virtual environment berbeda dengan yang terinstall di luar venv
**Instalasi Django**
```bash!
(trydjango-1.11)$ pip install django==1.11.*
```

**Install Wheel apabila belum di install(opsional)**
```bash!
(trydjango-1.11)$ pip install wheel
```

**Buat Projek baru pada direktori src**
```bash!
(trydjango-1.11)$ mkdir src && cd src
```
```bash!
(trydjango-1.11)$ django-admin startproject mywebsite .
```

# Struktur direktory project pada Django
**Membuat direktori yang diperlukan**
```bash!
(trydjango-1.11)$ mkdir mywebsite/settings/
```

```bash!
(trydjango-1.11)$ touch mywebsite/settings/__init__.py
```
```bash!
(trydjango-1.11)$ touch mywebsite/settings/base.py
```
```bash!
(trydjango-1.11)$ touch mywebsite/settings/production.py
```
```bash!
(trydjango-1.11)$ touch mywebsite/settings/local.py
```
**Copy mywebsite/settings.py file ke mywebsite/settings/base.py file**
```bash!
(trydjango-1.11)$ cp mywebsite/settings.py mywebsite/settings/base.py
```

**Edit base.py file**
```bash!
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
```
**Edit file mywebsite/settings/–init–.py**
```bash!
from .base import *
from .production import *
try:
from .local import *
except:
pass
```
**Install beberapa tools lain**
```bash!
(trydjango-1.11)$ pip install psycopg2
```

```bash!
(trydjango-1.11)$ pip install gunicorn
```

```bash!
(trydjango-1.11)$ pip install dj-database-url==0.4.2
```

```bash!
(trydjango-1.11)$ pip install django-crispy-forms==1.6.1
```

```bash!
(trydjango-1.11)$ pip install pillow
```

**Buat requirement.txt**
```bash!
(trydjango-1.11)$ pip freeze > requirements.txt
```

**Jalankan migration & buat superuser**
```bash!
(trydjango-1.11)$ python manage.py migrate
```

```bash!
(trydjango-1.11)$ python manage.py createsuperuser
```

**Jalankan server**
```bash!
(trydjango-1.11)$ python manage.py runserver
```

**Cek browser dengan 127.0.0.1:8080**

**Copy base.py ke local.py and production.py pada settings direktori**
```bash!
(trydjango-1.11)$ cp mywebsite/settings/base.py mywebsite/settings/local.py
```
```bash!
(trydjango-1.11)$ cp mywebsite/settings/base.py mywebsite/settings/production.py
```

**Edit file production.py**
```bash!
DEBUG = False
SECRET_KEY = "add random letter or number"
```
**Mulai Aplikasi Pertama**
```bash!
(trydjango-1.11)$ python manage.py startapp restaurants
```

# Struktur Direktori aplikasi Django
**Edit file views.py pada direktori restaurant**
```bash!
from django.http import HttpResponse
from django.shortcuts import render
def home(request):
return HttpResponse("hello")
```
**Edit file urls.py pada direktori mywebsite**
```bash!
from django.conf.urls import url
from django.contrib import admin
from restaurants.views import home
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', home),
]
```
**Test pada browser**

# Modul 2 (HTML dan Django)
# Render with HTML
**Edit file views.py pada direktori restaurant**
```bash!
from django.http import HttpResponse
from django.shortcuts import render
def home(request):
html_ = """<!DOCTYPE html>
<html lang=en>
<head>
<head/>
<body>
<h1>Hello world</h1>
<p>This is html coming trough</p>
</body>
</html>
"""
return HttpResponse(html_)
```
**Tes Browser**

# HTML using python variable
**Edit file views.py pada direktori restaurant**
```bash!
from django.http import HttpResponse
from django.shortcuts import render
def home(request):
html_var = 'f strings'
html_ = f"""<!DOCTYPE html>
<html lang=en>
<head>
<head/>
<body>
<h1>Hello world</h1>
<p>This is {html_var} coming trough</p>
</body>
</html>
"""
return HttpResponse(html_)
```
**Test Browser**

# Render with templates
**Buat direktori baru dan hmtl file**
```bash!
(trydjango-1.11)$ mkdir templates/
```
```bash!
(trydjango-1.11)$ touch templates/base.html
```

**Edit file templates/base.html**
```bash!
<!DOCTYPE html>
<html lang=en>
<head>
<head/>
<body>
<h1>
Hello world
</h1>
<p>
This is {html_var} coming trough
</p>
</body>
</html>
```
**Edit base.py pada direktori restaurant**
```bash!
TEMPLATES = [
'DIRS' : [os.path.join(BASE_DIR, 'templates')],
]
```
**Edit views.py inside pada direktori restaurants**
```bash!
from django.http import HttpResponse
from django.shortcuts import render
def home(request):
return render(request, "base.html", {})
```
**Edit mywebsite/settings/–init–.py**
```bash!
from .base import *
#from .production import *
#try:
# from .local import *
#except:
# pass
```
**Tes Browser**

# Render HTML templates using python variable
**Edit views.py dalam direktori restaurant**
```bash!
import random
from django.http import HttpResponse
from django.shortcuts import render
def home(request):
num = random.randint(0, 100000000)
return render(request, "base.html", {"html_var": True, "num": num})
```
**Edit templates/base.html file**
```bash!
<!DOCTYPE html>
<html lang=en>
<head>
<head/>
<body>
<h1>
Hello world
</h1>
<p>
This is {{ html_var }} coming trough
</p>
<p>
Random number is {{ num }}
</p>
</body>
</html>
```
**Tes Browser**

# Using context in Django templates
**Edit views.py dalam direktori restaurants**
```bash!
import random
from django.http import HttpResponse
from django.shortcuts import render
def home(request):
num = None
some_list = [
random.randint(0, 100000000),
random.randint(0, 100000000),
random.randint(0, 100000000)
]
condition_bool_item = False
if condition_bool_item:
num = random.randint(0, 100000000)
context = {
"num": num,
"some_list": some_list
}
return render(request, "base.html", context)
```
**Edit file templates/base.html**
```bash!
<!DOCTYPE html>
<html lang=en>
<head>
<head/>
<body>
<h1>
Hello world
</h1>
<p>
This is <code>{% verbatim %}{{ html_var }}{% endverbatim %}</code> coming trough
</p>
<p>
{% if num is not None %}
Random number is {{ num }}
{% endif %}
</p>
<p>
{% for some_item in some_list %}
{% if some_item|divisibleby:"2" %}
Even number
{% endif %}
{{ some_item }}<br/>
{% endfor %}
</p>
<p>
Some item is {{ some_item }}
</p>
</body>
</html>
```
**Tes Browser**

# Using template inheritance
**Buat file baru pada direktori template**
```bash!
(trydjango-1.11)$ touch templates/home.html
```
```bash!
(trydjango-1.11)$ touch templates/about.html
```
```bash!
(trydjango-1.11)$ touch templates/contact.html
```

**Edit urls.py dalam direktori mywebsite**
```bash!
from django.conf.urls import url
from django.contrib import admin
from restaurants.views import home, about, contact
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', home),
url(r'^about/$', about),
url(r'^contact/$', contact),
]
```
**Edit views.py dalam direktori restaurants**
```bash!
import random
from django.http import HttpResponse
from django.shortcuts import render
def home(request):
num = None
some_list = [
random.randint(0, 100000000),
random.randint(0, 100000000),
random.randint(0, 100000000)
]
condition_bool_item = False
if condition_bool_item:
num = random.randint(0, 100000000)
context = {
"num": num,
"some_list": some_list
}
return render(request, "home.html", context)
def about(request):
context = {
}
return render(request, "about.html", context)
def contact(request):
context = {
}
return render(request, "contact.html", context)
```
**Edit file templates/base.html**
```bash!
<!DOCTYPE html>
<html lang=en>
<head>
<title>{% block head_tittle %}SXD.com{% endblock head_tittle %}</title>
<head>
<body>
<h1>SXD.com</h1>
<a href="/">Home</a>
<a href="/about/">About</a>
<a href="/contact/">Contact</a>
<div class="container">
{% block content %}{% endblock content %}
</div>
</body>
</html>
```
**Edit file templates/home.html**
```bash!
{% extends "base.html" %}
{% block content %}
<h1>
Hello world
</h1>
<h3>
{{ block.super }}
</h3>
<p>
This is <code>{% verbatim %}{{ html_var }}{% endverbatim %}</code> coming trough
</p>
<p>
{% if num is not None %}
Random number is {{ num }}
{% endif %}
</p>
<p>
{% for some_item in some_list %}
{% if some_item|divisibleby:"2" %}
Even number
{% endif %}
{{ some_item }} <br/>
{% endfor %}
</p>
<p>
Some item is {{ some_item }}
</p>
{% endblock content %}
```
**Edit file templates/about.html**
```bash!
{% extends "base.html" %}
{% block head_tittle %}About || {{ block.super }}{% endblock head_tittle %}
{% block content %}
<p>About</p>
{% endblock %}
```
**Edit file templates/contact.html**
```bash!
{% extends "base.html" %}
{% block head_tittle %}Contact || {{ block.super }}{% endblock head_tittle %}
{% block content %}
<p>Contact</p>
{% endblock %}
```
**Test Browser**


# Using template tag
**Buat direktori baru dan file baru dalam direktori**
```bash!
(trydjango-1.11)$ mkdir templates/snippets/
```
```bash!
(trydjango-1.11)$ touch templates/snippets/nav.html
```
```bash!
(trydjango-1.11)$ touch templates/snippets/css.html
```
```bash!
(trydjango-1.11)$ touch templates/snippets/js.html
```
```bash!
(trydjango-1.11)$ touch templates/snippets/sidebar.html
```

**Edit file templates/base.html**
```bash!
<!DOCTYPE html>
<html lang=en>
<head>
<title>{% block head_tittle %}SXD.com{% endblock head_tittle %}</title>
{% include 'snippets/css.html' %}
<head>
<body>
{% include 'snippets/nav.html' %}
<div class="container">
{% block content %}{% endblock content %}
</div>
{% include 'snippets/js.html' %}
</body>
</html>
```
**Edit nav.html dalam direktori snippets**
```bash!
<div class="container">
<h1>SXD.com</h1>
<a href="/">Home</a>
<a href="/about/">About</a>
<a href="/contact/">Contact</a>
</div>
```
**Edit css.html dalam direktory snippets**
```bash!
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
```
**Edit js.html dalam direktory snippets**
```bash!
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
```
**Edit sidebar.html dalam direktori snippets**
```bash!
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>
```
**Tambahkan tag pada about.html**
```bash!
{% extends "base.html" %}
{% block head_tittle %}About || {{ block.super }}{% endblock head_tittle %}
{% block content %}
<h1>About</h1>
{% include 'snippets/sidebar.html' %}
{% endblock %}
```
**Tambahkan tag pada contact.html**
```bash!
{% extends "base.html" %}
{% block head_tittle %}Contact || {{ block.super }}{% endblock head_tittle %}
{% block content %}
<h1>Contact</h1>
{% include 'snippets/sidebar.html' %}
{% endblock %}
```
**Tes Browsing**

# Class Based Views
**Edit views.py inside of restaurants directory**
```bash!
import random
from django.http import HttpResponse
from django.shortcuts import render
from django.views import View
def home(request):
num = None
some_list = [
random.randint(0, 100000000),
random.randint(0, 100000000),
random.randint(0, 100000000)
]
condition_bool_item = False
if condition_bool_item:
num = random.randint(0, 100000000)
context = {
"num": num,
"some_list": some_list
}
return render(request, "home.html", context)
def about(request):
context = {
}
return render(request, "about.html", context)
def contact(request):
context = {
}
return render(request, "contact.html", context)
class ContactView(View):
def get(self, request, *args, **kwargs):
print(kwargs)
context = {
}
return render(request, "contact.html", context)
```
**Edit urls.py dalam direktory mywebsite**
```bash!
from django.conf.urls import url
from django.contrib import admin
from restaurants.views import home, about, contact, ContactView
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', home),
url(r'^about/$', about),
url(r'^contact/(?P<id>\d+)/$', ContactView.as_view()),
]
```
**Test Browser**


# Template View
**Edit views.py dalam direktori restaurants**
```bash!
import random
from django.http import HttpResponse
from django.shortcuts import render
from django.views import View
from django.views.generic import TemplateView
class HomeView(TemplateView):
template_name = 'home.html'
def get_context_data(self, *args, **kwargs):
context = super(HomeView, self).get_context_data(*args, **kwargs)
num = None
some_list = [
random.randint(0, 100000000),
random.randint(0, 100000000),
random.randint(0, 100000000)
]
condition_bool_item = False
if condition_bool_item:
num = random.randint(0, 100000000)
context = {
"num": num,
"some_list": some_list
}
return context
class AboutView(TemplateView):
template_name = 'about.html'
class ContactView(TemplateView):
template_name = 'contact.html'
```
**Edit urls.py dalam direktori mywebsite**
```bash!
from django.conf.urls import url
from django.contrib import admin
from restaurants.views import HomeView, AboutView, ContactView
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', HomeView.as_view()),
url(r'^about/$', AboutView.as_view()),
url(r'^contact/$', ContactView.as_view()),
]
```
# Remembering Things
# Remembering things with Models
**Buat Superuser baru**
```bash!
(trydjango-1.11)$ python manage.py createsuperuser
```

**Akses Django pada browser**


**Edit base.py pada direktori settings**
```bash!
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'restaurants',
]
```
**Edit models.py pada direktori restaurants**
```bash!
from django.db import models
class Restaurant(models.Model):
name = models.CharField(max_length=120)
location = models.CharField(max_length=120, null=True, blank=True)
```
**Lakukan Migrate restaurant models**
```bash!
(trydjango-1.11)$ python manage.py makemigrations
```
```bash!
(trydjango-1.11)$ python manage.py migrate
```
**Edit admin.py pada direktori restaurants**
```bash!
from django.contrib import admin
from .models import Restaurant
admin.site.register(Restaurant)
```
**Tes Browser**

**Edit nama modul pada file models.py**
```bash!
from django.db import models
class RestaurantLocation(models.Model):
name = models.CharField(max_length=120)
location = models.CharField(max_length=120, null=True, blank=True)
```
**Edit nama modul pada file admin.py**
```bash!
from django.contrib import admin
from .models import RestaurantLocation
admin.site.register(RestaurantLocation)
```
**Jalankan migrate setelah mengganti nama modul**
```bash!
(trydjango-1.11)$ python manage.py makemigrations
```
```bash!
(trydjango-1.11)$ python manage.py migrate
```

# More on Models field
**Edit models.py pada direktori restaurants**
```bash!
from django.db import models
class RestaurantLocation(models.Model):
name = models.CharField(max_length=120)
location = models.CharField(max_length=120, null=True, blank=True)
category = models.CharField(max_length=120, null=True, blank=True)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=False)
```
**Jalankan Migrate**
```bash!
(trydjango-1.11)$ python manage.py makemigrations
You are trying to add a non-nullable field 'timestamp' to restaurantlocation without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
Select an option: 1
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
Type 'exit' to exit this prompt
>>> timezone.now
Migrations for 'restaurants':
restaurants/migrations/0003_auto_20240313_0626.py
- Add field category to restaurantlocation
- Add field timestamp to restaurantlocation
```
```bash!
(trydjango-1.11)$ python manage.py migrate
```
**Tes Browser**

# Displaying saved data
**Edit views.py pada direktori restaurants**
```bash!
from django.http import HttpResponse
from django.shortcuts import render
from django.views import View
from django.views.generic import TemplateView
from .models import RestaurantLocation
def restaurants_listview(request):
template_name = 'restaurants/restaurants_list.html'
queryset = RestaurantLocation.objects.all()
context = {
"object_list": queryset
}
return render(request, template_name, context)
```
**Edit urls.py pada direktori mywebsite**
```bash!
from django.conf.urls import url
from django.contrib import admin
from django.views.generic import TemplateView
from restaurants.views import restaurants_listview
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', TemplateView.as_view(template_name='home.html')),
url(r'^restaurants/$', restaurants_listview),
url(r'^about/$', TemplateView.as_view(template_name='about.html')),
url(r'^contact/$', TemplateView.as_view(template_name='contact.html')),
]
```
**Tambahkan folder and file baru**
```bash!
(trydjango-1.11)$ mkdir -p restaurants/templates/restaurants
```
```bash!
(trydjango-1.11)$ touch restaurants/templates/restaurants/restaurants_list.html
```
**Edit restaurants_list.html**
```bash!
{% extends "base.html" %}
{% block head_tittle %}Restaurants | {{ block.super }}{% endblock head_tittle %}
{% block content %}
<h1>Restaurants List</h1>
<ul>
{% for obj in object_list %}
<li>{{ obj }} <br/>
{{ obj.name }} {{ obj.location }} {{ obj.category }} {{ obj.timestamp }} {{ obj.update }}</li>
{% endfor %}
</ul>
{% endblock %}
```
**Edit models.py pada direktori restaurants**
```bash!
from django.db import models
# Create your models here.
class RestaurantLocation(models.Model):
name = models.CharField(max_length=120)
location = models.CharField(max_length=120, null=True, blank=True)
category = models.CharField(max_length=120, null=True, blank=True)
timestamp = models.DateTimeField(auto_now=True)
update = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
```
**Jalankan Migrate**
```bash!
(trydjango-1.11)$ python manage.py makemigrations
```
```bash!
(trydjango-1.11)$ python manage.py migrate
```

**Tes Browser**

-------------------------------------------------------------
# Understanding QuerySets
**Akses Django Shell**
```bash!
(trydjango-1.11)$ python manage.py shell
Python 3.8.10 (default, Nov 22 2023, 10:22:35)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>
```
**Coba tampilkan data dalam database**
```bash!
>>> from restaurants.models import RestaurantLocation
>>> RestaurantLocation.objects.all()
<QuerySet [<RestaurantLocation: Restoran Sumber Dosa>]>
>>> for obj in RestaurantLocation.objects.all():
... print(obj.name)
...
Restoran Bapak Gatot
```

**Update Querysets**
```bash!
>>> qs = RestaurantLocation.objects.all()
>>> qs.filter(category__iexact='Restoran Sumber Dosa')
<QuerySet [<RestaurantLocation: djefry>]>
>>> qs.update(category='Rumah Makan Mewah')
```

**Coba untuk menambahkan restoran baru via shell**

**Filtering Data**
```bash!
>>> qs = RestaurantLocation.objects.filter(category__iexact='Warteg').exclude(name__icontains='Podomoro')
>>> qs.count()
1
>>> qs
<QuerySet [<RestaurantLocation: Bandung>]>
```

**Keluar dari Shell**
```bash!
>>> exit()
(trydjango-1.11)$
```
--------------
# Generic List View
**Edit views.py dalam direktori restaurants**
```bash!
from django.db.models import Q
from django.http import HttpResponse
from django.shortcuts import render
from django.views import View
from django.views.generic import TemplateView, ListView
from .models import RestaurantLocation
def restaurants_listview(request):
template_name = 'restaurants/restaurants_list.html'
queryset = RestaurantLocation.objects.all()
context = {
"object_list": queryset
}
return render(request, template_name, context)
class RestaurantListView(ListView):
def get_queryset(self):
slug = self.kwargs.get("slug")
if slug:
queryset = RestaurantLocation.objects.filter(
Q(category__iexact=slug) |
Q(category__icontains=slug)
)
else:
queryset = RestaurantLocation.objects.all()
return queryset
```
**Edit urls.py dalam direktori mywebsite**
```bash!
from django.conf.urls import url
from django.contrib import admin
from django.views.generic import TemplateView
from restaurants.views import (
restaurants_listview,
RestaurantListView,
)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', TemplateView.as_view(template_name='home.html')),
url(r'^restaurants/$', RestaurantListView.as_view()),
url(r'^restaurants/(?P<slug>\w+)/$', RestaurantListView.as_view()),
url(r'^about/$', TemplateView.as_view(template_name='about.html')),
url(r'^contact/$', TemplateView.as_view(template_name='contact.html')),
]
```
**Ubah nama restaurant_list.html**
```bash!
(trydjango-1.11)$ mv restaurants/tempalates/restaurants/restaurant_list.html restaurants/tempalates/restaurants/restaurantlocation_list.html
```

--------------
# Restaurant Profile Detail
**Edit views.py dalam direktori restaurants**
```bash!
from django.db.models import Q
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404
from django.views import View
from django.views.generic import TemplateView, ListView, DetailView
from .models import RestaurantLocation
def restaurants_listview(request):
template_name = 'restaurants/restaurants_list.html'
queryset = RestaurantLocation.objects.all()
context = {
"object_list": queryset
}
return render(request, template_name, context)
class RestaurantListView(ListView):
def get_queryset(self):
slug = self.kwargs.get("slug")
if slug:
queryset = RestaurantLocation.objects.filter(
Q(category__iexact=slug) |
Q(category__icontains=slug)
)
else:
queryset = RestaurantLocation.objects.all()
return queryset
class RestaurantDetailView(DetailView):
queryset = RestaurantLocation.objects.all()
def get_object(self, *args, **kwargs):
rest_id = self.kwargs.get('rest_id')
obj = get_object_or_404(RestaurantLocation, id=rest_id)
return obj
```
**Edit urls.py pada direktori mywebsite**
```bash!
from django.conf.urls import url
from django.contrib import admin
from django.views.generic import TemplateView
from restaurants.views import (
restaurants_listview,
RestaurantListView,
RestaurantDetailView,
)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', TemplateView.as_view(template_name='home.html')),
url(r'^restaurants/$', RestaurantListView.as_view()),
url(r'^restaurants/(?P<rest_id>\w+)/$', RestaurantDetailView.as_view()),
url(r'^about/$', TemplateView.as_view(template_name='about.html')),
url(r'^contact/$', TemplateView.as_view(template_name='contact.html')),
]
```
**Buat file baru pada restaurant template**
```bash!
(trydjango-1.11)$ touch restaurants/templates/restaurants/restaurantlocation_detail.html
```
**Edit file restaurantlocation_detail.html**
```bash!
{% extends "base.html" %}
{% block head_tittle %}Restaurants | {{ block.super }}{% endblock head_tittle %}
{% block content %}
<h1>{{ object.name }} <small> {{ object.category }}</small></h1>
<p>{{ object.location }}</p>
<p>{{ object.timestamp }}, Updated {{ object.update|timesince }} ago</p>
{% endblock %}
```

-----------------------
# SlugField & Unique Slug Generator
**Edit Models.py**
```bash!
from django.db import models
class RestaurantLocation(models.Model):
name = models.CharField(max_length=120)
location = models.CharField(max_length=120, null=True, blank=True)
category = models.CharField(max_length=120, null=True, blank=True)
timestamp = models.DateTimeField(auto_now=True)
update = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(unique=True, null=True, blank=True)
def __str__(self):
return self.name
@property
def title(self):
return self.name
```
**Jalankan Migrate**
```bash!
(trydjango-1.11)$ python manage.py makemigrations
```
```bash!
(trydjango-1.11)$ python manage.py migrate
```
**File baru pada direktori restaurants**
```bash!
(trydjango-1.11)$ touch restaurants/utils.py
```
**Edit utils.py pada direktori restaurants**
```bash!
import random
import string
from django.utils.text import slugify
def random_string_generator(size=10, chars=string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
def unique_slug_generator(instance, new_slug=None):
if new_slug is not None:
slug = new_slug
else:
slug = slugify(instance.title)
Klass = instance.__class__
qs_exists = Klass.objects.filter(slug=slug).exists()
if qs_exists:
new_slug = "{slug}-{randstr}".format(slug=slug, randstr=random_string_generator(size=4))
return unique_slug_generator(instance, new_slug=new_slug)
return slug
```
-----------------------------
# Signal for Unique Slug
**Edit models.py pada direktori restaurants**
```bash!
from django.db import models
from django.db.models.signals import pre_save, post_save
from .utils import unique_slug_generator
# Create your models here.
class RestaurantLocation(models.Model):
name = models.CharField(max_length=120)
location = models.CharField(max_length=120, null=True, blank=True)
category = models.CharField(max_length=120, null=True, blank=True)
timestamp = models.DateTimeField(auto_now=True)
update = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(unique=True, null=True, blank=True)
def __str__(self):
return self.name
@property
def title(self):
return self.name
def rl_pre_save_receiver(sender, instance, *args, **kwargs):
print("saving...")
print(instance.timestamp)
if not instance.slug:
instance.slug = unique_slug_generator(instance)
def rl_post_save_receiver(sender, instance, created, *args, **kwargs):
print('saved')
print(instance.timestamp)
instance.save()
pre_save.connect(rl_pre_save_receiver, sender=RestaurantLocation)
post_save.connect(rl_post_save_receiver, sender=RestaurantLocation)
```
**Tes Browser**

---------------------------
# Forms, View, Model, and more
# Slug as URL Params
**Edit urls.py pada direktori mywebsite**
```bash!
from django.conf.urls import url
from django.contrib import admin
from django.views.generic import TemplateView
from restaurants.views import (
restaurants_listview,
RestaurantListView,
RestaurantDetailView,
)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', TemplateView.as_view(template_name='home.html')),
url(r'^restaurants/$', RestaurantListView.as_view()),
url(r'^restaurants/(?P<slug>[\w-]+)/$', RestaurantDetailView.as_view()),
url(r'^about/$', TemplateView.as_view(template_name='about.html')),
url(r'^contact/$', TemplateView.as_view(template_name='contact.html')),
]
```
**Edit views.py pada direktori restaurants**
```bash!
from django.db.models import Q
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404
from django.views import View
from django.views.generic import TemplateView, ListView, DetailView
from .models import RestaurantLocation
def restaurants_listview(request):
template_name = 'restaurants/restaurants_list.html'
queryset = RestaurantLocation.objects.all()
context = {
"object_list": queryset
}
return render(request, template_name, context)
class RestaurantListView(ListView):
def get_queryset(self):
slug = self.kwargs.get("slug")
if slug:
queryset = RestaurantLocation.objects.filter(
Q(category__iexact=slug) |
Q(category__icontains=slug)
)
else:
queryset = RestaurantLocation.objects.all()
return queryset
class RestaurantDetailView(DetailView):
queryset = RestaurantLocation.objects.all()
```
**Edit restaurantlocation_list.html pada direktori restaurants/template**
```bash!
{% extends "base.html" %}
{% block head_tittle %}Restaurants | {{ block.super }}{% endblock head_tittle %}
{% block content %}
<h1>Restaurants List</h1>
<ul>
{% for obj in object_list %}
<li><a href="/restaurants/{{ obj.slug }}/">{{ obj }}</a><br/>
{{ obj.name }} {{ obj.location }} {{ obj.category }} {{ obj.timestamp }} {{ obj.update }}</li>
{% endfor %}
```
**Tes Broser**

**Akses 127.0.0.1:8000/restaurants**

------------------------------------
# Saving the Data Hard & Wrong Way
**Buat file forms.py pada direktori restaurants**
```bash!
from django import forms
class RestaurantCreateForm(forms.Form):
name = forms.CharField()
location = forms.CharField(required=False)
category = forms.CharField(required=False)
```
**Edit views.py**
```bash!
from django.db.models import Q
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.views.generic import ListView, DetailView
from .forms import RestaurantCreateForm
from .models import RestaurantLocation
def restaurant_createview(request):
if request.method == "GET":
print("get data")
if request.method == "POST":
print("post data")
print(request.POST)
title = request.POST.get("title")
location = request.POST.get("location")
category = request.POST.get("category")
obj = RestaurantLocation.objects.create(
title=title,
location=location,
category=category
)
return HttpResponseRedirect("/restaurants/")
template_name = 'restaurants/form.html'
context = {}
return render(request, template_name, context)
def restaurants_listview(request):
template_name = 'restaurants/restaurants_list.html'
queryset = RestaurantLocation.objects.all()
context = { "object_list": queryset }
return render(request, template_name, context)
class RestaurantListView(ListView):
def get_queryset(self):
slug = self.kwargs.get("slug")
if slug:
queryset = RestaurantLocation.objects.filter(
Q(category__iexact=slug) |
Q(category__icontains=slug)
)
else:
queryset = RestaurantLocation.objects.all()
return queryset
class RestaurantDetailView(DetailView):
queryset = RestaurantLocation.objects.all()
```
**Buat File form.html di dalam direktori restaurant**
```bash!
{% extends "base.html" %}
{% block head_title %}Add Restaurant | {{block.super}}{% endblock head_title %}
{% block content %}
<h1>Add Restaurant</h1>
<form>
<input type='text' name='title' placeholder="Restaurant"><br/>
<input type='text' name='location' placeholder="Location"><br/>
<input type='text' name='category' placeholder="Category"><br/>
<button type='submit'>Save</button>
</form>
{% endblock %}
```
**Edit urls.py pada direktory my website**
```bash!
from django.conf.urls import url
from django.contrib import admin
from django.views.generic import TemplateView
from restaurants.views import (
restaurants_listview,
RestaurantListView,
RestaurantDetailView,
)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', TemplateView.as_view(template_name='home.html')),
url(r'^restaurants/$', RestaurantListView.as_view()),
url(r'^restaurants/create/$', RestaurantListView.as_view()),
url(r'^restaurants/(?P<slug>[\w-]+)/$', RestaurantDetailView.as_view()),
url(r'^about/$', TemplateView.as_view(template_name='about.html')),
url(r'^contact/$', TemplateView.as_view(template_name='contact.html')),
]
```
**Edit utils.py pada direktori restaurants**
```bash!
import random
import string
from django.utils.text import slugify
DONT_USE = ['create']
def random_string_generator(size=10, chars=string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
def unique_slug_generator(instance, new_slug=None):
if new_slug is not None:
slug = new_slug
else:
slug = slugify(instance.title)
if slug in DONT_USE:
new_slug = "{slug}-{randstr}".format(
slug=slug,
randstr=random_string_generator(size=4)
)
return unique_slug_generator(instance, new_slug=new_slug)
Klass = instance.__class__
qs_exists = Klass.objects.filter(slug=slug).exists()
if qs_exists:
new_slug = "{slug}-{randstr}".format(
slug=slug,
randstr=random_string_generator(size=4))
return unique_slug_generator(instance, new_slug=new_slug)
return slug
```
**Tes Browser**


-----------------------
# The Power of Django Forms
**Edit file views.py**
```bash!
from django.db.models import Q
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.views.generic import ListView, DetailView
from .forms import RestaurantCreateForm
from .models import RestaurantLocation
def restaurant_createview(request):
form = RestaurantCreateForm(request.POST or None)
errors = None
if form.is_valid():
obj = RestaurantLocation.objects.create(
name = form.cleaned_data.get('name'),
location= form.cleaned_data.get('location'),
category = form.cleaned_data.get('category')
)
return HttpResponseRedirect("/restaurants/")
if form.errors:
errors = form.errors
template_name = 'restaurants/form.html'
context = {"form": form, "errors": errors}
return render(request, template_name, context)
def restaurants_listview(request):
template_name = 'restaurants/restaurants_list.html'
queryset = RestaurantLocation.objects.all()
context = { "object_list": queryset }
return render(request, template_name, context)
class RestaurantListView(ListView):
def get_queryset(self):
slug = self.kwargs.get("slug")
if slug:
queryset = RestaurantLocation.objects.filter(
Q(category__iexact=slug) |
Q(category__icontains=slug)
)
else:
queryset = RestaurantLocation.objects.all()
return queryset
class RestaurantDetailView(DetailView):
queryset = RestaurantLocation.objects.all()
```
**Edit file forms.html pada direktori templates restaurant**
```bash!
{% extends "base.html" %}
{% block head_title %}Add Restaurant | {{block.super}}{% endblock head_title %}
{% block content %}
<h1>Add Restaurant</h1>
{{ errors}}
<form method='POST'> {% csrf_token %}
{{ form.as_p }}
<button type='submit'>Save</button>
</form>
{% endblock %}
```
**Edit file form.py pada direktori src restaurants**
```bash!
from django import forms
class RestaurantCreateForm(forms.Form):
name = forms.CharField()
location = forms.CharField(required=False)
category = forms.CharField(required=False)
def clean_name(self):
name = self.cleaned_data.get("name")
if name == "Hello":
raise forms.ValidationError("Not a valid name")
return name
```
**Tes Browser**

-----------------------------------
# The Extra Power of Django Model Forms
**Edit file forms.py didalam direktori restaurants**
```bash!
from django import forms
from .models import RestaurantLocation
class RestaurantCreateForm(forms.Form):
name = forms.CharField()
location = forms.CharField(required=False)
category = forms.CharField(required=False)
def clean_name(self):
name = self.cleaned_data.get("name")
if name == "Hello":
raise forms.ValidationError("Not a valid name")
return name
class RestaurantLocationCreateForm(forms.ModelForm):
class Meta:
model = RestaurantLocation
fields = [
'name',
'location',
'category',
]
def clean_name(self):
name = self.cleaned_data.get("name")
if name == "Hello":
raise forms.ValidationError("Not a valid name")
return name
```
**Edit file form.html didalam direktori templas restaurants**
```bash!
{% extends "base.html" %}
{% block head_title %}Add Restaurant | {{block.super}}{% endblock head_title %}
{% block content %}
<h1>Add Restaurant</h1>
{% if form.errors %}
{{ form.errors }}
{% endif %}
<form method='POST'> {% csrf_token %}
{{ form.as_p }}
<button type='submit'>Save</button>
</form>
{% endblock %}
```
**Edit file views.py didalam direktori restaurants**
```bash!
from django.db.models import Q
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.views import View
from django.views.generic import TemplateView, ListView, DetailView, CreateView
from .forms import RestaurantCreateForm, RestaurantLocationCreateForm
from .models import RestaurantLocation
def restaurant_createview(request):
form = RestaurantCreateForm(request.POST or None)
errors = None
if form.is_valid():
form.save()
return HttpResponseRedirect("/restaurants/")
if form.errors:
errors = form.errors
template_name = 'restaurants/form.html'
context = {"form": form, "errors": errors}
return render(request, template_name, context)
def restaurants_listview(request):
template_name = 'restaurants/restaurants_list.html'
queryset = RestaurantLocation.objects.all()
context = { "object_list": queryset }
return render(request, template_name, context)
class RestaurantListView(ListView):
def get_queryset(self):
slug = self.kwargs.get("slug")
if slug:
queryset = RestaurantLocation.objects.filter(
Q(category__iexact=slug) |
Q(category__icontains=slug)
)
else:
queryset = RestaurantLocation.objects.all()
return queryset
class RestaurantDetailView(DetailView):
queryset = RestaurantLocation.objects.all()
class RestaurantCreateView(CreateView):
form_class = RestaurantLocationCreateForm
template_name = 'restaurants/form.html'
success_url = "/restaurants"
```
**Edit file urls.py didalam direktori mywebsite**
```bash!
from django.conf.urls import url
from django.contrib import admin
from django.views.generic import TemplateView
from restaurants.views import (
restaurants_listview,
RestaurantListView,
RestaurantDetailView,
RestaurantCreateView
)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', TemplateView.as_view(template_name='home.html')),
url(r'^restaurants/$', RestaurantListView.as_view()),
url(r'^restaurants/create/$', RestaurantCreateView.as_view()),
url(r'^restaurants/(?P<slug>[\w-]+)/$', RestaurantDetailView.as_view()),
url(r'^about/$', TemplateView.as_view(template_name='about.html')),
url(r'^contact/$', TemplateView.as_view(template_name='contact.html')),
]
```
**Tes Browser**

--------------------------------
# Simple Effective Validation
**Edit file forms.py di direktori restaurants**
```bash!
from django import forms
from .models import RestaurantLocation
from .validators import validate_category
class RestaurantCreateForm(forms.Form):
name = forms.CharField()
location = forms.CharField(required=False)
category = forms.CharField(required=False)
def clean_name(self):
name = self.cleaned_data.get("name")
if name == "Hello":
raise forms.ValidationError("Not a valid name")
return name
class RestaurantLocationCreateForm(forms.ModelForm):
category = forms.CharField(required=False, validators=[validate_category])
class Meta:
model = RestaurantLocation
fields = [
'name',
'location',
'category',
]
def clean_name(self):
name = self.cleaned_data.get("name")
if name == "Hello":
raise forms.ValidationError("Not a valid name")
return name
```
**Edit file form.html di direktori templates restaurants**
```bash!
{% extends "base.html" %}
{% block head_title %}Add Restaurant | {{block.super}}{% endblock head_title %}
{% block content %}
<h1>Add Restaurant</h1>
{% if form.errors.non_field_errors %}
{{ form.errors.non_field_errors }}
{% endif %}
<form method='POST'> {% csrf_token %}
{{ form.as_p }}
<button type='submit'>Save</button>
</form>
{% endblock %}
```
**Buat file validators.py di direktori restaurants**
```bash!
from django.core.exceptions import ValidationError
def validate_even(value):
if value %2 !=0:
raise ValidationError(
'%(value)s is not an even number',
params={'value':value},
)
def validate_email(value):
enail = value
if ".edu" in email:
raise ValidationError("We do not accept edu emails")
CATEGORIES = ['Mexican', 'Asian', 'American', 'Whatever']
def validate_category(value):
cat = value.capitalize()
if not value in CATEGORIES and not cat in CATEGORIES:
raise ValidationError(f"{value} not a valid category")
```
**Edit file models.py didalam direktori restaurants**
```bash!
from django.db import models
# Create your models here.
from django.db import models
from django.db.models.signals import pre_save, post_save
from .utils import unique_slug_generator
from .validators import validate_category
# Create your models here.
class RestaurantLocation(models.Model):
name = models.CharField(max_length=120)
location = models.CharField(max_length=120, null=True, blank=True)
category = models.CharField(max_length=120, null=True, blank=True, validators=[validate_category])
timestamp = models.DateTimeField(auto_now=True)
update = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(unique=True, null=True, blank=True)
def __str__(self):
return self.name
@property
def title(self):
return self.name
def rl_pre_save_receiver(sender, instance, *args, **kwargs):
instance.category = instance.category.capitalize()
if not instance.slug:
instance.slug = unique_slug_generator(instance)
#def rl_post_save_receiver(sender, instance, created, *args, **kwargs):
# print('saved')
# print(instance.timestamp)
# instance.save()
pre_save.connect(rl_pre_save_receiver, sender=RestaurantLocation)
#post_save.connect(rl_post_save_receiver, sender=RestaurantLocation)
```
**Jalankan Migrate**
```bash!
(trydjango-1.11)$ python manage.py makemigrations
```
```bash!
(trydjango-1.11)$ python manage.py migrate
```
**Akses lagi dan tambahkan name**

--------------
# Letting User own Data
**Edit models.py pada direktori restaurants**
```bash!
from django.db import models
# Create your models here.
from django.conf import settings
from django.db import models
from django.db.models.signals import pre_save, post_save
from .utils import unique_slug_generator
from .validators import validate_category
# Create your models here.
User = settings.AUTH_USER_MODEL
class RestaurantLocation(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=120)
location = models.CharField(max_length=120, null=True, blank=True)
category = models.CharField(max_length=120, null=True, blank=True, validators=[validate_category])
timestamp = models.DateTimeField(auto_now=True)
update = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(unique=True, null=True, blank=True)
def __str__(self):
return self.name
@property
def title(self):
return self.name
def rl_pre_save_receiver(sender, instance, *args, **kwargs):
instance.category = instance.category.capitalize()
if not instance.slug:
instance.slug = unique_slug_generator(instance)
#def rl_post_save_receiver(sender, instance, created, *args, **kwargs):
# print('saved')
# print(instance.timestamp)
# instance.save()
pre_save.connect(rl_pre_save_receiver, sender=RestaurantLocation)
#post_save.connect(rl_post_save_receiver, sender=RestaurantLocation)
```
**Jalankan perintah berikut**
```bash!
(trydjango-1.11)$ python manage.py shell
```
```bash!
>>>from django.contrib.auth import get_user_model
>>>User = get_user_model()
>>>User.objects.all()
>>>cfe_user = User.objects.get(id=1)
>>>cfe_user
>>>cfe_user.username
>>>cfe_user.email
>>>cfe_user.password
>>>cfe_user.is_active
>>>cfe_user.is_staff
>>>cfe_user
>>>obj = cfe_user
obj
>>>instance = cfe_user
instance
>>>instance.restaurantlocation_set.all()
instance.restaurantlocation_set.filter(category__iexact='Mexican')
>>>User.objects.all()
>>>User.objects.get(id=2)
>>>jm_user = User.objects.get(id=2)
>>>jm_user.restaurantlocation_set.all()
```
-----------------
# Associate User to Form Data in FBV
**Edit file views.py pada direktori restaurants**
```bash!
from django.db.models import Q
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.views import View
from django.views.generic import TemplateView, ListView, DetailView, CreateView
from .forms import RestaurantCreateForm, RestaurantLocationCreateForm
from .models import RestaurantLocation
def restaurant_createview(request):
form = RestaurantCreateForm(request.POST or None)
errors = None
if form.is_valid():
if request.user.is_authenticated():
instance = form.save(commit=False)
instance.owner = request.user
instance.save()
return HttpResponseRedirect("/restaurants/")
else:
return HttpResponseRedirect("/login/")
if form.errors:
errors = form.errors
template_name = 'restaurants/form.html'
context = {"form": form, "errors": errors}
return render(request, template_name, context)
def restaurants_listview(request):
template_name = 'restaurants/restaurants_list.html'
queryset = RestaurantLocation.objects.all()
context = { "object_list": queryset }
return render(request, template_name, context)
class RestaurantListView(ListView):
def get_queryset(self):
slug = self.kwargs.get("slug")
if slug:
queryset = RestaurantLocation.objects.filter(
Q(category__iexact=slug) |
Q(category__icontains=slug)
)
else:
queryset = RestaurantLocation.objects.all()
return queryset
class RestaurantDetailView(DetailView):
queryset = RestaurantLocation.objects.all()
class RestaurantCreateView(CreateView):
form_class = RestaurantLocationCreateForm
template_name = 'restaurants/form.html'
success_url = "/restaurants"
```
**Edit file urls.py pada direktori mywebsite**
```bash!
from django.conf.urls import url
from django.contrib import admin
from django.views.generic import TemplateView
from restaurants.views import (
restaurant_createview,
restaurants_listview,
RestaurantListView,
RestaurantDetailView,
RestaurantCreateView
)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', TemplateView.as_view(template_name='home.html')),
url(r'^restaurants/$', RestaurantListView.as_view()),
url(r'^restaurants/create/$', restaurant_createview ), #RestaurantCreateView.as_view()),
url(r'^restaurants/(?P<slug>[\w-]+)/$', RestaurantDetailView.as_view()),
url(r'^about/$', TemplateView.as_view(template_name='about.html')),
url(r'^contact/$', TemplateView.as_view(template_name='contact.html')),
]
```
**Tes Browser**

------------------------
# Login Required to View
**Edit file base.py pada direktori mywebsite/settings**
```bash!
ROOT_URLCONF = 'mywebsite.urls'
LOGIN_URL = '/login/'
```
**Edit file urls.py pada direktori mywebsite**
```bash!
from django.conf.urls import url
from django.contrib import admin
from django.views.generic import TemplateView
from restaurants.views import (
restaurant_createview,
restaurants_listview,
RestaurantListView,
RestaurantDetailView,
RestaurantCreateView
)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', TemplateView.as_view(template_name='home.html')),
url(r'^restaurants/$', RestaurantListView.as_view()),
url(r'^restaurants/create/$', RestaurantCreateView.as_view()),
# url(r'^restaurants/(?P<slug>[\w-]+)/$', RestaurantDetailView.as_view()),
url(r'^about/$', TemplateView.as_view(template_name='about.html')),
url(r'^contact/$', TemplateView.as_view(template_name='contact.html')),
]
```
**Edit file views.py pada direktori restaurants**
```bash!
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Q
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.views import View
from django.views.generic import TemplateView, ListView, DetailView, CreateView
from .forms import RestaurantCreateForm, RestaurantLocationCreateForm
from .models import RestaurantLocation
@login_required(login_url='/login/')
def restaurant_createview(request):
form = RestaurantCreateForm(request.POST or None)
errors = None
if form.is_valid():
if request.user.is_authenticated():
instance = form.save(commit=False)
instance.owner = request.user
instance.save()
return HttpResponseRedirect("/restaurants/")
else:
return HttpResponseRedirect("/login/")
if form.errors:
errors = form.errors
template_name = 'restaurants/form.html'
context = {"form": form, "errors": errors}
return render(request, template_name, context)
def restaurants_listview(request):
template_name = 'restaurants/restaurants_list.html'
queryset = RestaurantLocation.objects.all()
context = { "object_list": queryset }
return render(request, template_name, context)
class RestaurantListView(ListView):
def get_queryset(self):
slug = self.kwargs.get("slug")
if slug:
queryset = RestaurantLocation.objects.filter(
Q(category__iexact=slug) |
Q(category__icontains=slug)
)
else:
queryset = RestaurantLocation.objects.all()
return queryset
class RestaurantDetailView(DetailView):
queryset = RestaurantLocation.objects.all()
class RestaurantCreateView(LoginRequiredMixin, CreateView):
form_class = RestaurantLocationCreateForm
login_url = '/login/'
template_name = 'restaurants/form.html'
success_url = "/restaurants"
def form_valid(self, form):
instance = form.save(commit=False)
instance.owner = self.request.user
return super(RestaurantCreateView, self).form_valid(form)
```
**Tes Browser dengan metode Incognito**


-------------------
# Login View
**Buat file template login.html pada direktori registration**
```bash!
(trydjango-1.11) ubuntu@ubunu2004:~/Dev/trydjango-1.11/src$ cd templates/
```
```bash!
(trydjango-1.11) ubuntu@ubunu2004:~/Dev/trydjango-1.11/src/templates$ mkdir registration
```
```bash!
(trydjango-1.11) ubuntu@ubunu2004:~/Dev/trydjango-1.11/src/templates$ cd registration/
```
```bash!
(trydjango-1.11) ubuntu@ubunu2004:~/Dev/trydjango-1.11/src/templates/registration$ touch login.html
```

**Edit file login.html**
```bash!
{% extends "base.html" %}
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
{% if next %}
{% if user.is_authenticated %}
<p>Your account doesn't have access to this page. To proceed,
please login with an account that has access.</p>
{% else %}
<p>Please login to see this page.</p>
{% endif %}
{% endif %}
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>
<tr>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
</tr>
<tr>
<td>{{ form.password.label_tag }}</td>
<td>{{ form.password }}</td>
</tr>
</table>
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
{# Assumes you setup the password_reset view in your URLconf #}
{% endblock %}
```
**Edit file urls.py pada direktori mywebsite**
```bash!
from django.conf.urls import url
from django.contrib import admin
from django.views.generic import TemplateView
from django.contrib.auth.views import LoginView
from restaurants.views import (
restaurant_createview,
restaurants_listview,
RestaurantListView,
RestaurantDetailView,
RestaurantCreateView
)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', TemplateView.as_view(template_name='home.html')),
url(r'^login/$', LoginView.as_view(), name='login'),
url(r'^restaurants/$', RestaurantListView.as_view()),
url(r'^restaurants/create/$', RestaurantCreateView.as_view()),
# url(r'^restaurants/(?P<slug>[\w-]+)/$', RestaurantDetailView.as_view()),
url(r'^about/$', TemplateView.as_view(template_name='about.html')),
url(r'^contact/$', TemplateView.as_view(template_name='contact.html')),
]
```
**Tes Browser ke 127.0.0.1:8000/restaurant/create di browser incognito. Nantinya diarahkan ke page login, setelah login, baru bisa menambahkan restaurant**


----------------------
# Using Reverse to Shortcut URLS
**Edit file restaurantlocation_list.html pada direktori restaurants/templates/restaurants**
```bash!
{% extends "base.html" %}
{% block head_title %}Restaurants | {{ block.super }}{% endblock head_title %}
{% block content %}
<h1>Restaurants List</h1>
<ul>
{% for obj in object_list %}
<li><a href='{{ obj.get_absolute_url }}'>{{ obj }}</a><br/>
{{ obj.name }} {{ obj.location }} {{ obj.category }} {{ obj.timestamp }}
</li>
{% endfor %}
</ul>
{% endblock %}
```
**Buat file urls.py pada direktori restaurants**
```bash!
---
from django.conf.urls import url
from .views import (
RestaurantListView,
RestaurantDetailView,
RestaurantCreateView
)
urlpatterns = [
url(r'^$', RestaurantListView.as_view(), name='list'),
url(r'^create/$', RestaurantCreateView.as_view(), name='create'),
url(r'^(?P<slug>[\w-]+)/$', RestaurantDetailView.as_view(), name='detail'),
]
```
**Edit file urls.py di dalam direktori mywebsite**
```bash!
from django.conf.urls import url, include
from django.contrib import admin
from django.views.generic import TemplateView
from django.contrib.auth.views import LoginView
from restaurants.views import (
restaurant_createview,
restaurants_listview,
RestaurantListView,
RestaurantDetailView,
RestaurantCreateView
)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'),
url(r'^login/$', LoginView.as_view(), name='login'),
url(r'^restaurants/', include('restaurants.urls', namespace='restaurants')),
url(r'^about/$', TemplateView.as_view(template_name='about.html'), name='about'),
url(r'^contact/$', TemplateView.as_view(template_name='contact.html'), name='contact'),
]
```
**Edit file nav.html pada direktori templates/snippets**
```bash!
<div class="container">
<h1>mcxxkim.com</h1>
<a href='{% url "home" %}'>Home</a>
<a href='{% url "about" %}'>About</a>
<a href='{% url "contact" %}'>Contact</a>
<a href='{% url "restaurants:list" %}'>Restaurants</a>
</div>
```
**Edit file models.py di dalam direktori restaurants**
```bash!
from django.db import models
# Create your models here.
from django.conf import settings
from django.db import models
from django.db.models.signals import pre_save, post_save
from django.core.urlresolvers import reverse
from .utils import unique_slug_generator
from .validators import validate_category
# Create your models here.
User = settings.AUTH_USER_MODEL
class RestaurantLocation(models.Model):
owner = models.ForeignKey(User)
name = models.CharField(max_length=120)
location = models.CharField(max_length=120, null=True, blank=True)
category = models.CharField(max_length=120, null=True, blank=True, validators=[validate_category])
timestamp = models.DateTimeField(auto_now=True)
update = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(unique=True, null=True, blank=True)
def __str__(self):
return self.name
def get_absolute_url(self):
# return f"/restaurants/{self.slug}"
return reverse('restaurants:detail', kwargs={'slug': self.slug})
@property
def title(self):
return self.name
def rl_pre_save_receiver(sender, instance, *args, **kwargs):
instance.category = instance.category.capitalize()
if not instance.slug:
instance.slug = unique_slug_generator(instance)
#def rl_post_save_receiver(sender, instance, created, *args, **kwargs):
# print('saved')
# print(instance.timestamp)
# instance.save()
pre_save.connect(rl_pre_save_receiver, sender=RestaurantLocation)
#post_save.connect(rl_post_save_receiver, sender=RestaurantLocation)
```
**Akses 127.0.0.1:8000 pada browser dengan akses satu persatu navbar (Home, About. Contact, Restaurant)**

-------------------
# Menu Items App
**Buat menus**
```bash!
from django.conf import settings
from django.db import models
from restaurants.models import RestaurantLocation
class Item(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
restaurant = models.ForeignKey(RestaurantLocation)
name = models.CharField(max_length=120)
contents = models.TextField(help_text='Separate each item by comma')
excludes = models.TextField(blank=True, null=True, help_text='Separate each item by comma')
public = models.BooleanField(default=True)
timestamp = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-updated', '-timestamp']
def get_contents(self):
return self.contents.split(",")
def get_excludes(self):
return self.excludes.split(",")
```
**Edit file base.py di dalam direktori mywebsite/settings. Tambahkan menus di bagian INSTALLED_APPS**
```bash!
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'menus',
'restaurants',
]
```
**Edit file admin.py pada direktori menus**
```bash!
from django.contrib import admin
from .models import Item
admin.site.register(Item)
```
**Jalankan Migrate**
```bash!
python manage.py makemigrations
```
```bash!
python manage.py migrate
```
**Indikator keberhasilannya adalah ketika Add Items berhasil**
------------------
# Menu Items Views
**Edit file views.py pada menus**
```bash!
from django.shortcuts import render
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from .forms import ItemForm
from .models import Item
class ItemListView(ListView):
def get_queryset(self):
return Item.objects.filter(user=self.request.user)
class ItemDetailView(DetailView):
def get_queryset(self):
return Item.objects.filter(user=self.request.user)
class ItemCreateView(CreateView):
template_name = 'form.html'
form_class = ItemForm
def form_valid(self, form):
obj = form.save(commit=False)
obj.user = self.request.user
return super(ItemCreateView, self).form_valid(form)
def get_queryset(self):
return Item.objects.filter(user=self.request.user)
def get_context_data(self, *args, **kwargs):
context = super(ItemCreateView, self).get_context_data(*args, **kwargs)
context['title'] = 'Create Item'
return context
class ItemUpdateView(UpdateView):
template_name = 'form.html'
form_class = ItemForm
def get_queryset(self):
return Item.objects.filter(user=self.request.user)
def get_context_data(self, *args, **kwargs):
context = super(ItemUpdateView, self).get_context_data(*args, **kwargs)
context['title'] = 'Update Item'
return context
```
**Buat file forms.py di dalam direktori menus dan edit filenya**
```bash!
from django import forms
from .models import Item
class ItemForm(forms.ModelForm):
class Meta:
model = Item
fields = [
'restaurant',
'name',
'contents',
'excludes',
'public',
]
```
----------------------
# Limiting Form Field to QuerySet
```bash!
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from .forms import ItemForm
from .models import Item
class ItemListView(ListView):
def get_queryset(self):
return Item.objects.filter(user=self.request.user)
class ItemDetailView(DetailView):
def get_queryset(self):
return Item.objects.filter(user=self.request.user)
class ItemCreateView(CreateView):
template_name = 'form.html'
form_class = ItemForm
def form_valid(self, form):
obj = form.save(commit=False)
obj.user = self.request.user
return super(ItemCreateView, self).form_valid(form)
def get_form_kwargs(self):
kwargs = super(ItemCreateView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def get_queryset(self):
return Item.objects.filter(user=self.request.user)
def get_context_data(self, *args, **kwargs):
context = super(ItemCreateView, self).get_context_data(*args, **kwargs)
context['title'] = 'Create Item'
return context
class ItemUpdateView(LoginRequiredMixin, UpdateView):
template_name = 'form.html'
form_class = ItemForm
def get_queryset(self):
return Item.objects.filter(user=self.request.user)
def get_context_data(self, *args, **kwargs):
context = super(ItemUpdateView, self).get_context_data(*args, **kwargs)
context['title'] = 'Update Item'
return context
```
**Edit file forms.py pada direktori menus**
```bash!
from django import forms
from .models import Item
from restaurants.models import RestaurantLocation
class ItemForm(forms.ModelForm):
class Meta:
model = Item
fields = [
'restaurant',
'name',
'contents',
'excludes',
'public',
]
def __init__(self, user=None, *args, **kwargs):
print(user)
print(kwargs)
super(ItemForm, self).__init__(*args,**kwargs)
self.fields['restaurant'].queryset = RestaurantLocation.objects.filter(owner=user).exclude(item__isnull=False)
```
**Edit file urls.py pada direktori menus**
```bash!
from django.conf.urls import url
from .views import (
ItemCreateView,
ItemDetailView,
ItemListView,
ItemUpdateView,
)
urlpatterns = [
url(r'^create/$', ItemCreateView.as_view(), name='create'),
url(r'^(?P<pk>\d+)/edit/$', ItemUpdateView.as_view(), name='update'),
url(r'^(?P<pk>\d+)/$', ItemDetailView.as_view(), name='detail'),
url(r'$', ItemListView.as_view(), name='List'),
]
```
**Tes Broser 127.0.0.1:8000/items/1/edit di browser maka anda berhasil**
-----------------
# Personalize Items
**Edit file views.py pada direktori restaurants**
```bash!
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Q
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.views import View
from django.views.generic import TemplateView, ListView, DetailView, CreateView, UpdateView
from .forms import RestaurantCreateForm, RestaurantLocationCreateForm
from .models import RestaurantLocation
class RestaurantListView(LoginRequiredMixin, ListView):
def get_queryset(self):
return RestaurantLocation.objects.filter(owner=self.request.user)
class RestaurantDetailView(LoginRequiredMixin, DetailView):
def get_queryset(self):
return RestaurantLocation.objects.filter(owner=self.request.user)
class RestaurantCreateView(LoginRequiredMixin, CreateView):
form_class = RestaurantLocationCreateForm
login_url = '/login/'
template_name = 'form.html'
#success_url = "/restaurants/"
def form_valid(self, form):
instance = form.save(commit=False)
instance.owner = self.request.user
return super(RestaurantCreateView, self).form_valid(form)
def get_context_data(self, *args, **kwargs):
context = super(RestaurantCreateView, self).get_context_data(*args, **kwargs)
context['title'] = 'Add Restaurant'
return context
class RestaurantUpdateView(LoginRequiredMixin, UpdateView):
form_class = RestaurantLocationCreateForm
login_url = '/login/'
template_name = 'restaurants/detail-update.html'
#success_url = "/restaurants/"
def get_context_data(self, *args, **kwargs):
context = super(RestaurantUpdateView, self).get_context_data(*args, **kwargs)
name = self.get_object().name
context['title'] = f'Update Restaurant: {name}'
return context
def get_queryset(self):
return RestaurantLocation.objects.filter(owner=self.request.user)
```
**Edit file urls.py pada direktori restaurants**
```bash!
from django.conf.urls import url
from .views import (
RestaurantListView,
RestaurantDetailView,
RestaurantCreateView,
RestaurantUpdateView
)
urlpatterns = [
url(r'^create/$', RestaurantCreateView.as_view(), name='create'),
# url(r'^(?P<slug>[\w-]+)/edit/$', RestaurantUpdateView.as_view(), name='edit'),
url(r'^(?P<slug>[\w-]+)/$', RestaurantUpdateView.as_view(), name='detail'),
url(r'$', RestaurantListView.as_view(), name='list'),
]
```
**Edit file urls.py di dalam direktori menus**
```bash!
from django.conf.urls import url
from .views import (
ItemCreateView,
ItemDetailView,
ItemListView,
ItemUpdateView,
)
urlpatterns = [
url(r'^create/$', ItemCreateView.as_view(), name='create'),
# url(r'^(?P<pk>\d+)/edit/$', ItemUpdateView.as_view(), name='edit'),
url(r'^(?P<pk>\d+)/$', ItemUpdateView.as_view(), name='detail'),
url(r'$', ItemListView.as_view(), name='list'),
]
```
**Edit nav.html pada direktori templates/snippets**
```bash!
<div class="container">
<h1>mcxxkim.com</h1>
<a href='{% url "home" %}'>Home</a>
<a href='{% url "about" %}'>About</a>
<a href='{% url "contact" %}'>Contact</a>
{% if request.user.is_authenticated %}
<a href='{% url "restaurants:list" %}'>Restaurants</a>
<a href='{% url "menus:list" %}'>Menu Items</a>
{% endif %}
</div>
```
**Buat file baru**
```bash!
touch restaurants/templates/restaurants/form.html
```
```bash!
touch restaurants/templates/restaurants/detail-update.html
```
```bash!
touch templates/menus/detail-update.html
```
```bash!
touch templates/snippets/form-snippets.html
```
**Edit form.html**
```bash!
{% extends "base.html" %}
{% block head_title %}{{ title }} | {{block.super}}{% endblock head_title %}
{% block content %}
<h1>{{ title }}</h1>
{% if form.errors.non_field_errors %}
{{ form.errors.non_field_errors }}
{% endif %}
<form method='POST'> {% csrf_token %}
{{ form.as_p }}
<button type='submit'>Save</button>
</form>
{% endblock %}
```
**Edit detail-update.html**
```bash!
{% extends "base.html" %}
{% block head_title %}{{ form.instance.title }} | Restaurants | {{ block.super }}{% end>
{% block content %}
<h1>{{ form.instance.title }} <small> {{ form.instance.category }}</small></h1>
<p>{{ form.instance.location }}</p>
<p>{{ form.instance.timestamp }}, Updated {{ form.instance.updated|timesince }} ago</p>
<hr/>
<h3>Make Changes</h3>
{% include 'snippets/form-snippets.html' with form=form %}
</div>
</div>
{% endblock %}
```
**Edit form-snippets.html**
```bash!
{% if form.errors.non_field_errors %}
{{ form.errors.non_field_errors }}
{% endif %}
<form method='POST'> {% csrf_token %}
{{ form.as_p }}
<button type='submit'>Save</button>
</form>
```
**Tes Browser. Apabila bisa mengubah atau menambah items pada restaurant artinya konfigurasi sudah berhasil**
--------------------
# User Profil View
**Jalankan Profil**
```bash!
python manage.py startapp profiles
```
**Edit views.py pada direktori profiles**
```bash!
from django.contrib.auth import get_user_model
from django.http import Http404
from django.shortcuts import render, get_object_or_404
from django.views.generic import DetailView
User = get_user_model()
class ProfileDetailView(DetailView):
template_name = 'profiles/user.html'
def get_object(self):
username = self.kwargs.get("username")
if username is None:
raise Http404
return get_object_or_404(User, username__iexact=username, is_active=True)
```
**Buat file urls.py pada direktori profiles dan edit filenya**
```bash!
touch profiles/urls.py
```
```bash!
nano profiles/urls.py
```
```bash!
from django.conf.urls import url
from .views import ProfileDetailView
urlpatterns = [
url(r'^(?P<username>[\w-]+)/$', ProfileDetailView.as_view(), name='detail'),
]
```
**Edit file urls.py pada direktori mywebsite**
```bash!
from django.conf.urls import url, include
from django.contrib import admin
from django.views.generic import TemplateView
from django.contrib.auth.views import LoginView
from restaurants.views import (
RestaurantListView,
RestaurantDetailView,
RestaurantCreateView
)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'),
url(r'^login/$', LoginView.as_view(), name='login'),
url(r'^u/', include('profiles.urls', namespace='profiles')),
url(r'^items/', include('menus.urls', namespace='menus')),
url(r'^restaurants/', include('restaurants.urls', namespace='restaurants')),
url(r'^about/$', TemplateView.as_view(template_name='about.html'), name='about'),
url(r'^contact/$', TemplateView.as_view(template_name='contact.html'), name='contact'),
]
```
**Edit file base.py pada direktori mywebsite/settings**
```bash!
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'menus',
'profile',
'restaurants',
]
```
**Buat direktori /profiles di dalam templates, dan buat file baru dalam direktori templates/profiles bernama user.html dan edit.**
```bash!
mkdir templates/profiles
```
```bash!
touch templates/profiles/user.html
```
```bash!
nano templates/profiles/user.html
```
```bash!
{% extends "base.html" %}
{% block head_title %}{{ user.username }} | {{ block.super }}{% endblock head_title %}
{% block content %}
<h1>{{ user.username }}</h1>
<hr/>
{% if user.restaurantlocation_set.all %}
{% for rest in user.restaurantlocation_set.all %}
<li><b>{{ rest.title }}</b> {{ rest.location }} | {{ rest.category }}</li>
<p>
<b>Items</b>
<ul>
{% for item in rest.item_set.all %}
<li style='margin-bottom: 15px;'>{{ item.name }}<br/>
{% for ing in item.get_contents %}
<span style='padding: 2px 4px; margin-right:4px; background-color: #ccc;'>{{ ing }}</sp>
{% endfor %}
</li>
{% endfor %}
</ul>
</p>
{% endfor %}
{% else %}
<p class='lead'>No Items Found</p>
{% endif %}
{% endblock %}
```
**Edit file models.py pada direktori restaurants**
```bash!
from django.db import models
# Create your models here.
from django.conf import settings
from django.db import models
from django.db.models.signals import pre_save, post_save
from django.core.urlresolvers import reverse
from .utils import unique_slug_generator
from .validators import validate_category
# Create your models here.
User = settings.AUTH_USER_MODEL
class RestaurantLocation(models.Model):
owner = models.ForeignKey(User)
name = models.CharField(max_length=120)
location = models.CharField(max_length=120, null=True, blank=True)
category = models.CharField(max_length=120, null=True, blank=True, validators=[validate_category])
timestamp = models.DateTimeField(auto_now=True)
update = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(unique=True, null=True, blank=True)
def __str__(self):
return self.name
def get_absolute_url(self):
# return f"/restaurants/{self.slug}"
return reverse('restaurants:detail', kwargs={'slug': self.slug})
@property
def title(self):
return self.name
def rl_pre_save_receiver(sender, instance, *args, **kwargs):
instance.category = instance.category.capitalize()
if not instance.slug:
instance.slug = unique_slug_generator(instance)
#def rl_post_save_receiver(sender, instance, created, *args, **kwargs):
# print('saved')
# print(instance.timestamp)
# instance.save()
pre_save.connect(rl_pre_save_receiver, sender=RestaurantLocation)
#post_save.connect(rl_post_save_receiver, sender=RestaurantLocation)
```
**Tes Browser menggunakan user anda, apabila berhasil maka konfigurasi anda berhasil dan page yang ditampilkan sesuai**
-------------------------
# Style Profile with Bootstrap
**Edit file user.html pada direktori templates/profiles**
```bash!
{% extends "base.html" %}
{% block head_title %}{{ user.username }} | {{ block.super }}{% endblock head_title %}
{% block content %}
<h1>{{ user.username }}</h1>
<hr/>
{% if user.restaurantlocation_set.all %}
{% for rest in user.restaurantlocation_set.all %}
<div class='row'>
<div class='col-sm-12'>
<div class='thumbnail'>
<h4>{{ rest.title }}</h4>
<p>{{ rest.location }} | {{ rest.category }}</p>
<ul>
{% for item in rest.item_set.all %}
<li style='margin-bottom: 15px;'>
<strong>{{ item.name }}</strong><br/>
<span>{{ item.contents }}</span>
</li>
{% endfor %}
</ul>
<hr/>
</div>
</div>
</div>
{% endfor %}
{% else %}
<p class='lead'>No Items Found</p>
{% endif %}
{% endblock %}
```
**Tes Browser. Tampilan akan lebih rapi dan jika itu terjadi maka konfigurasi berhasil**
-------------------------
# Adding a Robust Search
**Edit views.py pada direktori profiles**
```bash!
from django.contrib.auth import get_user_model
from django.http import Http404
from django.shortcuts import render, get_object_or_404
from django.views.generic import DetailView
from menus.models import Item
from restaurants.models import RestaurantLocation
User = get_user_model()
class ProfileDetailView(DetailView):
template_name = 'profiles/user.html'
def get_object(self):
username = self.kwargs.get("username")
if username is None:
raise Http404
return get_object_or_404(User, username__iexact=username, is_active=True)
def get_context_data(self, **kwargs):
context = super(ProfileDetailView, self).get_context_data(**kwargs)
user = context['user']
query = self.request.GET.get('q')
items_exist = Item.objects.filter(user=user).exists()
qs = RestaurantLocation.objects.filter(owner=user)
if query:
qs = qs.filter(name__icontains=query)
if items_exist and qs.exists():
context['locations'] = qs
return context
```
**Edit file user.html pada direktori templates/profiles**
```bash!
{% extends "base.html" %}
{% block head_title %}{{ user.username }} | {{ block.super }}{% endblock head_title %}
{% block content %}
<h1>{{ user.username }}</h1>
<form class="form-inline mb-3" method="GET" action="">
<div class="form-group">
<input type="text" class="form-control mr-2" placeholder="Search..." name="q" value="{{ request.GET.q }}">
<button type="submit" class="btn btn-primary">Search</button>
</div>
</form>
<hr/>
{% if user.restaurantlocation_set.all %}
{% for rest in user.restaurantlocation_set.all %}
<div class='row'>
<div class='col-sm-12'>
<div class='thumbnail'>
<h4>{{ rest.title }}</h4>
<p>{{ rest.location }} | {{ rest.category }}</p>
<ul>
{% for item in rest.item_set.all %}
<li style='margin-bottom: 15px;'>
<strong>{{ item.name }}</strong><br/>
<span>{{ item.contents }}</span>
</li>
{% endfor %}
</ul>
<hr/>
</div>
</div>
</div>
{% endfor %}
{% else %}
<p class='lead'>No Items Found</p>
{% endif %}
{% endblock %}
```
**Tes Browser. Jika muncul kolom pencarian dan bisa filter maka konfigurasi berhasil**
---------------------------
# Handling User dan Followers
# Follow Users
**Edit file models.py pada direktori profiles**
```bash!
from django.conf import settings
from django.db import models
from django.db.models.signals import post_save
User = settings.AUTH_USER_MODEL
class Profile(models.Model):
user = models.OneToOneField(User) # user.profile
followers = models.ManyToManyField(User, related_name='is_following', blank=True) # user.is_following.all()
#following = models.ManyToManyField(User, related_name='following', blank=True) # user.following.all()
activated = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.user.username
def post_save_user_receiver(sender, instance, created, *args, **kwargs):
if created:
profile, is_created = Profile.objects.get_or_create(user=instance)
default_user_profile = Profile.objects.get_or_create(user__id=1)[0] #user__username=
default_user_profile.followers.add(instance)
#profile.followers.add(default_user_profile.user)
#profile.followers.add(2)
post_save.connect(post_save_user_receiver, sender=User)
```
**Edit file admin.py di dalam direktori profiles**
```bash!
from django.contrib import admin
from .models import Profile
admin.site.register(Profile)
```
**Edit file admin.py di dalam direktori profiles**
```bash!
from django.contrib import admin
from .models import Profile
admin.site.register(Profile)
```
**Jalankan Migrate**
```bash!
python manage.py makemigrations
```
```bash!
python manage.py migrate
```
```bash!
python manage.py runserver
```
**Tes Browser. Coba akses apakah section profiles sudah ada lalu pada bagian profiles terdapat followers. Jika ada maka aktifkan dan konfigurasi berhasil**
-------------------------
# Follow Button Form
```bash!
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import Http404
from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import DetailView, View
from menus.models import Item
from restaurants.models import RestaurantLocation
from .models import Profile
User = get_user_model()
class ProfileFollowToggle(LoginRequiredMixin, View):
def post(self, request, *args, **kwargs):
user_to_toggle = request.POST.get("username")
profile_ = Profile.objects.get(user__username__iexact=user_to_toggle)
user = request.user
if user in profile_.followers.all():
profile_.followers.remove(user)
else:
profile_.followers.add(user)
return redirect(f"/u/{profile_.user.username}/")
class ProfileDetailView(DetailView):
template_name = 'profiles/user.html'
model = User # Menggunakan model User sebagai model untuk detail view
def get_object(self):
username = self.kwargs.get("username")
if username is None:
raise Http404
return get_object_or_404(User, username__iexact=username, is_active=True)
def get_context_data(self, **kwargs):
context = super(ProfileDetailView, self).get_context_data(**kwargs)
user = context['user']
is_following = False
if user.profile in self.request.user.is_following.all():
is_following = True
context['is_following'] = is_following
query = self.request.GET.get('q')
items_exist = Item.objects.filter(user=user).exists()
qs = RestaurantLocation.objects.filter(owner=user)
if items_exist and qs.exists():
context['locations'] = qs
return context
```
**Edit file models.py pada direktori profiles**
```bash!
from django.conf import settings
from django.db import models
from django.db.models.signals import post_save
User = settings.AUTH_USER_MODEL
class ProfileManager(models.Manager):
def toggle_follow(self, request_user, username_to_toggle):
profile_ = Profile.objects.get(user__username__iexact=username_to_toggle)
user = request_user
is_following = False
if user in profile_.followers.all():
profile_.followers.remove(user)
else:
profile_.followers.add(user)
is_following = True
return profile_, is_following
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
followers = models.ManyToManyField(User, related_name='is_following', blank=True)
activated = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
objects = ProfileManager()
def __str__(self):
return self.user.username
def post_save_user_receiver(sender, instance, created, *args, **kwargs):
if created:
profile, is_created = Profile.objects.get_or_create(user=instance)
default_user_profile = Profile.objects.get_or_create(user__id=1)[0]
default_user_profile.followers.add(instance)
profile.followers.add(default_user_profile.user) # Mengganti profile.followers.add(2) menjadi profile.followers.add(default_user_profile.user)
post_save.connect(post_save_user_receiver, sender=User)
```
**Edit file urls.py pada direktori mywebsite**
```bash!
from django.conf.urls import url, include
from django.contrib import admin
from django.views.generic import TemplateView
from django.contrib.auth.views import LoginView
from profiles.views import ProfileFollowToggle
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'),
url(r'^login/$', LoginView.as_view(), name='login'),
url(r'^profile-follow/$', ProfileFollowToggle.as_view(), name='follow'),
url(r'^u/', include('profiles.urls', namespace='profiles')),
url(r'^items/', include('menus.urls', namespace='menus')),
url(r'^restaurants/', include('restaurants.urls', namespace='restaurants')),
url(r'^about/$', TemplateView.as_view(template_name='about.html'), name='about'),
url(r'^contact/$', TemplateView.as_view(template_name='contact.html'), name='contact'),
]
```
**Buat file follow_form.html di dalam direktori templates/profiles/snippet**
```bash!
mdkir templates/profiles/snippet
```
```bash!
touch templates/profiles/snippet.follow_form.html
```
```bash!
nano templates/profiles/snippet.follow_form.html
```
```bash!
{% if request.user.is_authenticated %}
<form class='form' method='POST' action='{% url "follow" %}'> {% csrf_token %}
<input type='hidden' name='username' value='{% if username %}{{ username }}{% else %}jmitchel3{% endif %}'/>
<button class='btn {% if is_following %}btn-default{% else %}btn-primary{% endif %}'>{% if is_following %}Unfollow{% else %}Follow{% endif %}</button>
</form>
{% endif %}
```
**Tes Browser 127.0.0.1:8000/u/(nama user) dan menggunakan django admin**
-------------------------
# Following Home Page Feed
**Edit views.py pada direktori menus**
```bash!
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render
from django.views.generic import View, ListView, DetailView, CreateView, UpdateView
from .forms import ItemForm
from .models import Item
class HomeView(View):
def get(self, request, *args, **kwargs):
if not request.user.is_authenticated():
object_list = Item.objects.filter(public=True).order_by('-timestamp')
return render(request, "home.html", {"object_list": object_list})
user = request.user
is_following_user_ids = [x.user.id for x in user.is_following.all()]
qs = Item.objects.filter(user__id__in=is_following_user_ids, public=True).order_by("-updated")[:3]
return render(request, "menus/home-feed.html", {'object_list': qs})
class ItemListView(ListView):
def get_queryset(self):
return Item.objects.filter(user=self.request.user)
class ItemDetailView(DetailView):
def get_queryset(self):
return Item.objects.filter(user=self.request.user)
class ItemCreateView(CreateView):
template_name = 'form.html'
form_class = ItemForm
def form_valid(self, form):
obj = form.save(commit=False)
obj.user = self.request.user
return super(ItemCreateView, self).form_valid(form)
def get_form_kwargs(self):
kwargs = super(ItemCreateView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def get_queryset(self):
return Item.objects.filter(user=self.request.user)
def get_context_data(self, *args, **kwargs):
context = super(ItemCreateView, self).get_context_data(*args, **kwargs)
context['title'] = 'Create Item'
return context
class ItemUpdateView(LoginRequiredMixin, UpdateView):
template_name = 'menus/detail-update.html'
form_class = ItemForm
def get_queryset(self):
return Item.objects.filter(user=self.request.user)
def get_context_data(self, *args, **kwargs):
context = super(ItemUpdateView, self).get_context_data(*args, **kwargs)
context['title'] = 'Update Item'
return context
```
**Edit urls.py di dalam direktori mywebsite**
```bash!
from django.conf.urls import url, include
from django.contrib import admin
from django.views.generic import TemplateView
from django.contrib.auth.views import LoginView
from menus.views import HomeView
from profiles.views import ProfileFollowToggle
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', HomeView.as_view(), name='home'),
url(r'^login/$', LoginView.as_view(), name='login'),
url(r'^profile-follow/$', ProfileFollowToggle.as_view(), name='follow'),
url(r'^u/', include('profiles.urls', namespace='profiles')),
url(r'^items/', include('menus.urls', namespace='menus')),
url(r'^restaurants/', include('restaurants.urls', namespace='restaurants')),
url(r'^about/$', TemplateView.as_view(template_name='about.html'), name='about'),
url(r'^contact/$', TemplateView.as_view(template_name='contact.html'), name='contact'),
]
```
**Buat direktori menus di dalam restaurants/templates dan baut file baru bernama home-feed.html di dalam direktori restaurants/templates/menus, serta edit file home-feed.html**
```bash!
{% extends 'base.html' %}
{% block content %}
{% for obj in object_list %}
<div class='row'>
<div class='col-sm-12'>
<div class='thumbnail'>
<h3><a href='{% url "profiles:detail" username=obj.user.username %}'>{{ obj.user.username }}</a></h3>
<h4>{{ obj.name }}</h4>
<p>{{ obj.restaurant.title }} | {{ obj.restaurant.location }} | {{ obj.restaurant.category }}</p>
<p>
<ul>
<li style='margin-bottom: 15px;'><b>{{ item.name }}</b><br/>
{% for ing in obj.get_contents %}
<a href='{{ request.path }}?q={{ ing }}'>{{ ing }}</a>
{% endfor %}
</li>
</ul>
</p>
</div>
</div>
</div>
{% endfor %}
{% endblock %}
```
**Tes Browser 127.0.0.1:8000 dengan akun yang sudah terlogin, dan akan mendirect ke landing page**