ในบทความนี้เรากำลังทำ web-poll application ต่อจากบทความที่แล้วและจะโฟกัสไปที่กระบวนการทำและ cut down โค้ดของ simple formWrite a simple form
ทำการอัพเดทรายละเอียดของ poll จากตัวอย่างอันที่แล้ว template ที่เป็น html formpolls/detail.html
<h1>{{ poll.question }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' poll.id %}" method="post">
{% csrf_token %}
{% for choice in poll.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 %}
<input type="submit" value="Vote" />
</form>
จากที่เราทำการ implementation ของ function vote ไว้ ตอนนี้เราจะทำการเพิ่มรายละเอียดของ function เพื่อจะรับ request กับ poll_id จาก นำมาตรวจสอบว่ามีการเลือก choice หรือไม่ ถ้าไม่จะเรียกหน้า polls/detail.html พร้อมส่ง error message แต่ถ้ามีการเลือกก็จะทำการเพิ่ม vote ของ choice นั้นๆ โดยทำการเพิ่มโค้ดใน polls/views.py ดังนี้polls/views.py
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse
from polls.models import Choice, Poll
# ...
def vote(request, poll_id):
p = get_object_or_404(Poll, pk=poll_id)
try:
selected_choice = p.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the poll voting form.
return render(request, 'polls/detail.html', {
'poll': p,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.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=(p.id,)))
ทดสอบการทำงานผ่าน browser
หน้าต่างเมื่อเข้ามาจาก หน้า index |
ทดสอบเลือก "The sky" |
แสดงข้อความหลังคลิก "Vote" ดังรูป |
ถ้าไม่เลือกอะไร จะแสดงข้อความ "You didn't select a choice." |
เช่นเดียวกันกับ function vote ต่อจานี้เราก็ทำการแก้ไขโค้ดใน function results เพื่อให้ function นี้แสดวผลโหวตของ choice ต่างๆ ว่ามีจำนวนโหวตเท่าไหร่ โดยทำการเพิ่มโค้ดใน polls/views.py ดังนี้polls/views.py
from django.shortcuts import get_object_or_404, render
def results(request, poll_id):
poll = get_object_or_404(Poll, pk=poll_id)
return render(request, 'polls/results.html', {'poll': poll})
และสร้าง results.html เพื่อเป็น templete ของส่วนแสดงผลนี้polls/results.html
<h1>{{ poll.question }}</h1>
<ul>
{% for choice in poll.choice_set.all %}
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>
<a href="{% url 'polls:detail' poll.id %}">Vote again?</a>
จากในตอนแรกจะขึ้นข้อความ "You're looking at the results of .." จะเปลี่ยนเป็นดังรูปด้านล่าง แสดงผลโหวตของแต่ละ choice
Use generic views: Less code is better
จากการเขียนโค้ดที่ผ่านมา ในฟังก์ชั่น detail(), results(), และ index() มันเป็นมุมมองพื้นฐานของ Web development เช่น การรับข้อมูลพารามิเตอร์จาก URL และการโหลด template และรีเทิร์น template กลับมาแสดงผล เป็นต้น จะเห็นว่าสิ่งเหล่านี้เป็นสิ่งทั่วไป Django จึงได้สร้างทางลัดที่เรียกว่าระบบ "generic views"
Generic views เป็็็นรูปแบบที่เป็นนามธรรม ซึ่งคุณไม่จำเป็็นต้องเขียน โค้ด python เพื่อที่จะเขียน app
มี 3 ขั้นตอนในการแปลงให้เป็น "generic views" ดังนี้้้1) ทำการแปลง URLconf
2) ลบมุมมองแบบเก่าและมุมมองที่เป็นจำเป็น
3) เข้าสู่มุมมองพื้้นฐาน ของ Django’s generic views
ขั้นตอนแรกจะทำการแปลง URLconf โดยทำการแก้ไข polls/urls.py
polls/urls.py
from django.conf.urls import patterns, url
from polls import views
urlpatterns = patterns('',
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
url(r'^(?P<pk>\d+)/results/$', views.ResultsView.as_view(), name='results'),
url(r'^(?P<poll_id>\d+)/vote/$', views.vote, name='vote'),
)
ขั้นตอนที่สองและสามนั้นให้ทำการลบฟังก์ชั่น detail(), results(), และ index() ออกและเพิ่มส่วนที่เป็น generic views เข้าไปแทนที่polls/views.py
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.views import generic
from polls.models import Choice, Poll
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_poll_list'
def get_queryset(self):
"""Return the last five published polls."""
return Poll.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
model = Poll
template_name = 'polls/detail.html'
class ResultsView(generic.DetailView):
model = Poll
template_name = 'polls/results.html'
def vote(request, poll_id):
....
โดยปกติถ้าเราไม่กำหนดไฟล์ template ของ ListView และ DetailView ทั้งสองจะเรียกไฟล์ชื่อ poll_list.html และ poll_detail.html ตามลำดับ
ทดสอบโดยแก้ไขดังโค้ดด้านล่างและสร้างไฟล์ poll/poll_list.htmlpolls/views.py
class IndexView(generic.ListView):
#template_name = 'polls/index.html'
#context_object_name = 'latest_poll_list'
...
ผลที่ได้จากการทดสอบ |
สามารถศึกษาเรื่อง generic views เพิ่มเติมได้ที่ generic views documentation
Reference
https://docs.djangoproject.com/en/1.6/intro/tutorial04/
https://docs.djangoproject.com/en/1.6/topics/class-based-views/
ไม่มีความคิดเห็น:
แสดงความคิดเห็น