Menulis aplikasi Django pertama anda, bagian 4¶
Tutorial ini memulai dimana Tutorial 3 ditinggalkan. Kami sedang melanjutkan aplikasi poling jaringan dan akan fokus pada pengolahan formulit dan memotong kode kami.
Dimana mendapatkan bantuan:
Jika anda memiliki masalah melalui tutorial ini, harap geser ke Getting Help bagian dari FAQ.
Tulis sebuah formulir minimal¶
Mari kita memperbaharui cetakan rincian jejak pendapat ("polls/detail.html") dari tutorial terakhir, sehingga cetakan mengandung sebuah unsur <form>
HTML:
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
<fieldset>
<legend><h1>{{ question.question_text }}</h1></legend>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
</fieldset>
<input type="submit" value="Vote">
</form>
Laporan cepat :
Cetakan diatas menampilkan tombol radio untuk setiap pilihan pertanyaan.
nilai
dari setiap tombol adalah ID pilihan pertanyaan dikaitkan.name
dari setiap tombol radio adalah"pilihan"
. itu berarti, ketika seseorang memilih satu dari tombol radio dan mengajukan formulir, itu akan mengirim data POSTchoice=#
dimana # adalah ID dari pilihan terpilih. Ini adalah konsep dasar dari formulir HTML.Kami mensetel
action
formulir menjadi{% url 'polls:vote' question.id %}
, dan kami mensetelmethod="post"
. Menggunakanmethod="post"
(sebagai lawanmethod="get"
) adalah sangat penting, karena tindakan mengajukan formulir ini akan merubah data sisi-peladen. Kapanpun anda membuat sebuah formulir yang merubah data sisi-peladen, gunakanmethod="post"
. Saran ini tidak khusus pada Django; itu adalah praktik pengembangan jaringan baik secara umum.forloop.counter
mengindikasikan seberapa kali theuntuk
etiket telah melalui putarannyaSejak kami membuat formulir POST (yang dapat memiliki pengaruh dari merubah data), kami perlu khawatir mengenai Cross Site Request Forgeries. Untungnya, anda tidak perlu khawatir terlalu keras, karena Django datang dengan sistem sangat membantu untuk perlindungan terhadapnya. Pendeknya, semua formulir POST yang menyasarkan pada URL dalam harus menggunakan etiket cetakan
{% csrf_token %}
.
Sekarang, mari kita membuat tampilan Django yang menangani data diajukan dan melakukan sesuatu dengannya. Ingat, di Tutorial 3, kami membuat URLconf untuk aplikasi jejak pendapat yang menyertakan baris ini:
path("<int:question_id>/vote/", views.vote, name="vote"),
Kami juga membuat penerapan tiruan dari fungsi vote()
. mari kita membuat versi sebenarnya. Tambah berikut ke polls/views.py
:
from django.db.models import F
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from .models import Choice, Question
# ...
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST["choice"])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(
request,
"polls/detail.html",
{
"question": question,
"error_message": "You didn't select a choice.",
},
)
else:
selected_choice.votes = F("votes") + 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse("polls:results", args=(question.id,)))
Kode ini menyertakan beberapa hal kami belum tangani di tutorial ini:
request.POST
adalah obyek seperti-kamus yang membiarkan anda akses data diajukan oleh nama kunci. Di kasus ini,request.POST['choice']
mengembalikan ID dari pilihan terpilih, sebagai string. Nilairequest.POST
selalu string.Catat bahwa Django juga menyediakan
request.GET
untuk mengakses data GET di cara sama -- tetapi kami eksplisit menggunakanrequest.POST
di kode kami, untuk memastikan bahwa data hanya diubah melalui panggilan POST.request.POST['choice']
akan menaikkanKeyError
jikapilihan
tidak disediakan di data POST. Kode diatas memeriksa untukKeyError
dan menampilkan kembali formulir pertanyaan dengan pesan kesalahan jikapilihan
tidak diberikan.F("votes") + 1
instructs the database to increase the vote count by 1.Setelah menaikkan jumlah pilihan, kode mengembalikan sebuah
HttpResponseRedirect
daripadaHttpResponse
biasa.HttpResponseRedirect
mengambil argumen tunggal: URL dimana pengguna akan dialihkan (lihat titik berikut untuk bagaimana membangun URL di kasus ini).Seperti ditunjukkan komentar Python diatas, aanda harus selalu mengembalikan
HttpResponseRedirect
setelah berhasil berurusan dengan data POST. Saran ini tidak khusus pada Django; itu adalah praktik pengembangan jaringan bagus secara umum.Kami sedang menggunakan fungsi
reverse()
di pembangunHttpResponseRedirect
di contoh ini. Fungsi ini membantu mengindari memiliki URL kode keras di fungsi tampilan. Itu diberikan nama dari tampilan yang kami ingin melewatkan kendali ke dan bagian variabel dari corak URL yang menunjuk ke tampilan itu. Dalam kasus ini, menggunakan URLconf kami setel di Tutorial 3, panggilanreverse()
ini akan mengembalikan deretan karakter seperti"/polls/3/results/"
dimana
3
adalah nilai dariquestion.id
. Ini URL dialihkan akan memanggil tampilan'results'
untuk menampilkan halaman akhir.
Seperti disebutkan di Tutorial 3, request
adalah sebuah obyek HttpRequest
. Untuk lebih pada obyek HttpRequest
, lihat permintaan dan tanggapan dokumentasi.
Setelah seseorang memilih di pertanyaan, tampilan vote()
mengalihkan ke halaman hasil untuk pertanyaan. Mari kita tulis tampilan itu:
from django.shortcuts import get_object_or_404, render
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, "polls/results.html", {"question": question})
Ini hampir tepat sama seperti tampilan detail()
dari Tutorial 3. Perbedaannya adalah hanya nama cetakan. Kami akan memperbaiki kelebihan ini kemudian.
Sekarang, buat cetakan polls/result.html
:
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>
<a href="{% url 'polls:detail' question.id %}">Vote again?</a>
Sekarang, pergi ke /polls/1/
di perambah anda dan pilih di pertanyaan. Anda seharusnya melihat halaman hasil yang mendapatkan pembaharuan setiap waktu anda memilih. Jika anda mengajukan formulir tanpa memilih pilihan, anda akan melihat pesan kesalahan.
Gunakan tampilan umum: Sedikit kode lebih baik¶
Tampilan detail()
(from Tutorial 3) dan results()
sangat pendek -- dand seperti disebutkan diatas, berlebih-lebihan. Tampilan index()
, yang menampilkan daftar dari jejak pendapat, adalah mirip.
Tampilan ini mewakili kasus umum dari pengembangan dasar jaringan: mendapatkan data dari basisdata menurut sebuah parameter dilewatkan dalam URL, membuat sebuah cetakan dan mengembalikan cetakan yang dibangun. Karena ini sudah umum, Django menyediakan jalan pintas, disebut sistem "generic views".
Generic views abstract common patterns to the point where you don't even need to
write Python code to write an app. For example, the
ListView
and
DetailView
generic views
abstract the concepts of "display a list of objects" and
"display a detail page for a particular type of object" respectively.
Mari rubah aplikasi jejak pendapat kami menggunakan sistem tampilan umum, sehingga kami dapat menghapus sekelompok dari kode milik kami. Kami harus mengambil beberapa langkah untuk membuat perubahan. Kami akan:
Rubah URLconf.
Hapus beberapa lama, tampilan tidak dibutuhkan.
Memperkenalkan tampilan baru berbasis pada tampilan umum Django.
Membaca untuk rinci.
Kenapa kode dikocok?
Umumnya, ketika menulis aplikasi Django, anda akan menilai apakah tampilan umum cocok untuk masalah anda, dan anda akan menggunakan mereka dari mulai, daripada mengurai kembali kode anda setengah jalan. Tetapi tutorial ini sengaja fokus pada penulisan tampilan "cara sulit" sampai sekarang, untuk fokus pada konsep inti.
Anda harus mengetahui matematika dasar sebelum mulai menggunakan penghitung.
Merubah URLconf¶
Pertama, buka URLconf polls/urls.py
dan rubah nya seperti itu:
from django.urls import path
from . import views
app_name = "polls"
urlpatterns = [
path("", views.IndexView.as_view(), name="index"),
path("<int:pk>/", views.DetailView.as_view(), name="detail"),
path("<int:pk>/results/", views.ResultsView.as_view(), name="results"),
path("<int:question_id>/vote/", views.vote, name="vote"),
]
Note that the name of the matched pattern in the path strings of the second and
third patterns has changed from <question_id>
to <pk>
. This is
necessary because we'll use the
DetailView
generic view to replace our
detail()
and results()
views, and it expects the primary key value
captured from the URL to be called "pk"
.
Merubah tampilan¶
Selanjutnya, kami akan memindahkan tampilan index
, detail
, dan results
lama dan menggunakan tampilan umum Django. Untuk melakukannya, buka berkas polls/views.py
dan rubah seperti itu:
from django.db.models import F
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from .models import Choice, Question
class IndexView(generic.ListView):
template_name = "polls/index.html"
context_object_name = "latest_question_list"
def get_queryset(self):
"""Return the last five published questions."""
return Question.objects.order_by("-pub_date")[:5]
class DetailView(generic.DetailView):
model = Question
template_name = "polls/detail.html"
class ResultsView(generic.DetailView):
model = Question
template_name = "polls/results.html"
def vote(request, question_id):
# same as above, no changes needed.
...
Each generic view needs to know what model it will be acting upon. This is
provided using either the model
attribute (in this example, model =
Question
for DetailView
and ResultsView
) or by defining the
get_queryset()
method (as
shown in IndexView
).
Secara awal, tampilan umum DetailView
menggunakan cetakan dipanggil <app name>/<model name>_detail.html
. Di kasus kami, dia akan menggunakan cetakan "polls/question_detail.html"
. Atribut template_name
digunakan untuk memberitahu Django untuk menggunakan cetakan spesifik dibandingkan dari nama cetakan awal otomatis dibangkitkan. Kami juga menentukan template_name
untuk tampilan daftar results
-- ini memastikan bahwa tampilan hasil dan tampilan rinci mempunyai penampilan ebrbeda ketika dibentuk, bahkan mereka berdua DetailView
dibelakang layar.
Demikian pula, tampilan umum ListView
menggunakan cetakan awal disebut <app name>/<model name>_list.html
; kami menggunakan template_name
untuk memberitahu ListView
untuk menggunakan cetakan "polls/index.html"
kami yang ada.
Dalam bagian sebelumnya dari tutorial, cetakan telah disediakan dengan sebuah konteks yang mengandung variabel konteks question
dan latest_question_list
. Untuk DetailView
variabel question
adalah disediakan otomatis -- sejak kami menggunakan model Django (Question
), Django dapat menentukan sebuah nama sesuai untuk variabel konteks. Bagaimanapun untuk ListView, variabel konteks dibangkitkan otomatos adalah question_list
. Untuk menimpa ini kami menyediakan atribut context_object_name
, menentukan apa yang kita ingin gunakan latest_question_list
. Sebagai sebuah pendekatan alternatif, anda dapat merubah cetakan anda untuk mencocokkan dengan variabel konteks awalan baru -- tetapi itu lebih mudah memberitahu Django untuk menggunakan varaibel anda inginkan.
Jalankan peladen, dan gunakan aplikasi jejak pendapat baru anda berdasarkan tampilan umum.
Untuk rincian penuh pada tampilan umum, lihat dokumentasi tampilan umum.
Ketika anda nyaman dengan formulir dan tampilan umum, baca bagian 5 dari tutorial ini untuk mempelajari tentang aplikasi jejak pendapat kami.