Advertisement
  1. Code
  2. Python

Membangun Ribbit di Django

Scroll to top
Read Time: 27 min

Indonesian (Bahasa Indonesia) translation by Uady (you can also view the original English article)

Setelah menerapkan Twitter-clone kami, Ribbit, dalam PHP dan Rails biasa, inilah saatnya memperkenalkan walk-through berikutnya: Python! Dalam tutorial ini, kita akan membangun kembali Ribbit menggunakan Django. Tanpa penundaan lebih lanjut, mari kita mulai!

Home Page

Langkah 0 - Bootstrapping

Pada saat penulisan ini, Django 1.4 mendukung Python 2.5 hingga 2.7.3. Sebelum melanjutkan, pastikan Anda memiliki versi apt dengan menjalankan python-v di terminal. Perhatikan bahwa Python 2.7.3 lebih disukai. Di seluruh tutorial ini, kita akan menggunakan pip sebagai manajer paket dan virtualenv untuk mengatur Lingkungan Virtual. Untuk menginstal ini, jalankan terminal dan jalankan perintah berikut sebagai root

1
curl https://python-distribute.org/distribute_setup.py | sudo python
2
curl https://raw.github.com/pypa/pip/master/contrib/get-pip.py | sudo python
3
sudo pip install virtualenv

Untuk mengatur lingkungan pengembangan Django, kita akan memulai dengan menciptakan Lingkungan Virtual. Jalankan perintah berikut di terminal (lebih disukai di dalam direktori pengembangan Anda)

1
virtualenv --no-site-packages ribbit_env
2
source ribbit_env/bin/activate

Dengan Lingkungan Virtual, mengatur dan mengaktifkan (command prompt Anda harus diubah untuk mencerminkan nama lingkungan), mari kita lanjutkan dengan menginstal dependensi untuk proyek. Selain Django, kita akan menggunakan South untuk menangani migrasi basis data. Kita akan menggunakan pip untuk menginstal keduanya dengan mengeksekusi. Perhatikan bahwa mulai sekarang, kita akan melakukan segala sesuatu di dalam virtualenv. Karena itu, pastikan bahwa itu diaktifkan sebelum melanjutkan.

1
pip install Django South

Dengan semua pengaturan dependensi, kita siap untuk melanjutkan pembuatan Proyek Django baru.


Langkah 1 - Membuat Proyek dan Aplikasi Ribbit

Kita akan mulai dengan membuat proyek Django baru dan aplikasi. cd ke direktori pilihan Anda dan jalankan:

1
django-admin.py startproject ribbit
2
cd ribbit
3
django-admin.py startapp ribbit_app

Selanjutnya, kita akan menginisialisasi repositori git kita dan membuat file .gitignore di dalam proyek Ribbit yang baru kita buat. Untuk melakukannya, jalankan:

1
git init
2
echo "*.pyc" >> .gitignore
3
git add .
4
git commit -m 'Initial Commit'

Mari kita lanjutkan ke pengeditan ribbit/settings.py dan konfigurasi proyek. Pertama, kita akan mendefinisikan beberapa konstanta. Tambahkan yang berikut ini ke bagian atas file:

1
import os
2
3
PROJECT_PATH = os.path.dirname(os.path.abspath(__file__))  
4
LOGIN_URL = '/'

PROJECT_PATH akan menyimpan lokasi direktori tempat settings.py disimpan. Ini akan memungkinkan kita untuk menggunakan jalur relatif untuk konstanta masa depan. LOGIN_URL, sesuai namanya, menunjukkan bahwa akar situs kita adalah URL untuk Login.

Lanjut, mari konfigurasi database. Untuk lingkungan pengembangan, sqlite3 adalah pilihan ideal. Untuk melakukannya, edit konstanta DATABASES dengan nilai-nilai berikut:

1
DATABASES = {
2
    'default': {
3
        'ENGINE': 'django.db.backends.sqlite3',  # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.

4
        'NAME': os.path.join(PROJECT_PATH, 'database.db'),                      # Or path to database file if using sqlite3.

5
        'USER': '',                      # Not used with sqlite3.

6
        'PASSWORD': '',                  # Not used with sqlite3.

7
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.

8
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.

9
    }
10
}

Django menemukan file statis dari direktori yang disebutkan di STATIC_ROOT konstan dan rute permintaan ke file ke jalur yang ditentukan dalam STATIC_URL. Konfigurasikan mereka sehingga mencerminkan hal-hal berikut:

1
# Absolute path to the directory static files should be collected to.

2
# Don't put anything in this directory yourself; store your static files

3
# in apps' "static/" subdirectories and in STATICFILES_DIRS.

4
# Example: "/home/media/media.lawrence.com/static/"

5
STATIC_ROOT = os.path.join(PROJECT_PATH, 'static')
6
7
# URL prefix for static files.

8
# Example: "http://media.lawrence.com/static/"

9
STATIC_URL = '/static/'

Perhatikan penggunaan os.path.join(). Fungsi ini memungkinkan kita untuk secara relatif menentukan jalur menggunakan konstanta PROJECT_PATH yang telah kita definisikan sebelumnya.

Selanjutnya, kita perlu menentukan lokasi yang perlu dilihat Django untuk menemukan file template. Kita akan mengedit konstanta TEMPLATE_DIRS untuk menentukan jalur.

1
TEMPLATE_DIRS = (
2
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".

3
    # Always use forward slashes, even on Windows.

4
    # Don't forget to use absolute paths, not relative paths.

5
    os.path.join(PROJECT_PATH, 'templates')
6
)

Terakhir, mari tambahkan South dan ribbit_app ke daftar INSTALLED_APPS.

1
INSTALLED_APPS = (
2
    'django.contrib.auth',
3
    'django.contrib.contenttypes',
4
    'django.contrib.sessions',
5
    'django.contrib.sites',
6
    'django.contrib.messages',
7
    'django.contrib.staticfiles',
8
    'south',
9
    'ribbit_app',
10
    # Uncomment the next line to enable the admin:

11
    # 'django.contrib.admin',

12
    # Uncomment the next line to enable admin documentation:

13
    # 'django.contrib.admindocs',

14
)

Selanjutnya, mari kita buat direktori yang ditentukan dalam pengaturan dan membuat database:

1
mkdir ribbit/static ribbit/templates ribbit_app/static
2
python manage.py syncdb
3
python manage.py schemamigration ribbit_app --initial
4
python manage.py migrate ribbit_app

Perintah syncdb akan membuat tabel yang diperlukan dan membuat akun superuser. Karena menggunakan South untuk migrasi, kita membuat migrasi awal untuk aplikasi menggunakan sintaksis schemamigration<app_name> --initial dan menerapkannya dengan phyton manage.py migrate ribbit_app

Mari kita mulai server pengembangan untuk memastikan semuanya berfungsi dengan benar.

1
python manage.py runserver

Jika semuanya memang bagus, Anda harus disambut dengan halaman berikut ketika Anda mengunjungi http://localhost:8000

Landing Page

Selanjutnya, pohon proyek akan terlihat seperti:

1
ribbit
2
|-- manage.py
3
|-- ribbit
4
|   |-- database.db
5
|   |-- __init__.py
6
|   |-- __init__.pyc
7
|   |-- settings.py
8
|   |-- settings.pyc
9
|   |-- static
10
|   |-- templates
11
|   |-- urls.py
12
|   |-- urls.pyc
13
|   |-- wsgi.py
14
|   `-- wsgi.pyc
15
`-- ribbit_app
16
    |-- __init__.py
17
    |-- __init__.pyc
18
    |-- migrations
19
    |   |-- 0001_initial.py
20
    |   |-- 0001_initial.pyc
21
    |   |-- __init__.py
22
    |   `-- __init__.pyc
23
    |-- models.py
24
    |-- models.pyc
25
    |-- static
26
    |-- tests.py
27
    `-- views.py

Sebelum beralih ke langkah berikutnya, mari lakukan perubahan pada repo.

1
git add .
2
git commit -m 'Created app and configured settings'

Langkah 2 - Template Dasar dan File Statis

Mengikuti dari tutorial antarmuka, unduh aset dan letakkan di dalam direktori ribbit_app/statis. Kita perlu melakukan beberapa pengeditan untuk style.less untuk tutorial ini. Mari mulai dengan menambahkan beberapa gaya untuk flash.

1
.flash {
2
    padding: 10px;
3
    margin: 20px 0;
4
    &.error {
5
        background: #ffefef;
6
        color: #4c1717;
7
        border: 1px solid #4c1717;
8
    }
9
    &.warning {
10
        background: #ffe4c1;
11
        color: #79420d;
12
        border: 1px solid #79420d;
13
    }
14
    &.notice {
15
        background: #efffd7;
16
        color: #8ba015;
17
        border: 1px solid #8ba015;
18
    }
19
}

Selanjutnya, mari kita perbarui lebar elemen input dan tambahkan kelas kesalahan untuk hal yang sama. Perhatikan bahwa kode di bawah ini hanya berisi gaya yang perlu ditambahkan atau diperbarui. Kode yang tersisa tetap tak tersentuh.

1
input {
2
    width: 179px;
3
    &.error {
4
        background: #ffefef;
5
        color: #4c1717;
6
        border: 1px solid #4c1717;
7
    }
8
}

Kita juga perlu menambah tinggi #content.wrapper.panel.right.

1
height: 433px;

Terakhir, mari tambahkan margin kanan ke gambar footer.

1
footer {
2
    div.wrapper {
3
        img {
4
            margin-right: 5px;
5
        }
6
    }
7
}

Sebelum berpindah, mari lakukan perubahan:

1
git add .
2
git commit -m 'Added static files'

Selanjutnya, mari buat template dasar, yang akan diwarisi oleh semua template lain. Django menggunakan mesin templatingnya sendiri (seperti ERB atau Jade). Tentukan template dalam ribbit/templates/base.html dengan konten berikut:

1
<!DOCTYPE html>
2
<html>
3
<head>
4
    <link rel="stylesheet/less" href="{{ STATIC_URL }}style.less">
5
    <script src="{{ STATIC_URL }}less.js"></script>
6
</head>
7
<body>
8
    <header>
9
        <div class="wrapper">
10
            <img src="{{ STATIC_URL }}gfx/logo.png">
11
            <span>Twitter Clone</span>
12
            {% block login %}
13
            <a href="/">Home</a>
14
            <a href="/users/">Public Profiles</a>
15
            <a href="/users/{{ username }}">My Profile</a>
16
            <a href="/ribbits">Public Ribbits</a>
17
            <form action="/logout">
18
                <input type="submit" id="btnLogOut" value="Log Out">
19
            </form>
20
            {% endblock %}
21
        </div>
22
    </header>
23
    <div id="content">
24
        <div class="wrapper">
25
            {% block flash %}
26
            {% if auth_form.non_field_errors or user_form.non_field_errors or ribbit_form.errors %}
27
            <div class="flash error">
28
                {{ auth_form.non_field_errors }}
29
                {{ user_form.non_field_errors }}
30
                {{ ribbit_form.content.errors }}
31
            </div>
32
            {% endif %}
33
            {% if notice %}
34
            <div class="flash notice">
35
                {{ notice }}
36
            </div>
37
            {% endif %}
38
            {% endblock %}
39
40
            {% block content %}
41
42
            {% endblock %}
43
        </div>
44
    </div>
45
    <footer>
46
        <div class="wrapper">
47
            Ribbit - A Twitter Clone Tutorial
48
            <a href="http://net.tutsplus.com">
49
                <img src="{{ STATIC_URL }}gfx/logo-nettuts.png">
50
            </a>
51
            <a href="http://www.djangoproject.com/">
52
                <img src="https://www.djangoproject.com/m/img/badges/djangomade124x25.gif" border="0" alt="Made with Django." title="Made with Django." />
53
            </a>
54
        </div>
55
    </footer>
56
</body>
57
</html>

Pada markup di atas, {{ STATIC_URL }} mencetak lintasan untuk url statis yang ditentukan di settings.py. Fitur lainnya adalah penggunaan blok. Semua konten blok diwariskan ke sub-kelas dari template dasar, dan tidak akan ditimpa kecuali blok secara eksplisit didefinisikan ulang di dalamnya. Ini memberi kita fleksibilitas untuk menempatkan tautan navigasi di tajuk dan menggantinya dengan formulir masuk jika pengguna tidak masuk. Kita juga menggunakan blok dengan kondisi if untuk memeriksa apakah salah satu variabel flash tidak kosong dan merender pesan dengan tepat.

Baiklah! Saatnya membuat komitmen lain:

1
git add .
2
git commit -m 'Created base template'

Langkah 3 - Membuat Model

Salah satu hal terbaik tentang Django adalah bahwa ia menyertakan beberapa model dan bentuk, yang dapat dikesampingkan untuk memenuhi berbagai tujuan. Untuk aplikasi, kita akan menggunakan model User dan menambahkan beberapa properti ke dalamnya dengan membuat Model UserProfile. Lebih lanjut, untuk mengelola pita, kita juga akan membuat Model Ribbit. Model User yang disediakan oleh Django mencakup bidang untuk menyimpan nama pengguna, kata sandi, nama depan dan belakang dan alamat email (dengan validasi) bersama dengan banyak lainnya. Saya menyarankan Anda untuk melihat API untuk mengetahui tentang semua bidang yang didukung secara default. Tambahkan kode berikut untuk model di ribbit_app/models.py.

1
from django.db import models
2
from django.contrib.auth.models import User
3
import hashlib
4
5
6
class Ribbit(models.Model):
7
    content = models.CharField(max_length=140)
8
    user = models.ForeignKey(User)
9
    creation_date = models.DateTimeField(auto_now=True, blank=True)
10
11
12
class UserProfile(models.Model):
13
    user = models.OneToOneField(User)
14
    follows = models.ManyToManyField('self', related_name='followed_by', symmetrical=False)
15
16
    def gravatar_url(self):
17
        return "http://www.gravatar.com/avatar/%s?s=50" % hashlib.md5(self.user.email).hexdigest()
18
19
20
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])

Mari kita mulai dengan Model Ribbit. Atribut termasuk CharField dengan panjang maksimum 140 karakter untuk menyimpan konten, model ForeignKey to User (sehingga kita memiliki hubungan antara dua model) dan DateTimeField yang secara otomatis diisi dengan waktu ketika instance dari model disimpan.

Pindah ke Model UserProfile, kita memiliki bidang OneToOne yang mendefinisikan hubungan Satu ke Satu dengan Model User dan bidang ManyToMany untuk menerapkan hubungan follows/followed_by. Parameter related_name memungkinkan kita untuk menggunakan relasi mundur menggunakan nama pilihan kita. Kita juga telah menetapkan symmetrical ke False untuk memastikan bahwa jika Pengguna A mengikuti B maka Pengguna B tidak secara otomatis mengikuti A. Kita juga telah mendefinisikan fungsi untuk mendapatkan tautan ke gambar gravatar berdasarkan url pengguna dan properti untuk dapatkan (jika UserProfile ada untuk pengguna) atau buat satu saat kita menggunakan sintaks <user_object>.profile. Ini memungkinkan kita untuk mengambil properti UserProfile dengan mudah. Berikut ini contoh bagaimana Anda dapat menggunakan ORM untuk mendapatkan pengguna bahwa User yang diberikan mengikuti dan diikuti oleh:

1
superUser = User.object.get(id=1)
2
superUser.profile.follows.all() # Will return an iterator of UserProfile instances of all users that superUser follows

3
superUse.profile.followed_by.all() # Will return an iterator of UserProfile instances of all users that follow superUser

Sekarang setelah model kita ditentukan, mari hasilkan migrasi dan terapkan:

1
python manage.py schemamigration ribbit_app --auto
2
python manage.py migrate ribbit_app

Sebelum melanjutkan, mari lakukan perubahan

1
git add .
2
git commit -m 'Created Models'

Langkah 4 - Membuat Formulir

Django memungkinkan kita untuk membuat formulir sehingga kita dapat dengan mudah memvalidasi data yang diterima oleh pengguna untuk ketidakberesan. Kita akan membuat formulir kustom untuk Model Ribbit dan membuat formulir yang mewarisi UserCreationForm yang disediakan secara default untuk mengelola pendaftaran. Untuk mengelola otentikasi, kita akan memperluas AuthenticationForm yang disediakan secara default di Django. Mari buat file baru ribbit_app/forms.py dan tambahkan impor.

1
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
2
from django.contrib.auth.models import User
3
from django import forms
4
from django.utils.html import strip_tags
5
from ribbit_app.models import Ribbit

Mari kita mulai dengan membuat formulir pendaftaran. Kita akan menamakannya UserCreateForm dan kode itu diberikan di bawah ini:

1
class UserCreateForm(UserCreationForm):
2
    email = forms.EmailField(required=True, widget=forms.widgets.TextInput(attrs={'placeholder': 'Email'}))
3
    first_name = forms.CharField(required=True, widget=forms.widgets.TextInput(attrs={'placeholder': 'First Name'}))
4
    last_name = forms.CharField(required=True, widget=forms.widgets.TextInput(attrs={'placeholder': 'Last Name'}))
5
    username = forms.CharField(widget=forms.widgets.TextInput(attrs={'placeholder': 'Username'}))
6
    password1 = forms.CharField(widget=forms.widgets.PasswordInput(attrs={'placeholder': 'Password'}))
7
    password2 = forms.CharField(widget=forms.widgets.PasswordInput(attrs={'placeholder': 'Password Confirmation'}))
8
9
    def is_valid(self):
10
        form = super(UserCreateForm, self).is_valid()
11
        for f, error in self.errors.iteritems():
12
            if f != '__all_':
13
                self.fields[f].widget.attrs.update({'class': 'error', 'value': strip_tags(error)})
14
        return form
15
16
    class Meta:
17
        fields = ['email', 'username', 'first_name', 'last_name', 'password1',
18
                  'password2']
19
        model = User

Dalam formulir di atas, kita telah secara eksplisit mengatur beberapa bidang sebagai wajib dengan meneruskan required=True. Selanjutnya, saya telah menambahkan atribut placeholder ke berbagai widget yang digunakan oleh formulir. Kelas bernama error juga ditambahkan ke bidang yang berisi kesalahan. Ini dilakukan dalam fungsi is_valid(). Akhirnya, di kelas Meta, kita dapat menentukan urutan di mana kita ingin bidang formulir kita untuk membuat dan mengatur model terhadap mana formulir harus divalidasi.

Selanjutnya, mari tulis formulir untuk autentikasi:

1
class AuthenticateForm(AuthenticationForm):
2
    username = forms.CharField(widget=forms.widgets.TextInput(attrs={'placeholder': 'Username'}))
3
    password = forms.CharField(widget=forms.widgets.PasswordInput(attrs={'placeholder': 'Password'}))
4
5
    def is_valid(self):
6
        form = super(AuthenticateForm, self).is_valid()
7
        for f, error in self.errors.iteritems():
8
            if f != '__all__':
9
                self.fields[f].widget.attrs.update({'class': 'error', 'value': strip_tags(error)})
10
        return form

Seperti pada UserCreateForm, AuthenticateForm menambahkan beberapa placeholder dan kelas error.

Akhirnya, mari kita selesaikan formulir, untuk menerima Ribbit baru.

1
class RibbitForm(forms.ModelForm):
2
    content = forms.CharField(required=True, widget=forms.widgets.Textarea(attrs={'class': 'ribbitText'}))
3
4
    def is_valid(self):
5
        form = super(RibbitForm, self).is_valid()
6
        for f in self.errors.iterkeys():
7
            if f != '__all__':
8
                self.fields[f].widget.attrs.update({'class': 'error ribbitText'})
9
        return form
10
11
    class Meta:
12
        model = Ribbit
13
        exclude = ('user',)

Opsi pengecualian di kelas Meta di atas mencegah bidang pengguna dirender. Kita tidak membutuhkannya karena pengguna Ribbit akan diputuskan dengan menggunakan sesi.

Mari lakukan perubahan yang telah kita buat sejauh ini

1
git add .
2
git commit -m 'Created Forms'

Langkah 5 - Menerapkan Pendaftaran dan Login

Django menawarkan fleksibilitas yang hebat dalam hal routing. Mari kita mulai dengan menentukan beberapa rute di ribbit/urls.py.

1
urlpatterns = patterns('',
2
    # Examples:

3
    url(r'^$', 'ribbit_app.views.index'), # root

4
    url(r'^login$', 'ribbit_app.views.login_view'), # login

5
    url(r'^logout$', 'ribbit_app.views.logout_view'), # logout

6
    url(r'^signup$', 'ribbit_app.views.signup'), # signup

7
)

Selanjutnya, mari kita menggunakan model dan formulir yang baru saja kita buat dan tulis tampilan yang terkait untuk setiap rute yang baru saja kita tetapkan.. Mari kita mulai dengan menambahkan impor di ribbit_app/views.py.

1
from django.shortcuts import render, redirect
2
from django.contrib.auth import login, authenticate, logout
3
from django.contrib.auth.models import User
4
from ribbit_app.forms import AuthenticateForm, UserCreateForm, RibbitForm
5
from ribbit_app.models import Ribbit

Diikuti oleh tampilan indeks:

1
def index(request, auth_form=None, user_form=None):
2
    # User is logged in

3
    if request.user.is_authenticated():
4
        ribbit_form = RibbitForm()
5
        user = request.user
6
        ribbits_self = Ribbit.objects.filter(user=user.id)
7
        ribbits_buddies = Ribbit.objects.filter(user__userprofile__in=user.profile.follows.all)
8
        ribbits = ribbits_self | ribbits_buddies
9
10
        return render(request,
11
                      'buddies.html',
12
                      {'ribbit_form': ribbit_form, 'user': user,
13
                       'ribbits': ribbits,
14
                       'next_url': '/', })
15
    else:
16
        # User is not logged in

17
        auth_form = auth_form or AuthenticateForm()
18
        user_form = user_form or UserCreateForm()
19
20
        return render(request,
21
                      'home.html',
22
                      {'auth_form': auth_form, 'user_form': user_form, })

Untuk tampilan indeks, pertama-tama periksa apakah pengguna masuk atau tidak dan render templatnya. Querysets ribbits_self dan ribbits_buddies digabungkan dengan | operator dalam kode di atas. Juga, kita memeriksa apakah instance dari formulir telah diteruskan ke metode (dalam definisi fungsi) dan jika tidak kita buat yang baru. Ini memungkinkan kita untuk mengirimkan instance formulir ke template yang sesuai dan merender kesalahan.

Mari lanjutkan dengan mengedit 'home.html' template yang akan digunakan untuk menampilkan halaman indeks untuk pengguna anonim. Dalam file ribbit/templates/home.html, tambahkan kode berikut.

1
{% extends "base.html" %}
2
3
{% block login %}
4
    <form action="/login" method="post">{% csrf_token %}
5
        {% for field in auth_form %}
6
        {{ field }}
7
        {% endfor %}
8
        <input type="submit" id="btnLogIn" value="Log In">
9
    </form>
10
{% endblock %}
11
12
{% block content %}
13
{% if auth_form.non_field_errors or user_form.non_field_errors %}
14
<div class="flash error">
15
    {{ auth_form.non_field_errors }}
16
    {{ user_form.non_field_errors }}
17
</div>
18
{% endif %}
19
<img src="{{ STATIC_URL}}gfx/frog.jpg">
20
<div class="panel right">
21
    <h1>New to Ribbit?</h1>
22
    <p>
23
        <form action="/signup" method="post">{% csrf_token %}
24
            {% for field in user_form %}
25
            {{ field }}
26
            {% endfor %}
27
            <input type="submit" value="Create Account">
28
        </form>
29
    </p>
30
</div>
31
{% endblock %}

Dalam template, kita mewarisi template dasar yang didefinisikan sebelumnya, merender otentikasi dan mendaftar formulir dengan mengganti blok login. Suatu hal yang rapi tentang Django adalah bahwa itu membuat CSRF Protection cukup mudah! Yang perlu Anda lakukan adalah menambahkan csrf_token di setiap formulir yang Anda gunakan dalam template.

Mari kita lanjutkan ke template buddies.html, yang akan menampilkan halaman Ribbit Sobat. Edit ribbit/templates/buddies.html dan tambahkan kode berikut:

1
{% extends "base.html" %}
2
{% block login %}
3
    {% with user.username as username %}
4
        {{ block.super }}
5
    {% endwith %}
6
{% endblock %}
7
8
{% block content %}
9
    <div class="panel right">
10
        <h1>Create a Ribbit</h1>
11
        <p>
12
            <form action="/submit" method="post">
13
            {% for field in ribbit_form %}{% csrf_token %}
14
            {{ field }}
15
            {% endfor %}
16
            <input type="hidden" value="{{ next_url }}" name="next_url">
17
            <input type="submit" value="Ribbit!">
18
            </form>
19
        </p>
20
    </div>
21
    <div class="panel left">
22
        <h1>Buddies' Ribbits</h1>
23
        {% for ribbit in ribbits %}
24
        <div class="ribbitWrapper">
25
            <a href="/users/{{ ribbit.user.username }}">
26
                <img class="avatar" src="{{ ribbit.user.profile.gravatar_url }}">
27
                <span class="name">{{ ribbit.user.first_name }}</span>
28
            </a>
29
            @{{ ribbit.user.username }}
30
            <p>
31
                {{ ribbit.content }}
32
            </p>
33
        </div>
34
        {% endfor %}
35
    </div>
36
{% endblock %}

Dalam template ini, kita menyediakan template induk yaitu base.html dengan nilai nama pengguna sehingga tautan navigasi untuk yang tercatat dalam profil User dirender dengan benar. Kita juga menggunakan turunan RibbitForm untuk menerima Ribbits baru dan mengulanginya dan menunjukkan pita saat ini oleh teman-teman.

Dengan templat selesai, mari kita lanjutkan dan menulis kode untuk masuk/keluar pengguna. Tambahkan kode berikut ke ribbit_app/views.py

1
def login_view(request):
2
    if request.method == 'POST':
3
        form = AuthenticateForm(data=request.POST)
4
        if form.is_valid():
5
            login(request, form.get_user())
6
            # Success

7
            return redirect('/')
8
        else:
9
            # Failure

10
            return index(request, auth_form=form)
11
    return redirect('/')
12
13
14
def logout_view(request):
15
    logout(request)
16
    return redirect('/')

Pandangan untuk login mengharapkan permintaan HTTP POST untuk login (karena metode form adalah POST). Ini memvalidasi formulir dan, jika berhasil, login pengguna menggunakan login() metode yang memulai sesi dan kemudian mengarahkan ke url root. Jika validasi gagal, kita meneruskan instance dari auth_form yang diterima dari pengguna ke fungsi indeks dan daftar kesalahan, sedangkan, jika permintaan tidak POST maka pengguna diarahkan ke url root.

Tampilan logout relatif lebih sederhana. Ini memanfaatkan fungsi logout() di Django yang menghapus sesi dan log pengguna keluar diikuti dengan mengarahkan ke url root.

Kita sekarang perlu menulis tampilan untuk mendaftar dan mendaftarkan pengguna. Tambahkan kode berikut ke ribbit_app/views.py.

1
def signup(request):
2
    user_form = UserCreateForm(data=request.POST)
3
    if request.method == 'POST':
4
        if user_form.is_valid():
5
            username = user_form.clean_username()
6
            password = user_form.clean_password2()
7
            user_form.save()
8
            user = authenticate(username=username, password=password)
9
            login(request, user)
10
            return redirect('/')
11
        else:
12
            return index(request, user_form=user_form)
13
    return redirect('/')

Mirip dengan tampilan login, tampilan pendaftaran mengharapkan permintaan POST juga dan mengarahkan ke url root jika cek gagal. Jika formulir Sign Up valid, pengguna disimpan ke database, dikonfirmasi, masuk dan kemudian dialihkan ke halaman beranda. Jika tidak, kita memanggil fungsi indeks dan meneruskan instance dari user_form yang dikirimkan oleh pengguna untuk daftar kesalahan.

Mari kita periksa kemajuan kami dengan memulai server dan menguji pandangan yang telah kami tulis sejauh ini secara manual.

1
python manage.py runserver

Mari kunjungi Server Pengembangan kita dan coba daftarkan pengguna baru. Jika semua berjalan dengan baik, Anda harus disajikan dengan halaman 'Ribbits Teman'. Kita dapat keluar dan mengautentikasi ulang pengguna yang baru dibuat untuk memeriksa apakah fungsi masuk berfungsi seperti yang diharapkan.

Buddies

Saatnya melakukan perubahan!

1
git add .
2
git commit -m 'Implemented User Login and Sign Up'

Langkah 6 - Menerima Ribbits baru dan Cantumkan Ribbits Publik

Dalam template buddies.html yang dibuat sebelumnya, ribbit_form telah dikirim ke /submit. Mari kita edit ribbit/urls.py dan tambahkan rute untuk formulir dan halaman untuk mencantumkan semua ribbits publik.

1
urlpatterns = patterns('',
2
    # Examples:

3
    url(r'^$', 'ribbit_app.views.index'), # root

4
    url(r'^login$', 'ribbit_app.views.login_view'), # login

5
    url(r'^logout$', 'ribbit_app.views.logout_view'), # logout

6
    url(r'^ribbits$', 'ribbit_app.views.public'), # public ribbits

7
    url(r'^submit$', 'ribbit_app.views.submit'), # submit new ribbit

8
)

Mari menulis pandangan untuk memvalidasi dan menyimpan pita yang dikirim. Buka ribbit_app/views.py dan tambahkan kode berikut:

1
from django.contrib.auth.decorators import login_required
2
3
@login_required
4
def submit(request):
5
    if request.method == "POST":
6
        ribbit_form = RibbitForm(data=request.POST)
7
        next_url = request.POST.get("next_url", "/")
8
        if ribbit_form.is_valid():
9
            ribbit = ribbit_form.save(commit=False)
10
            ribbit.user = request.user
11
            ribbit.save()
12
            return redirect(next_url)
13
        else:
14
            return public(request, ribbit_form)
15
    return redirect('/')

Tampilan menggunakan dekorator @login_required, yang hanya menjalankan fungsi jika pengguna diautentikasi; lain, pengguna dialihkan ke jalur yang ditentukan dalam LOGIN_URL konstan dalam pengaturan. Jika validasi form berhasil, kita secara manual mengatur pengguna ke yang ada dalam sesi dan kemudian menyimpan catatan. Setelah database komit, pengguna diarahkan ke jalur yang ditentukan dalam bidang next_url yang merupakan bidang formulir tersembunyi yang secara manual dimasukkan dalam template untuk tujuan ini. Nilai next_url diteruskan dalam tampilan yang merender Form Ribbit.

Pindah, mari kita menulis pandangan ke daftar 10 Ribbit Publik terakhir. Tambahkan hal berikut di ribbit_app/views.py

1
@login_required
2
def public(request, ribbit_form=None):
3
    ribbit_form = ribbit_form or RibbitForm()
4
    ribbits = Ribbit.objects.reverse()[:10]
5
    return render(request,
6
                  'public.html',
7
                  {'ribbit_form': ribbit_form, 'next_url': '/ribbits',
8
                   'ribbits': ribbits, 'username': request.user.username})

Di tampilan publik, kita meminta database untuk 10 ribbits terakhir dengan mengiris queryset ke 10 elemen terakhir. Bentuk bersama dengan ribbits kemudian diberikan ke template. Mari buat ribbit/templates/public.html untuk tampilan ini

1
{% extends "base.html" %}
2
3
{% block content %}
4
    <div class="panel right">
5
        <h1>Create a Ribbit</h1>
6
        <p>
7
            <form action="/submit" method="post">
8
            {% for field in ribbit_form %}{% csrf_token %}
9
            {{ field }}
10
            {% endfor %}
11
            <input type="hidden" value="{{ next_url }}" name="next_url">
12
            <input type="submit" value="Ribbit!">
13
            </form>
14
        </p>
15
    </div>
16
    <div class="panel left">
17
        <h1>Public Ribbits</h1>
18
        {% for ribbit in ribbits %}
19
        <div class="ribbitWrapper">
20
            <img class="avatar" src="{{ ribbit.user.profile.gravatar_url }}">
21
            <span class="name">{{ ribbit.user.first_name }}</span>@{{ ribbit.user.username }}
22
            <span class="time">{{ ribbit.creation_date|timesince }}</span>
23
            <p>{{ ribbit.content }}</p>
24
        </div>
25
        {% endfor %}
26
    </div>
27
{% endblock %}

Saat mengulang objek ribbit, template menggunakan tag template timesince untuk secara otomatis menentukan perbedaan waktu antara tanggal pembuatan rusuk dan waktu saat ini, dan mencetaknya dengan cara seperti Twitter.

Memastikan bahwa server pengembangan sedang berjalan, buatlah sebuah ribbit baru dan lihatlah halaman Public Ribbits untuk memastikan semuanya baik-baik saja.

First Ribbit

Mari lakukan perubahan sebelum melanjutkan:

1
git add .
2
git commit -m 'Implemented Ribbit Submission and Public Ribbits Views'

Langkah 7 - User Profiles dan Following Users

Sebuah klon twitter, User Profiles dan Following Users berjalan beriringan. Mari tulis rute untuk menerapkan fungsi ini. Perbarui ribbit/urls.py dengan kode berikut:

1
urlpatterns = patterns('',
2
    # Examples:

3
    url(r'^$', 'ribbit_app.views.index'), # root

4
    url(r'^login$', 'ribbit_app.views.login_view'), # login

5
    url(r'^logout$', 'ribbit_app.views.logout_view'), # logout

6
    url(r'^ribbits$', 'ribbit_app.views.public'), # public ribbits

7
    url(r'^submit$', 'ribbit_app.views.submit'), # submit new ribbit

8
    url(r'^users/$', 'ribbit_app.views.users'),
9
    url(r'^users/(?P<username>\w{0,30})/$', 'ribbit_app.views.users'),
10
    url(r'^follow$', 'ribbit_app.views.follow'),
11
)

Rute yang menarik di atas adalah yang mengarahkan ke profil pengguna tertentu. <?P<username> menangkap nama pengguna yang ditanyakan melalui GET, dan \w{0,30} menegaskan bahwa panjang maksimum untuk nama pengguna adalah 30 karakter:

Selanjutnya, kita akan melanjutkan dengan menulis tampilan untuk membuat User Profiles. Tambahkan hal berikut di `ribbit_app/views.py '.

1
from django.db.models import Count
2
from django.http import Http404
3
4
5
def get_latest(user):
6
    try:
7
        return user.ribbit_set.order_by('-id')[0]
8
    except IndexError:
9
        return ""
10
11
12
@login_required
13
def users(request, username="", ribbit_form=None):
14
    if username:
15
        # Show a profile

16
        try:
17
            user = User.objects.get(username=username)
18
        except User.DoesNotExist:
19
            raise Http404
20
        ribbits = Ribbit.objects.filter(user=user.id)
21
        if username == request.user.username or request.user.profile.follows.filter(user__username=username):
22
            # Self Profile or buddies' profile

23
            return render(request, 'user.html', {'user': user, 'ribbits': ribbits, })
24
        return render(request, 'user.html', {'user': user, 'ribbits': ribbits, 'follow': True, })
25
    users = User.objects.all().annotate(ribbit_count=Count('ribbit'))
26
    ribbits = map(get_latest, users)
27
    obj = zip(users, ribbits)
28
    ribbit_form = ribbit_form or RibbitForm()
29
    return render(request,
30
                  'profiles.html',
31
                  {'obj': obj, 'next_url': '/users/',
32
                   'ribbit_form': ribbit_form,
33
                   'username': request.user.username, })

Pandangan ini mungkin yang paling menarik dari semua yang telah dibahas sejauh ini. Kita mulai dengan memastikan bahwa hanya pengguna yang masuk yang dapat melihat profil. Di rute yang kita tentukan di ribbit/urls.py, kita menulis satu untuk menangkap nama pengguna. Parameter yang ditangkap ini secara otomatis dipanggil bersama dengan objek permintaan dalam tampilan pengguna. Kita menemukan dua opsi untuk tampilan ini:

  • Nama pengguna diteruskan ke url untuk merender profil pengguna tertentu
  • Tidak ada nama pengguna yang disahkan yang berarti pengguna ingin melihat semua profil

Kita mulai dengan memeriksa apakah nama pengguna dilewatkan dan tidak kosong. Kemudian, kita mencoba mengambil objek User untuk nama pengguna yang sesuai. Perhatikan penggunaan blok tangkap percobaan dalam kode di atas. Kita hanya menaikkan pengecualian Http404 yang disediakan oleh Django untuk mengarahkan ke default 404 template. Selanjutnya, kita perlu memeriksa apakah profil yang diminta adalah pengguna yang masuk atau salah satu temannya. Jika demikian, kita tidak perlu membuat tautan mengikuti di profil karena relasi sudah ditetapkan. Jika tidak, kita meneruskan parameter follow berikut dalam tampilan untuk mencetak tautan Follow.

Pindah ke poin kedua, jika tidak ada nama pengguna yang diberikan dalam url, kita mengambil daftar semua pengguna dan menggunakan fungsi annotate() untuk menambahkan atribut ribbit_count ke semua objek, yang menyimpan jumlah Ribbits yang dibuat oleh setiap pengguna dalam kueri. Ini memungkinkan kita untuk menggunakan sesuatu di sepanjang baris <user_object>.ribbit_count untuk mengambil Ribbit Count dari pengguna.

Mendapatkan Ribbit terbaru oleh setiap pengguna agak sedikit rumit. Kita menggunakan Python yang dibangun di map() berfungsi untuk ini dan memanggil get_latest() ke semua elemen kueri pengguna. Fungsi get_latest() didefinisikan dalam kode di atas dan memanfaatkan relasi balik pada relasi User <--> Ribbit. Misalnya user.ribbit_set.all() akan mengembalikan semua ribbits oleh pengguna. Kita memesan ribbits dengan id dalam urutan menurun dan memotong elemen pertama. Kode ini diapit dalam blok try catch untuk menangkap pengecualian jika tidak ada ribbits yang dibuat oleh pengguna. Kita kemudian memanfaatkan fungsi Python zip() untuk menghubungkan setiap elemen dari kedua iterator (pengguna dan pita) sehingga kita memiliki tuple dengan Obyek Pengguna dan pasangan Ribbit Terbaru. Kita kemudian meneruskan objek zip ini bersama dengan formulir ke templat. Mari tulis tampilan terakhir yang akan menerima permintaan untuk mengikuti pengguna

1
from django.core.exceptions import ObjectDoesNotExist
2
3
@login_required
4
def follow(request):
5
    if request.method == "POST":
6
        follow_id = request.POST.get('follow', False)
7
        if follow_id:
8
            try:
9
                user = User.objects.get(id=follow_id)
10
                request.user.profile.follows.add(user.profile)
11
            except ObjectDoesNotExist:
12
                return redirect('/users/')
13
    return redirect('/users/')

Pada tampilan di atas, kita mendapatkan nilai follow parameter, dilewatkan oleh POST. Jika id diset, kita memeriksa apakah ada pengguna dan menambahkan relasinya, yang lain, kita menangkap pengecualian ObjectDoesNotExist dan mengalihkan pengguna ke halaman yang mencantumkan semua Profil Pengguna.

Kita sudah selesai dengan pandangan di sini. Mari tulis dua templat yang tersisa yang diperlukan untuk merender profil pengguna. Buka editor teks Anda dan edit ribbit/templates/profiles.html.

1
{% extends "base.html" %}
2
3
{% block content %}
4
    <div class="panel right">
5
        <h1>Create a Ribbit</h1>
6
        <p>
7
            <form action="/submit" method="post">
8
            {% for field in ribbit_form %}{% csrf_token %}
9
            {{ field }}
10
            {% endfor %}
11
            <input type="hidden" value="{{ next_url }}" name="next_url">
12
            <input type="submit" value="Ribbit!">
13
            </form>
14
        </p>
15
    </div>
16
    <div class="panel left">
17
        <h1>Public Profiles</h1>
18
        {% for user, ribbit in obj %}
19
        <div class="ribbitWrapper">
20
            <a href="/users/{{ user.username }}">
21
                <img class="avatar" src="{{ user.profile.gravatar_url }}">
22
                <span class="name">{{ user.first_name }}</span>
23
            </a>
24
            @{{ user.username }}
25
            <p>
26
                {{ user.ribbit_count}} Ribbits
27
                <span class="spacing">{{ user.profile.followed_by.count }} Followers</span>
28
                <span class="spacing">{{ user.profile.follows.count }} Following</span>
29
            </p>
30
            <p>{{ ribbit.content }}</p>
31
        </div>
32
        {% endfor %}
33
    </div>
34
{% endblock %}

Untuk membuat daftar pengguna bersama dengan ribbit terakhirnya, kita menggunakan konstruksi python umum untuk mengulang daftar tuple: for user, ribbit in obj. Di dalam loop kita mencetak informasi tentang pengguna bersama dengan statistik ribbit-nya. Perhatikan penggunaan relasi backward di {{user.profile.followed_by.count}}. following_by adalah nama terkait yang kita tetapkan saat mendefinisikan atribut ManyToManyField untuk Model UserProfile.

Akhirnya, mari tulis template untuk mencantumkan profil pengguna tertentu. Tuliskan kode berikut dalam ribbit/templates/user.html.

1
{% extends "base.html" %}
2
{% block login %}
3
    {% with user.username as username %}
4
        {{ block.super }}
5
    {% endwith %}
6
{% endblock %}
7
8
{% block content %}
9
    <div class="panel left">
10
        <h1>{{ user.first_name }}'s Profile</h1>
11
        <div class="ribbitWrapper">
12
            <a href="/users/{{ user.username }}">
13
                <img class="avatar" src="{{ user.profile.gravatar_url }}">
14
                <span class="name">{{ user.first_name }}</span>
15
            </a>
16
                @{{ user.username }}
17
            <p>
18
                {{ ribbits.count }} Ribbits
19
                <span class="spacing">{{ user.profile.follows.all.count }} Following</span>
20
                <span class="spacing">{{ user.profile.followed_by.all.count }} Followers</span>
21
            </p>
22
            {% if follow %}
23
            <form action="/follow" method="post">
24
                {% csrf_token %}
25
                <input type="hidden" name="follow" value="{{ user.id }}">
26
                <input type="submit" value="Follow">
27
            </form>
28
            {% endif %}
29
        </div>
30
    </div>
31
32
    <div class="panel left">
33
        <h1>{{ user.first_name }}'s Ribbits</h1>
34
        {% for ribbit in ribbits %}
35
        <div class="ribbitWrapper">
36
            <a href="/users/{{ user.username }}">
37
                <img class="avatar" src="{{ user.profile.gravatar_url }}">
38
                <span class="name">{{ ribbit.user.first_name }}</span>
39
            </a>
40
            @{{ ribbit.user.username }}
41
            <span class="time">{{ ribbit.creation_date|timesince }}</span>
42
            <p>{{ ribbit.content }}</p>
43
        </div>
44
        {% endfor %}
45
    </div>
46
{% endblock %}

Seperti di template buddies.html, kita meneruskan nama pengguna dari template yang sudah masuk ke template induk menggunakan konstruksi {% with%}. Selanjutnya, kita menampilkan profil pengguna dan menampilkan tautan berikut hanya jika variabel follow disetel ke True. Setelah itu, kita daftar semua ribbits yang dibuat oleh pengguna dengan iterasi atas variabel ribbits.

Kita akhirnya selesai dengan semua tampilan dan templat. Jelajahi semua tautan dan coba pengguna dummy berikut dan jelajahi klon Twitter yang baru saja Anda buat.

Mari lakukan perubahan:

1
git add .
2
git commit -m 'Implemented User Profiles and Following Relation on frontend'

Langkah 8 - Deployment ke Heroku

Saya lebih suka menjaga cabang pengembangan dan produksi saya terpisah; git membuat percabangan menjadi mudah. Jalankan terminal dan laksanakan yang berikut:

1
git branch -b production

Ini akan membuat cabang produksi dan segera beralih ke sana. Mari perbarui file .gitignore dan tambahkan database ke dalamnya. Isinya seharusnya

1
*.pyc
2
ribbit/database.db

Mari instal beberapa paket ke virtualenv yang diperlukan untuk penyebaran.

1
pip install psycopg2 dj-database-url gunicorn

Kita juga akan membuat file dengan semua dependensi proyek sehingga mereka diambil oleh Heroku.

1
pip freeze > requirements.txt

Selanjutnya, mari kita edit ribbit/settings.py. Pengaturan basis data harus diubah seperti.

1
DATABASES = {
2
    'default': {
3
        'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.

4
        'NAME': 'ribbit',                      # Or path to database file if using sqlite3.

5
        'USER': 'username',                      # Not used with sqlite3.

6
        'PASSWORD': 'password',                  # Not used with sqlite3.

7
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.

8
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.

9
    }
10
}

Di akhir file, tambahkan yang berikut ini sehingga Heroku dapat mengetahui pengaturan basis data.

1
import dj_database_url
2
3
DATABASES['default'] = dj_database_url.config()

Mari buat Procfile untuk memulai proses di server Heroku. Tempatkan yang berikut ini dalam sebuah file, bernama Procfile.

1
web: gunicorn ribbit.wsgi

Selain itu, jika aplikasi Anda tidak berskala besar, Anda dapat melewati layanan penyimpanan dengan menambahkan rute untuk file statis di dalam ribbit/urls.py

1
urlpatterns += patterns('django.contrib.staticfiles.views',
2
        url(r'^static/(?P<path>.*)$', 'serve'),
3
    )

Kita sudah siap! Mari lakukan perubahan ini:

1
git commit -a -m 'Configured for Production'

Akhirnya, kita akan membuat aplikasi Heroku dan mendorong repo ke repositori jarak jauh:

1
heroku create
2
git push heroku production:master

Setelah file ditransfer, jalankan syncdb dan terapkan migrasi ke database.

1
heroku run python manage.py syncdb
2
heroku run python manage.py migrate ribbit_app

Terakhir, buka aplikasi yang diterapkan dengan:

1
heroku open

Kesimpulan

Kita akhirnya selesai dengan Ribbit di Django! Tutorial ini cukup panjang, memang, dan aplikasi masih memiliki lebih banyak potensi yang dapat diimplementasikan. Saya harap, jika Anda baru mengenal Django, artikel ini telah mendorong Anda untuk menggali lebih dalam.

Jangan ragu untuk bermain bersama dengan penyebaran saya di Heroku. Jika Anda memiliki pertanyaan, saya akan senang menjawab dan semua pertanyaan.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.