---
# System prepended metadata

title: Untitled

---

---
title: HackMD Dark Theme
tags: theme
description: Use `{%hackmd theme-dark %}` syntax to include this theme.
---

<style>

html, body, .ui-content {
    background-color: #333;
    color: #ddd;
}

.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
    color: #ddd;
}

.markdown-body h1,
.markdown-body h2 {
    border-bottom-color: #ffffff69;
}

.markdown-body h1 .octicon-link,
.markdown-body h2 .octicon-link,
.markdown-body h3 .octicon-link,
.markdown-body h4 .octicon-link,
.markdown-body h5 .octicon-link,
.markdown-body h6 .octicon-link {
    color: #fff;
}

.markdown-body img {
    background-color: transparent;
}

.ui-toc-dropdown .nav>.active:focus>a, .ui-toc-dropdown .nav>.active:hover>a, .ui-toc-dropdown .nav>.active>a {
    color: white;
    border-left: 2px solid white;
}

.expand-toggle:hover, 
.expand-toggle:focus, 
.back-to-top:hover, 
.back-to-top:focus, 
.go-to-bottom:hover, 
.go-to-bottom:focus {
    color: white;
}


.ui-toc-dropdown {
    background-color: #333;
}

.ui-toc-label.btn {
    background-color: #191919;
    color: white;
}

.ui-toc-dropdown .nav>li>a:focus, 
.ui-toc-dropdown .nav>li>a:hover {
    color: white;
    border-left: 1px solid white;
}

.markdown-body blockquote {
    color: #bcbcbc;
}

.markdown-body table tr {
    background-color: #5f5f5f;
}

.markdown-body table tr:nth-child(2n) {
    background-color: #4f4f4f;
}

.markdown-body code,
.markdown-body tt {
    color: #eee;
    background-color: rgba(230, 230, 230, 0.36);
}

a,
.open-files-container li.selected a {
    color: #5EB7E0;
}

</style>
**3. Edit file models.py didalam direktori menus**
```
from django.conf import settings
from django.db import models
from django.core.urlresolvers import reverse
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)

    def get_absolute_url(self):
        return reverse('menus:detail', kwargs={'pk': self.pk})

    class Meta:
        ordering = ['-updated', '-timestamp']

    def get_contents(self):
        return self.contents.split(",")

    def get_excludes(self):
        return self.excludes.split(",")
```
![image](https://hackmd.io/_uploads/HywZQlGkC.png)

**4. Edit file urls.py didalam direktori menus**
```
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+)/$', ItemDetailView.as_view(), name='detail'),
     url(r'$', ItemListView.as_view(), name='List'),

]
```
![image](https://hackmd.io/_uploads/SkOrQlz10.png)

**5. Edit file urls.py didalam direktori src/mywebsite**
```
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'^items/', include('menus.urls', namespace='menus')),
    url(r'^restaurants/', include('restaurants.urls', namespace='restaurants')),
    #url(r'^restaurants/$', RestaurantListView.as_view(), name='restaurants'),
    #url(r'^restaurants/create/$', RestaurantCreateView.as_view(), name='restaurants-creat'),
    #url(r'^restaurants/(?P<slug>[\w-]+)/$', RestaurantDetailView.as_view(), name='restaur'),
    url(r'^about/$', TemplateView.as_view(template_name='about.html'), name='about'),
    url(r'^contact/$', TemplateView.as_view(template_name='contact.html'), name='contact'),
]
```
![image](https://hackmd.io/_uploads/B1chXgG10.png)

**6. Buat direktori menus pada src/restaurants/templates dan buat juga untuk file item_list.html kemudian edit filenya**
```
{% extends "base.html" %}
{% block head_title %}Menu Items | {{ block.super }}{% endblock head_title %}
{% block content %}
<h1>Menu Items</h1>

<ul>
  {% for obj in object_list %}
  <li><a href='{{ obj.get_absolute_url }}'>{{ obj.name }}</a><br/>
    <a href='/restaurants/{{ obj.slug }}/'>{{ obj }}</a><br/>
    {% if obj.contents %}
    <p>Contents:</p>
    <ul>
      {% for item in obj.get_contents %}
      <li>{{ item }}</li>
      {% endfor %}
    </ul>
    {% endif %}
    {% if obj.excludes %}
    <p>Excludes:</p>
    <ul>
      {% for item in obj.get_excludes %}
      <li>{{ item }}</li>
      {% endfor %}
    </ul>
    {% endif %}
  </li>
  {% endfor %}
</ul>
{% endblock %}
```
![image](https://hackmd.io/_uploads/r1ON4lMk0.png)

**8. Kemudian buat juga file item_detail.html dan edit (masih didalam direktori yang sama)**
```
{% extends "base.html" %}
{% block head_title %}Menu Items | {{ block.super }}{% endblock head_title %}
{% block content %}
  <h1>{{ object.name }}</h1>
  <p>Location: {{ object.restaurant.name }}</p>
  {% if object.contents %}
    <p>Contents:</p>
    <ul>
      {% for item in object.get_contents %}
        <li>{{ item }}</li>
      {% endfor %}
    </ul>
  {% endif %}
  {% if object.excludes %}
    <p>Excludes:</p>
    <ul>
      {% for item in object.get_excludes %}
        <li>{{ item }}</li>
      {% endfor %}
    </ul>
  {% endif %}
{% endblock %}
```
![image](https://hackmd.io/_uploads/SkgpVeGyA.png)

**9. Kemudian buka di browser ubuntu**
![Screenshot (1426)](https://hackmd.io/_uploads/HktQSefJC.png)

coba change item dari Django Admin
![Screenshot (1427)](https://hackmd.io/_uploads/SJIOHxfy0.png)

kemudian liat pada items page
![Screenshot (1428)](https://hackmd.io/_uploads/HyhtBgf10.png)

kemudian coba update items dengan web page tanpa Django Admin
![Screenshot (1430)](https://hackmd.io/_uploads/rJ2I8xMy0.png)

# Limiting Form Field to QuerySet
Kita membatasi opsi yang tersedia dalam form dengan menggunakan queryset. Ini memungkinkan kita untuk menampilkan hanya entitas yang sesuai dengan kriteria tertentu dalam form, seperti item yang dimiliki oleh pengguna yang saat ini masuk. Dengan cara ini, pengguna hanya dapat memilih opsi yang relevan untuk mereka. Ini meningkatkan pengalaman pengguna dan membantu memastikan data yang konsisten dan relevan.

**1. Edit file views.py didalam direktori menus**
```
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
```
![image](https://hackmd.io/_uploads/HkoGsMmkA.png)

**2. Edit file forms.py didalam direktori menus**
```
from django import forms
from restaurants.models import RestaurantLocation
from .models import Item

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(user=user).exclude(item__isnull=False)
```
![image](https://hackmd.io/_uploads/HkQLoM71C.png)

**3. Edit file urls.py didalam direktori menus**
```
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'),
]
```
![image](https://hackmd.io/_uploads/S1jniGQJC.png)

**4. Akses 127.0.0.1:8000/items/1/edit di browser ubuntu**
![Screenshot (1431)](https://hackmd.io/_uploads/Bk9ZnM7k0.png)

# Personalize Items
Kita akan membuat fitur di aplikasi yang memungkinkan pengguna untuk melihat dan mengelola item-menu dan restoran mereka sendiri. Hal ini akan memastikan bahwa setiap pengguna hanya melihat informasi yang terkait dengan akun mereka. 

**1. Edit file views.py didalam direktori restaurants**
```
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from .forms import RestaurantLocationCreateForm
from .models import RestaurantLocation

class RestaurantListView(LoginRequiredMixin, ListView):
    def get_queryset(self):
        return RestaurantLocation.objects.filter(user=self.request.user)

class RestaurantDetailView(LoginRequiredMixin, DetailView):
    def get_queryset(self):
        return RestaurantLocation.objects.filter(user=self.request.user)

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)

    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):
    model = RestaurantLocation  # Menetapkan model untuk UpdateView
    form_class = RestaurantLocationCreateForm
    login_url = '/login/'
    template_name = 'restaurants/form.html'
    # success_url = "/restaurants"

    def get_queryset(self):  # Mendefinisikan queryset untuk UpdateView
        return RestaurantLocation.objects.filter(user=self.request.user)

    def get_context_data(self, *args, **kwargs):
        context = super(RestaurantUpdateView, self).get_context_data(*args, **kwargs)
        context['title'] = 'Update Restaurant'
        return context
```
![image](https://hackmd.io/_uploads/r1OTW47kR.png)

**2. Edit file urls.py didalam direktori restaurants**
```
from django.conf.urls import url
from .views import (
    RestaurantListView,
    RestaurantDetailView,
    RestaurantCreateView,
    RestaurantUpdateView
)

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'^create/$', RestaurantCreateView.as_view(), name='create'),  # Perhatikan penghapusan tanda kutip ganda ekstra dan tanda slash di depan
    url(r'^(?P<slug>[\w-]+)/$', RestaurantUpdateView.as_view(), name='edit'),
    url(r'^(?P<slug>[\w-]+)/$', RestaurantDetailView.as_view(), name='detail'),  # Perhatikan penghapusan tanda kutip ganda ekstra dan tanda slash di depan
    url(r'$', RestaurantListView.as_view(), name='list'),
    #url(r'^about/$', TemplateView.as_view(template_name='about.html'), name='about'),
    #url(r'^contact/$', TemplateView.as_view(template_name='contact.html'), name='contact'),
]
```
![image](https://hackmd.io/_uploads/B1L7GVmJ0.png)

**3. Edit file nav.html didalam direktori src/mywebsite/templates/snippets**
```
<div class="container">
<h1>Nicholai Dandy Nainggolan.org</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>
{% endif %}
</div>
```
![image](https://hackmd.io/_uploads/S1-2zN7k0.png)

**4. Buat direktori restautants didalam direktori mywebsite/templates/ dan buat file form.html didalam direktori restaurants**
![image](https://hackmd.io/_uploads/S1O64EX1R.png)

**5. Edit file form.html**
```
{% 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 %}
```
![image](https://hackmd.io/_uploads/B1VgHEm1R.png)

6. Akses ke 127.0.01:8000/restaurants pada browser ubuntu
![Screenshot (1433)](https://hackmd.io/_uploads/rkK_HV71C.png) klik Add disamping restaurants

![Screenshot (1432)](https://hackmd.io/_uploads/r1SfBNQJ0.png)

# User Profile View
Anda membuat fitur baru di aplikasi Anda yang disebut "Profiles" untuk membuat profil publik pengguna. Fitur ini memungkinkan pengguna untuk melihat daftar restoran dan item makanan yang disukai oleh pengguna lain. Untuk melakukannya, Anda membuat kelas view ProfileDetailView yang mengambil detail view dari Django. Setelah itu, Anda menyiapkan tampilan profil dengan menampilkan daftar restoran dan item makanan yang disukai oleh pengguna, dengan sedikit penyesuaian tata letak dan gaya. Dengan ini, pengguna dapat berbagi preferensi makanan mereka dengan orang lain.

**1. Buat project baru bernama profiles**
![image](https://hackmd.io/_uploads/rySFQSXyR.png)

**2. Edit file views.py dalam direktori profiles**
```
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)
```
![image](https://hackmd.io/_uploads/HJrDTB710.png)

**3. Edit file urls.py didalam direktori profiles**
```
from django.conf.urls import url
from .views import ProfileDetailView

urlpatterns = [
    url(r'^(?P<username>[\w-]+)/$', ProfileDetailView.as_view(), name='detail'),
]
```
![image](https://hackmd.io/_uploads/HkJ9aBQ10.png)

**4. Edit file didalam direktori mywebsite/settings**
![image](https://hackmd.io/_uploads/rJL0pHmJC.png)

**5. Buat direktori baru didalam mywebsite/templates dan buat file baru didalam direktori yang baru dibuat dengan nama user.html**
![image](https://hackmd.io/_uploads/BySdRSQy0.png)

Edit file user.html
```
{% 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 }}</span>
            {% endfor %}
        </li>
        {% endfor %}
    </ul>
</p>
{% endfor %}
{% else %}
<p class='lead'>No Items Found</p>
{% endif %}
{% endblock %}
```
![image](https://hackmd.io/_uploads/HJu9RS7y0.png)

**6. Edit file models.py dalam direktori restaurants**
```
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):
    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

    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)
```
![image](https://hackmd.io/_uploads/SkpgJUXJA.png)

**7. Cek di browser ubuntu dengan 127.0.0.1:8000/u/(user)**
![Screenshot (1434)](https://hackmd.io/_uploads/By6SJIXkC.png)

# Style Profile with Bootstrap

**1. Edit file user.html didalam direktori mywebsite/templates/profiles**
```
{% 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 %}
```
![image](https://hackmd.io/_uploads/Sk9GMI7yA.png)

**2. Cek di browser ubuntu dengan 127.0.0.1:8000/u/(user)**
![Screenshot (1435)](https://hackmd.io/_uploads/H1fWfIX1R.png)

# Adding a Robust Search
"Adding a robust search" adalah proses menambahkan fitur pencarian yang kuat atau canggih ke dalam sebuah aplikasi web. Ini melibatkan pengembangan sistem pencarian yang dapat melakukan pencarian yang kompleks dan akurat, termasuk kemampuan untuk mencari berdasarkan kriteria yang beragam dan filter yang diterapkan. Tujuannya adalah untuk memberikan pengguna pengalaman pencarian yang lebih baik dan efisien dalam menemukan informasi yang mereka perlukan. Dalam konteks pengembangan web dengan Django

**1. Edit file views.py didalam direktori profiles**
```
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
```
![image](https://hackmd.io/_uploads/BJnMsL7J0.png)

**2. Edit file user.html pada direktori mywebsite/templates/profiles**
```
{% 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 %}
```
![image](https://hackmd.io/_uploads/By5LsI7y0.png)

**3. Akses ke 127.0.0.1:8000/u/(user) pada browser ubuntu**
![image](https://hackmd.io/_uploads/BJ3C9UQ10.png)

Lakukan pencarian (contoh pada gambar melakukan pencarian warung)
![image](https://hackmd.io/_uploads/H1fT5IQ10.png)

# Handling User & Followers

**1. Follow Users**
Bagaimana cara membuat fitur yang memungkinkan pengguna untuk mengikuti pengguna lain di situs web. Fitur ini memungkinkan pengguna untuk melihat profil pengguna lain, mengikuti mereka, dan melihat pembaruan terkait aktivitas pengguna yang diikuti.

**1. Edit file models.py didalam direktori profiles**
```
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, on_delete=models.CASCADE)  # user.profile
    followers = models.ManyToManyField(User, related_name='followers', blank=True)
    following = models.ManyToManyField(User, related_name='following', blank=True)
    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)

post_save.connect(post_save_user_receiver, sender=User)
```
![image](https://hackmd.io/_uploads/r1FofDQJR.png)

**2. Edit file admin.py didalam direktori profiles**
```
from django.contrib import admin

from .models import Profile

admin.site.register(Profile)
```
![image](https://hackmd.io/_uploads/r1AAMP7yC.png)

**3. Lakukan migrasi & jalankan server**
python manage.py makemigrations
python manage,py migrate
python manage.py runserver
![image](https://hackmd.io/_uploads/H1TgXvm1C.png)

**4. Cek pada browser ubuntu dengan membuka Django admin & cek Profiles sudah ada**
![image](https://hackmd.io/_uploads/BkJPQw71C.png)

**5. Cek pada bagian profiles dan pilih salah satu user & lihat bahwa Followers dan Following ada**
![image](https://hackmd.io/_uploads/B1DK4wQ10.png)

# Follow Button Form

**1. Edit file views.py didalam direktori profiles**
```
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):
        username_to_toggle = request.POST.get("username")
        profile_, is_following = Profile.objects.toggle_follow(request.user, username_to_toggle)
        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 self.request.user.is_authenticated:  # Periksa apakah pengguna sedang login
            if user.profile in self.request.user.profile.followers.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(user=user)
        if items_exist and qs.exists():
            context['locations'] = qs
        return context
```
![image](https://hackmd.io/_uploads/B19ZfZN1C.png)

**2. Edit file models.py didalam direkori profiles**
```
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.profile in profile.followers.all():
            profile.followers.remove(user.profile)
            is_following = False
        else:
            profile.followers.add(user.profile)
            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)
```
![image](https://hackmd.io/_uploads/HJ-b7-NJC.png)

**3. Edit file urls.py didalam direktori mywebsite**
![image](https://hackmd.io/_uploads/B1QQXZEk0.png)

**4. Edit file follow_form.html didalam direktori src/restaurants/templates/profiles/snippet (jika belum ada silahkan dibuat direktorinya dan filenya)**
![image](https://hackmd.io/_uploads/B1BPX-Ny0.png)

**5. Untuk melihat access authenticated, buka pada mode penyamaran browser 127.0.0.1:8000/u/(nama user)**
![image](https://hackmd.io/_uploads/rJ36XbV10.png)
"Kita bisa melihat bahwa tidak ada tombol follow"

**6. Coba buka tanpa mode penyamaran (sudah login Django Admin)**
![image](https://hackmd.io/_uploads/rJJZEZN1A.png)

# Following Home Page Feed

**1. Edit file views.py didalam direktori menus**
```
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:
            return render(request, "home.html", {})

        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")[:]

        return render(request, "menus/home-feed.html", {'object_list': qs})

class ItemListView(LoginRequiredMixin, ListView):
    def get_queryset(self):
        return Item.objects.filter(user=self.request.user)

class ItemDetailView(LoginRequiredMixin, DetailView):
    def get_queryset(self):
        return Item.objects.filter(user=self.request.user)

class ItemCreateView(LoginRequiredMixin, 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
```
![image](https://hackmd.io/_uploads/r1hwn-VkC.png)

**2. Edit file urls.py didalam direkotori mywebiste**
```
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'),  # Fixed the URL pattern
    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')),  # Fixed the syntax error
    url(r'^about/$', TemplateView.as_view(template_name='about.html'), name='about'),  # Fixed the URL pattern
    url(r'^contact/$', TemplateView.as_view(template_name='contact.html'), name='contact'),  # Fixed the URL pattern
]
```
![image](https://hackmd.io/_uploads/rJZpnZEJR.png)

3. Edit file home-feed.html didalam direktori restaurants/templates/menus
![image](https://hackmd.io/_uploads/SyA16bVJ0.png)

```
{% 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 %}
```
![image](https://hackmd.io/_uploads/ryQZTbNJC.png)

**4. Buka pada browser ubuntu 172.0.0.1:8000**
![image](https://hackmd.io/_uploads/SyOXTbVyA.png)

# Register View

**1. Buat file forms.py dalam direkotri profiles**
![image](https://hackmd.io/_uploads/BkgeCZVkR.png)

```
from django import forms

from django.contrib.auth import get_user_model

User = get_user_model()


class RegisterForm(forms.ModelForm):
    """A form for creating new users. Includes all the required
    fields, plus a repeated password."""
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ('username', 'email',)

    def clean_email(self):
        email = self.cleaned_data.get("email")
        qs = User.objects.filter(email__iexact=email)
        if qs.exists():
            raise forms.ValidationError("Cannot use this email. It's already registered")
        return email

    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("Passwords don't match")
        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super(RegisterForm, self).save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        #user.password = "asdfasd"
        user.is_active = False


        if commit:
            user.save()
            user.profile.send_activation_email()
            # create a new user hash for activating email.
        return user
```
![image](https://hackmd.io/_uploads/rkATWWw1C.png)

**2. Edit file views.py didalam direktori profiles**
```
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 CreateView, DetailView, View
# Create your views here.
from menus.models import Item
from restaurants.models import RestaurantLocation

from .forms import RegisterForm
from .models import Profile
User = get_user_model()


class RegisterView(CreateView):
    form_class = RegisterForm
    template_name = 'registration/register.html'
    success_url = '/'

    def dispatch(self, *args, **kwargs):
        # if self.request.user.is_authenticated():
        #     return redirect("/logout")
        return super(RegisterView, self).dispatch(*args, **kwargs)



class ProfileFollowToggle(LoginRequiredMixin, View):
    def post(self, request, *args, **kwargs):
        username_to_toggle = request.POST.get("username")
        profile_, is_following = Profile.objects.toggle_follow(request.user, username_to_toggle)
        return redirect(f"/u/{profile_.user.username}/")


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, *args, **kwargs):
        context = super(ProfileDetailView, self).get_context_data(*args, **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_exists = Item.objects.filter(user=user).exists()
        qs = RestaurantLocation.objects.filter(user=user).search(query)
        if items_exists and qs.exists():
            context['locations'] = qs
        return context
```
![image](https://hackmd.io/_uploads/rkpeGZvJA.png)

**3. Edit file urls.py didalam direktori mywebsite**
```
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, LogoutView

from menus.views import HomeView
from profiles.views import ProfileFollowToggle, RegisterView

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', HomeView.as_view(), name='home'),
    url(r'^register/$', RegisterView.as_view(), name='register'),
    url(r'^login/$', LoginView.as_view(), name='login'),
    url(r'^logout/$', LogoutView.as_view(), name='logout'),
    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'),
]
```
![image](https://hackmd.io/_uploads/S1yNMZvJ0.png)

**4. Buat direktori registration didalam direktori src/restaurants/template & Buat file login.html dan register.html
![image](https://hackmd.io/_uploads/S1YKGZDkC.png)
![image](https://hackmd.io/_uploads/S1f5zbPJA.png)

**5. Edit file login.html **
```
{% 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 %}
{{ form.as_p }}

<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>

{# Assumes you setup the password_reset view in your URLconf #}

{% endblock %}
```
![image](https://hackmd.io/_uploads/S1XbmbD1A.png)

**6. Edit file register.html**
```
{% extends "base.html" %}

{% block content %}

<div class='col-sm-6 col-sm-offset-3 text-center'>
<h1>Register</h1>

<form method="post" action="{% url 'register' %}">
{% csrf_token %}
{{ form.as_p }}

<input type="submit" value="Register" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
<p>Did you need to <a href='{% url "login" %}'>Login</a>?
</div>

{% endblock %}
```
![image](https://hackmd.io/_uploads/S1Dm7-v10.png)

**7. Edit file models.py didalam direktori profiles**
```
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) # 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)

    objects = ProfileManager()

    def __str__(self):
        return self.user.username

    def send_activation_email(self):
        print("Activation")
        pass


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)
```
![image](https://hackmd.io/_uploads/HJrcwZPJ0.png)

8. Edit file base.py didalam direktori src/mywebsite/settings
Sesuaikan seperti gambar dibawah ini
![image](https://hackmd.io/_uploads/BJx0D-DkC.png)


**9. Stop runserver dan runserver kembali**

**10. Akses server dengan 127.0.0.1:8000/register/ dan coba register user baru**
![image](https://hackmd.io/_uploads/r17WubvJ0.png)

**11. Cek pada Django admin dan cek apakah user baru sudah tertambahkan**
![image](https://hackmd.io/_uploads/HJydOWDk0.png)

# Activation Keys

**1. Edit file views.py di direktori profiles**
```
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 CreateView, DetailView, View
# Create your views here.
from menus.models import Item
from restaurants.models import RestaurantLocation

from .forms import RegisterForm
from .models import Profile
User = get_user_model()


def activate_user_view(request, code=None, *args, **kwargs):
    if code:
        qs = Profile.objects.filter(activation_key=code)
        if qs.exists() and qs.count() == 1:
            profile = qs.first()
            if not profile.activated:
                user_ = profile.user
                user_.is_active = True
                user_.save()
                profile.activated=True
                profile.activation_key=None
                profile.save()
                return redirect("/login")
    return redirect("/login")



class RegisterView(CreateView):
    form_class = RegisterForm
    template_name = 'registration/register.html'
    success_url = '/'

    def dispatch(self, *args, **kwargs):
        # if self.request.user.is_authenticated():
        #     return redirect("/logout")
        return super(RegisterView, self).dispatch(*args, **kwargs)



class ProfileFollowToggle(LoginRequiredMixin, View):
    def post(self, request, *args, **kwargs):
        username_to_toggle = request.POST.get("username")
        profile_, is_following = Profile.objects.toggle_follow(request.user, username_to_toggle)
        return redirect(f"/u/{profile_.user.username}/")


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, *args, **kwargs):
        context = super(ProfileDetailView, self).get_context_data(*args, **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_exists = Item.objects.filter(user=user).exists()
        qs = RestaurantLocation.objects.filter(owner=user).search(query)
        if items_exists and qs.exists():
            context['locations'] = qs
        return context
```
![image](https://hackmd.io/_uploads/BJcgcfv1C.png)

**2. Edit file models.py di direktori profiles**
```
from django.conf import settings
from django.db import models
from django.db.models.signals import post_save
from django.core.mail import send_mail
from django.core.urlresolvers import reverse
from .utils import code_generator


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) # 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()
    activation_key    = models.CharField(max_length=120, blank=True, null=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 send_activation_email(self):
        if not self.activated:
            self.activation_key = code_generator()# 'somekey' #gen key
            self.save()
            #path_ = reverse()
            path_ = reverse('activate', kwargs={"code": self.activation_key})
            subject = 'Activate Account'
            from_email = settings.DEFAULT_FROM_EMAIL
            message = f'Activate your account here: {path_}'
            recipient_list = [self.user.email]
            html_message = f'<p>Activate your account here: {path_}</p>'
            print(html_message)
            # sent_mail = send_mail(
            #                 subject, 
            #                 message, 
            #                 from_email, 
            #                 recipient_list, 
            #                 fail_silently=False, 
            #                 html_message=html_message)
            sent_mail = False
            return sent_mail




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)
```
![image](https://hackmd.io/_uploads/SkYS9fv10.png)

**3. Edit file utils.py didalam direktori profiles**
sudo nano utils.py
```
import random
import string

from django.conf import settings


SHORTCODE_MIN = getattr(settings, "SHORTCODE_MIN", 35)

#from shortener.models import KirrURL

def code_generator(size=SHORTCODE_MIN, chars=string.ascii_lowercase + string.digits):
    # new_code = ''
    # for _ in range(size):
    #     new_code += random.choice(chars)
    # return new_code
    return ''.join(random.choice(chars) for _ in range(size))
```
![image](https://hackmd.io/_uploads/SJnnqMPJ0.png)

**4. Edit file base.py didalam direktori src/mywebsite/settings**
```
ALLOWED_HOSTS = []

EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'youremail@gmail.com' 
EMAIL_HOST_PASSWORD = 'yourpassword'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = 'Your Name <you@email.com>'

ADMINS = (
    ('You', 'you@email.com'),
)
MANAGERS = ADMINS

```
![image](https://hackmd.io/_uploads/S1FmjfwyR.png)

5. Edit file urls.py didalam direktori src/mywebsite
```
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, LogoutView

from menus.views import HomeView
from profiles.views import ProfileFollowToggle, RegisterView, activate_user_view

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', HomeView.as_view(), name='home'),
    url(r'^register/$', RegisterView.as_view(), name='register'),
    url(r'^activate/(?P<code>[a-z0-9].*)/$', activate_user_view, name='activate'),
    url(r'^login/$', LoginView.as_view(), name='login'),
    url(r'^logout/$', LogoutView.as_view(), name='logout'),
    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'),
]
```
![image](https://hackmd.io/_uploads/H1YlR7vyA.png)

**6. Migrasi Server**
python manage.py makemigrations
python manage.py migrate
python manage.py runserver
![image](https://hackmd.io/_uploads/ByDknMvJ0.png)

**7. Akses server dengan 127.0.0.1:8000/register/ dan coba register user baru**
![image](https://hackmd.io/_uploads/SyGLAQD1R.png)

ketika sudah register
![image](https://hackmd.io/_uploads/SkDLRQw1C.png)

acitvasi sudah langsung otomatis keluar pada terminal
![image](https://hackmd.io/_uploads/ryxvAXvyR.png)
