Menulis aplikasi Django pertama anda, bagian 3

Tutorial ini mulai dimana Tutorial 2 tinggalkan. Kami sedang melanjutkan aplikasi jejak pendapat jaringan dan akan fokus membuat antarmuka umum -- "tampilan".

Ikhtisar

Sebuah tampilan adalah "jenis" dari halaman Jaringan di aplikasi Django yang umumnya melayani fungsi khusus dan mempunyai cetakan khusus. Sebagai contoh, di aplikasi blog, anda mungkin mempunyai tampilan berikut:

  • Halaman rumah Blog -- menampilkan sedikit masukan terakhir.
  • Halaman "rincian" masukan -- halaman permalink untuk masukan tunggal.
  • Halaman arsip berdasarkan-tahun -- menampilkan semua bulan dengan masukan di tahun yang diberikan.
  • Halaman arsip berdasarkan-bulan -- menampilkan semua hari dengan masukan di bulan yang diberikan.
  • Halaman arsip berdasarkan-hari -- menampilkan semua masukan di hari yang diberikan.
  • Tindakan komentar -- menangani penempatan komentar pada masukan yang diberikan.

Di aplikasi jejak pendapat kami, kami akan mempunyai empat tampilan berikut:

  • Halaman "index" pertanyaan -- menampilkan sedikit pertanyaan terakhir.
  • Halaman "index" pertanyaan -- menampilkan teks pertanyaan, dengan tidak ada hasil tetapi dengan formulir untuk memilih.
  • Halaman "hasil" pertanyaan -- menampilkan hasil untuk pertanyaan tertentu.
  • Tindakan pilih -- menangani pemilihan untuk pilihan tertentu di pertanyaan tertentu.

Di Django, halaman jaringan dan isi lain dikirimkan oleh tampilan. Setiap tampilan diwakilkan dengan fungsi Phyton sederhana (atau cara, di kasus ini dari tampilan berbasis-kelas). Django akan memilih tampilan dengan menguji URL yang diminta (agar akurat, bagian dari URL setelah nama ranah).

Sekarang waktu anda di jaringan anda mungkin telah menemukan keindahan seperti "ME2/Sites/dirmod.asp?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B". Anda akan dipersilahkan untuk mengetahui bahwa Django mengizinkan kami lebih banyak elegan corak URL dari pada itu.

Corak URL adalah formulir umum sederhana dari URL - sebagai contoh: /newsarchive/<year>/<month>/.

Untuk mendapatkan URL pada tampilan, Django menggunakan apa yang dikenal sebagai 'URLconfs'. URLconfs memetakan corak URL (digambarkan sebagai regular expression) pada tampilan

Tutorial ini menyediakan perintah dasar di penggunaan dari URLconf, dan anda dapat menunjuk pada django.urls untuk informasi lebih.

Menulis tampilan lebih

Sekarang mari kita menambahkan tampilan lebih pada polls/views.py. Tampilan ini sedikit berbeda karena mereka mangambil argumen:

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

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

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

Ikat tampilan baru ini ke dalam modul polls.urls dengan menambahkan pemanggilan berikut url():

polls/urls.py
from django.conf.urls import url

from . import views

urlpatterns = [
    # ex: /polls/
    url(r'^$', views.index, name='index'),
    # ex: /polls/5/
    url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
    # ex: /polls/5/results/
    url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
    # ex: /polls/5/vote/
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

Lihatlah di perambah anda, pada "/polls/34/". Itu akan menjalankan cara detail() dan menampilkan ID apapun anda sediakan di URL. Coba "/polls/34/results/" dan "/polls/34/vote/" juga -- ini akan menampilkan hasil placeholder dan halaman pemilihan.

Ketika seseorang meminta sebuah halaman dari situs jaringan anda -- katakan, "/polls/34/", Django akan memuat modul Python mysite.urls karena itu ditunjuk oleh pengaturan ROOT_URLCONF. Dia menemukan variabel dinamai urlpatterns dan melewati regular expression berurutan. Setelah menemukan kecocokan pada '^polls/', dia mengupas teks yang cocok ("polls/") dan mengirim teks tersisa -- "34/" -- ke URLconf 'polls.urls' untuk pengolahan lanjut. Ada kecocokan r'^(?P<question_id>[0-9]+)/$', menghasilkan panggilan ke tampilan detail() seperti itu:

detail(request=<HttpRequest object>, question_id='34')

Bagian question_id='34'` datang dari (?P<question_id>[0-9]+). Menggunakan tanda kurung disekitar corak "menangkap" teks dicocokkan oleh corak itu dan dikirim sebagai argumen ke fungsi tampilan; ?P<question_id> menentukan nama yang akan digunakan untuk mencirikan corak dicocokkan; dan [0-9]+ adalah regular expression untuk mencocokkan urutan angka (yaitu sebuah angka).

Karena corak URL adalah regular expression, mereka sangat tidak terbatas pada apa yang anda dapat lakukan dengan mereka. Dan tidak perlu menambahkan rancangan jelek URL seperti .html -- meskipun anda ingin, dalamhal ini anda dapat melakukan sesuatu seperti ini:

url(r'^polls/latest\.html$', views.index),

Tetapi, jangan melakukan itu. Itu lucu.

Tulis tampilan yang sebenarnya melakukan sesuatu

Setiap tampilan bertanggung jawab untuk melakukan satu dari dua hal: mengembalikan sebuah obyek HttpResponse mengandung isi untuk halaman diminta, atau menimbulkan sebuah pengecualian seperti Http404. Sisanya terserah anda.

Tampilan anda dapat membaca rekaman dari basisdata, atau tidak. Dia dapat menggunakan cetakan sistem seperti DJango -- atau sistem cetakan Phyton pihak-ketiga -- atau tidak. Dia dapat membangkitkan berkas PDF, mengeluarkan XML, membuat berkas ZIP dengan cepat, apapun anda inginkan, menggunakan pustaka Phyton apapun anda inginkan.

Semua Django inginkan adalah HttpResponse. Atau sebuah pengecualian.

Karena sangat nyaman, mari kita menggunakan API basisdata Django sendiri, yang akan melingkupi di Tutorial 2. Ini satu tikaman pada tampilan index() baru, yang menampilka pertanyaan jejak pendapat 5 terakhir di sistem, dipisahkan oleh koma, menurut tanggal penerbitan:

polls/views.py
from django.http import HttpResponse

from .models import Question


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

# Leave the rest of the views (detail, results, vote) unchanged

Tidak ada masalah disini, meskipun: rancangan halaman adalah kode-keras di tampilan. Jika anda ingin merubah cara tampilan halaman, anda harus menyunting kode Phyton ini. Jadi mari kita menggunakan sistem cetakan Django untuk memisahkan rancangan dari Phyton dengan membuat cetakan yang tampilan dapat digunakan.

Pertama, buat direktori disebut templates di direktori``polls``. Django akan mencari cetakan disana.

Pengaturan TEMPLATES proyek anda menggambarkan bagaimana Django akan memuat dan membuat halaman. Pengaturan awal berkas mengkonfigurasikan backend DjangoTemplates yang pilihan APP_DIRS adalah disetel ke True. Berdasarkan kaidah DjangoTemplates mencari untuk subdirektori :cetakan" dalam setiap INSTALLED_APPS.

Dalam direktori templates anda telah buat, buat direktori lain disebut polls, dan dalam itu buat sebuah berkas disebut index.html. Dengan kata lain, cetakan anda harus di polls/templates/polls/index.html. Karena bagaimana pemuat cetakan app_directories bekerja seperti yang digambarkan diatas, anda dapat mengacu ke cetakan ini dalam Django hanya sebagai polls/index.html.

Namespacing cetakan

Sekarang kami mungkin dapat lolos dengan menaruh cetakan kami langsung di polls/templates (daripada membuat subdirektori polls lain), tetapi itu mungkin ide buruk. Django akan memilih cetakan pertama dia temukan yang namanya cocok, dan jika anda mempunyai cetakan dengan nama sama di aplikasi berbeda. Django akan tidak dapat membedakan diantara mereka. Kami butuh dapat menunjuk Django satu yang benar, dan cara termudah untuk memastikan ini adalah dengan namespace mereka. Itu adalah, dengan menaruh cetakan tersebut didalam direktori lain dinamai untuk aplikasi itu sendiri.

Taruh kode berikut di cetakan itu:

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

Sekarang mari kita perbaharui tampilan index di polls/views.py untuk menggunakan cetakan:

polls/views.py
from django.http import HttpResponse
from django.template import loader

from .models import Question


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

Kode memuat cetakan disebut polls/index.html dan melewatkannya ke konteks. Konteks adalah kamus variabel cetakan pemetaan dinamai untuk obyek Phyton.

Muat halaman dengan menunjuk perambah anda pada "/polls/", dan anda akan melihat daftar-bullet mengandung pertanyaan "Ada apa" dari Tutorial 2. Tautan menunjuk ke halaman rincian pertanyaan.

Jalan pintas: render()

Itu adalah dialek umum untuk memuat cetakan, isi konteks dan mengembalikan sebuah obyek HttpResponse dengan hasil dari cetakan dibuat. Django menyediakan jalan pintas. Disini tampilan index() penuh, ditulis kembali:

polls/views.py
from django.shortcuts import render

from .models import Question


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

Catat bahwa sekali kami telah selesaikan ini di semua tampilan ini, kami tidak lagi butuh mengimpor loader dan HttpResponse (anda akan ingin menjaga HttpResponse jika anda masih mempunyai potongan cara untuk detail, results, dan vote).

Fungsi render() mengambil permintaan obyek sebagai argumen pertamanya, nama cetakan sebagai argumen keduanya dan kamus sebagai pilihan argumen ketiganya. Dia mengembalikan sebuah obyek HttpResponse dari cetakan diberikan dibangun dengan konteks yang diberikan.

Menaikkan kesalahan 404

Sekarang, mari kita mengerjakan tampilan rincian pertanyaan -- halaman yang menampilkan teks pertanyaan untuk jejak pertanyaan yang diberikan. Inilah tampilan:

polls/views.py
from django.http import Http404
from django.shortcuts import render

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

Konsep baru disini: Tapilan memunculkan pengecualian Http404 jika sebuah pertanyaan dengan ID diminta tidak ada.

Kami akan berunding apa anda dapat taruh di cetakan polls/detail.html itu kemudian, tetapi jika anda suka mendapatkan cepat contoh diatas bekerja, sebuah berkas mengandung hanya:

polls/templates/polls/detail.html
{{ question }}

akan membantu anda mulai untuk sekarang.

Jalan pintas: get_object_or_404()

Adalah dialek umum untuk menggunakan get() dan menimbulkan Http404 jika obyek tidak ada. Django menyediakan jalan pintas. Ini tampilan detail()`, ditulis kembali:

polls/views.py
from django.shortcuts import get_object_or_404, render

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

Fungsi get_object_or_404() mengambil model Django sebagai argumen pertamanya dan angka sewenang-wenang dari kata kunci argumen, yang dia melalui fungsi get() dari pengelola model. Dia menimbulkan Http404 jika obyek tidak ada.

Filosofi

Kenapa kami menggunakan fungsi pembantu get_object_or_404() daripada otomatis menangkap pengecualian ObjectDoesNotExist pada tingkatan lebih tinggi, atau mempunyai API model menimbulkan Http404 daripada ObjectDoesNotExist?

Karena itu akan memasangkan lapisan model ke lapisan tampilan. Satu dari terutama sasaran rancangan dari Django adalah merawat sambungan longgar. Beberapa sambungan terkendali diperkenalkan di modul django.shortcuts.

Terdapat juga sebuah fungsi get_list_or_404(), yang bekerja hanya sebagai get_object_or_404() -- kecuali menggunakan filter() daripada get(). Itu memunculkan Http404 jika daftar kosong.

Gunakan sistem cetakan

Kembali ke tampilan detail() untuk aplikasi jejak pendapat kami. Diberikan variabel konteks question, disini adalah apa cetakan polls/detail.html mungkin kelihatan seperti:

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

Sistem cetakan menggunakan sintaks dot-lookup untuk mengakses atribut variabel. Di contoh dari {{ question.question_text }}, pertama Django melakukan lookup perkamusan pada obyek question. Kegagalan itu, dia mencoba sebuah atribut lookup -- yang bekerja, di kasus ini. Jika atribut lookup telah gagal, dia akan mencoba list-index lookup.

Pemanggilan-cara terjadi di {% for %} loop: question.choice_set.all adalah ditafsirkan sebagai kode Phyton question.choice_set.all(), yang mengembalikan berulang obyek Choice dan cocok untuk digunakan di etiket {% for %}.

Lihat panduan cetakan untuk lebih tentang cetakan.

Memindahkan URL kode keras di cetakan

Ingat, ketika kami menulis tautan ke pertanyaan di cetakan polls/index.html, tautan sebagian dikodekan keras seperti ini:

<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>

Masalah dengan kode keras ini, pendekatam pasangan-erat adalah bahwa dia menjadi menantang untuk merubah URL di proyek anda dengan banyak cetakan. Bagaimanapun, sejak anda menentukan nama argumen di fungsi url() di modul polls.urls, anda dapat memindahkan kepercayaan pada jalur URL khusus ditentukan di konfigurasi url anda dengan menggunakan etiket cetakan {% url %}:

<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

Cara ini bekerja adalah dengan mencari pengertian URL seperti yang ditentukan di modul polls.urls. Anda dapat melihat sebenarnya dimana nama URL dari 'rincian' ditentukan dibawah:

...
# the 'name' value as called by the {% url %} template tag
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
...

Jika anda ingin merubah URL dari tampilan rinci jejak pendapat ke sesuatu lain, mungkin ke sesuatu seperti polls/specifics/12/ dibandingkan melakukannya di cetakan (atau cetakan-cetakan) anda akan merubahnya di polls/urls.py:

...
# added the word 'specifics'
url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
...

Nama URL namespacing

Proyek tutorial hanya punya satu aplikasi, polls. Di proyek Django nyata, mungkin ada lima, sepuluh, dua puluh aplikasi atau lebih. Bagaimana Django membedakan nama URL diantara mereka? Sebagai contoh, aplikasi polls mempunyai tampilan detail, dan mungkin sebuah aplikasi di proyek sama yaitu untuk sebuah blog. Bagaimana satu membuatnya sehingga Django mengetahui tampilan aplikasi mana untuk membuat untuk sebuah url ketika menggunakan etiket cetakan {% url %}?

Jawabannya adalah menambahkan namespace ke URLconf anda. Di berkas polls/urls.py, lanjutkan dan tambah app_name untuk mengatur namespace aplikasi:

polls/urls.py
from django.conf.urls import url

from . import views

app_name = 'polls'
urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
    url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

Sekarang rubah cetakan polls/index.html anda dari:

polls/templates/polls/index.html
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

untuk menunjuk tampilan rincian namespace:

polls/templates/polls/index.html
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>

Ketika anda nyaman dengan tampilan penulisan, baca bagian 4 dari tutorial ini untuk mempelajari tentang bentuk sederhana pengolahan dan tampilan umum.

Back to Top