วันอังคารที่ 31 ธันวาคม พ.ศ. 2556

Assignment 3 - Python HTML Profile DB

Python HTML Profile DB


    โดยข้อมูลที่นำมาสร้างเป็น HTML Profile นี้นั้นกำหนดรูปแบบไว้เป็นไฟล์ .txt โดยข้อมูลของแต่ละคนจะใช้ความยาว 1 บรรทัดมีรูปแบบดังนี้
StudentID \Name \Surname \Nickname \Birthday \Age \Sex \Religion \Weight \Height \E-mail \Address \Facebook \Phone
ตัวอย่างข้อมูลที่ได้เก็บไว้เพื่อใช้สร้าง HTML Profile
StudentID \Name \Surname \Nickname \Birthday \Age \Sex \Religion \Weight \Height \E-mail \Address \Facebook \Phone
5311564149 \Chawatvish \Worrapoj \best \09.11.1991 \22 \male \Buddhism \92 \185 \bestwhatup@gmail.com \418 M.2 Wongpong Pranburi Prachuapkhirikhan \facebook.com/bestwhatup \0811736937
5401012631025 \Klanarong \Raluek \kla \12.11.1992 \21 \male \Buddhism \60 \172 \kla_223@hotmail.com \4 M.4 Praputtabat Changklang Nan \facebook.com/kla223 \0824976605
5211164370 \Suwadee \Piyawartsopon \A \21.06.1990 \23 \female \Buddhism \53 \164 \p.suwadee_a@hotmail.com \47/2 M.12 Huaima Muang Phrae \facebook.com/alis492 \0811804841
5311564164 \Chukieat \Boontae \Poa \20.09.1987 \26 \male \Buddhism \80 \175 \poashadow@hotmaill.com \52/288 Phraramhokmansion Bang O Bang Phlat Bangkok \facebook.com/poashadow \0809004406
5401012630240 \Siriwimon \Sunthon \Jaa \16.07.1992 \21 \female \Buddhism \48 \162 \darkblood_rockaholic@hotmaill.com \434 Village No.3 Wangkrajae Sub-Distric Meong Trat Distric,Trat \facebook.com/siriwimon.sunthon \0849335018
5401012630142 \Parichat \Larwongsa \Tai \28.01.1993 \20 \female \Buddhism \57 \160 \tqy_naka@hotmail.com \346 Bangmod Chomthong Bangkok 10150 \facebook.com/parichat larwongsa \0906782882
5501012630109 \Thanakorn \Nguansiew \Boy \26.06.1993 \20 \male \Buddhism \106 \180 \podmeax@gmail.com \4 M.1 Thaka Amphawa Samutsongkhram 75110 \facebook.com/mheeboy \0836939551
5501012620073 \Wittawin \Kahuttanaseth \Dew \23.10.1993 \20 \male \Catholic \64 \155 \wittawin_k@hotmail.com \189/41 Siriya Homeland Watcharaphon rd. ThaRaeng Bangken Bangkok 10220 \facebook.com/wittawin.kahuttanaseth \0877990445
5501012630133 \Tatchagon \Koonkoei \Kol \02.06.1993 \20 \male \Buddhism \50 \168 \o_k_t@hotmail.com \111/1 M.3 Banmai Thamuang Kanchanaburi \facebook.com/tatchagon \0826810461
5401012620082 \Chonnipa \Yenpensuk \Myu \29 January 1993 \20 \Female \Buddhism \39 \155 \bahimuch@hotmail.com \65/4 M.5(93) Paknumkrajomthong Lane Rachaprek Road Bangphom Subdistrict Talingchan District Bangkok 10170 \facebook.com/za.tabo.za \0809783200
5401012630185 \Pokai \Nitiroj \Joint \19.11.1992 \21 \Male \Buddhism \80 \176 \pokai.nitiroj@gmail.com \111/472 Mantana(onnuch - outer ring) Dokmai Prawet Bangkok 10250 \facebook.com/jibjoint \0836029000
5211163182 \Teejuta \Kaewthong \Mimz \02.11.1990 \23 \Female \Buddhism \55 \174 \takachi_pada@hotmail.com \314/434 DonmuengVilla SongPraPa Road,Donmueng Bangkok 10210 \facebook.com/teejuta.kaewthong \0861075824
 ในส่วนของ Python Code นั้นเป็นดังนี้
#!/usr/bin/env python

def make_index(mData):
    body = ""
    for l in range(len(mData)):
        body = body + """<a href=./htmlPage/""" + str(l) + """.html>""" + mData[l][0] + """</a><br><br>"""
    file = open("./index.html", 'w')
    file.write("""
    <html>
    <head>
        <title>Index of Profile</title>
    </head>
    <body bgcolor="skyblue"><font color="brown">
    <center>
    <font size="10">Index of Student Profile by StudentID</font><br><br>
    """ + body + """
    </center>
    </body>
    </html>""")
    file.close()
    print "Generate Index HTML Complete"

def make_html(Maxpage, mi, mData):
    Linkpage = ""
    if mi==0:
        Linkpage = Linkpage + """<p style="float: left; width: 33.33%; text-align: left;"></p>"""
    else:
        Linkpage = Linkpage + """<p style="float: left; width: 33.33%; text-align: left;"><a href="./"""+str(mi-1)+""".html">Previous</a></p>"""
    Linkpage = Linkpage + """<p style="float: left; width: 33.33%; text-align: center;"><a href=./../index.html>Back To Index Page</a></p>"""
    if mi<Maxpage-1:
        Linkpage = Linkpage + """<p style="float: left; width: 33.33%; text-align: right;"><a href="./"""+str(mi+1)+""".html">Next</a></p>"""
    file = open("./htmlPage/"+str(mi)+".html", 'w')
    file.write("""
    <html>
    <head>
        <title>Profile  of """ + mData[0] + """</title>
    </head>
    <body bgcolor="skyblue"><font color="brown">
        StudentID : """ + mData[0] + """<br><br>
        Name : """ + mData[1] + "   " + mData[2] + """<br><br>
        Nickname : """ + mData[3] + """<br><br>
        Birthday : """ + mData[4] + """<br><br>
        Age : """ + mData[5] + """<br><br>
        Sex : """ + mData[6] + """<br><br>
        Religion : """ + mData[7] + """<br><br>
        Weight : """ + mData[8] + """<br><br>
        Height : """ + mData[9] + """<br><br>
        E-mail : """ + mData[10] + """<br><br>
        Address : """ + mData[11] + """<br><br>
        Facebook : """ + mData[12] + """<br><br>
        Phone Number : """ + mData[13][:10] + """<br></font>
        """ + Linkpage + """
    </body>
    </html>""")
    file.close()
    print "Generate HTML Complete " + str(mi)
  
file = open("./DB.txt", "r")
all_line = file.readlines()
all_line.pop(0)
all_line.sort()
All_Data = []
for i in all_line:
    All_Data.append(i.split(" \\"))
for k in range(len(All_Data)):
    make_html(len(All_Data), k, All_Data[k])
make_index(All_Data)
    เริ่มต้นนั้นโปรแกรมนี้จะทำการเปิดไฟล์ DB.txt ขึ้นมาอ่านแล้วทำการอ่านแต่ละบรรทัดไปเก็บไว้ใน List ที่ชื่อ all_line แล้วทำการ pop บรรทัดแรกออกเพราะบรรทัดแรกในไฟล์นั้น DB.txt นั้นเป็นหัวข้อของข้อมูลที่จะใส่ซึ่งเราไม่ต้องการนำหัวข้อตรงนี้มาใช้ จากนั้น sort ข้อมูลโดยจะเรียงตามลำดับเลขที่นักศึกษา จากนั้นสร้าง List ขึ้นมาใหม่อีกอันชื่อ All_Data แล้วจึงนำข้อมูลใน List ของ all_line แต่ละตัวมาใช้คำสั่ง split ซึ่งเป็น API พื้นฐานของ String ที่มากับ Python หลังจาก split แล้วก็ให้นำข้อมูลไปเก็บใน List All_Data ที่สร้างไว้ทำให้ข้อมูลใน All_Data นั้นเก็บไว้ในรูปแบบของ List ซ้อน List อีกที จากนั้นจึงเรียกใช้ฟังก์ชั่นเพื่อสร้างไฟล์ HTML ซึ่งโปรแกรมนี้จะมีฟังก์ชั่น 2 ฟังก์ชั่น คือ make_html และ make_index

    โดย make_html นั้นมี Argument 3 ตัวคือ Maxpage, mi, mData โดย Maxpage คือจำนวนหน้าของ Profile ทั้งหมดซึ่งมีค่าตามความยาวของ List All_Data , mi เป็นเลขใช้สำหรับระบุลำดับที่จะใช้สร้าง HTML Page และ mData เป็น List ของข้อมูลที่จะนำไปใส่ใน HTML Page ที่ได้จากการ split ก่อนหน้านี้นั่นเอง จากนั้นสร้างตัวแปร Linkpage จากนั้นทำการเช็คเงื่อนไขหาก mi เป็นตัวแรกจะไม่ใส่ Link สำหรับ Previous หรือหากเป็นตัวสุดท้ายก็จะไม่ใส่ Next เช่นกันจากนั้นจึงสร้างไฟล์ HTML โดยใช้คำสั่งของ file มาเขียนโค้ด HTML ลงไปโดยดึงข้อมูลจาก mData ไปใส่ระหว่างการเขียนไฟล์ด้วยจากนั้นปิดท้ายด้วยการนำ Linkpage ไปใส่ไว้ล่างสุดของ HTML Code แล้วทำการปิด file จากนั้น print คำว่า Generate HTML Complete ตามด้วยเลขหน้าออกทางหน้าจอ

    และ make_html มี Argument 1 ตัวคือ mData ซึ่งเป็นตัวแปรที่เก็บข้อมูลทั้งหมดไว้ จากนั้นเริ่มต้นด้วยการสร้างตัวแปรชื่อ Body แล้ววน loop ตามความยาวของ mData เพื่อเก็บ Code ที่ใช้สร้างลิ้งค์ไปยังไฟล์ HTML ของแต่ละเลขประจำตัวจากนั้นจึงเขียนลงไฟล์ที่ชื่อ index.html แล้วทำการปิดไฟล์ print คำว่า Generate Index HTML Complete ออกทางหน้าจอ

    จากโปรแกรมนี้จะเห็นได้ว่าเราสามารถนำข้อมูลจากภายนอกมาใช้เป็นข้อมูลในโปรแกรมของเราและนำไปสร้างเป็นไฟล์ HTML ที่ใช้ในการแสดงผลอีกด้วยโดยการใช้ file นั้นจะเห็นว่า file = open("./DB.txt", "r") ในคำสั่ง open นั้นจะประกอบไปด้วยชื่อไฟล์ และ Mode ซึ่งจากที่ยกตัวอย่างนัั้นจะมีทั้ง "r" และ "w" โดย "r" นั้นจะเป็นโหมดในการอ่านเพียงอย่างเดียวเท่านั้น ส่วน "w" จะเป็นการเขียนไฟล์เท่านั้นหากมีไฟล์ชื่อนี้อยู่แล้วจะลบของเก่าทิ้งแล้วเขียนลงไปใหม่ นอกจากนี้ยังมีอีกโหมดนั่นก็คือ "a" ซึ่งโหมดนี้จะเป็นการเขียนไฟล์เพิ่มต่อจากของเดิม และสุดท้ายโหมด "r+" ซึ่งโหมดนี้สามารถทำได้ทั้งอ่านและเขียนไฟล์ได้เลย

โดยได้ศึกษาการใช้ open จากเว็บ python.org
โดยได้ศึกษาการเขียนโค้ด HTML จากเว็บ w3schools.com
Read more ...

วันอาทิตย์ที่ 15 ธันวาคม พ.ศ. 2556

งานครบรอบ 50 ปีวิศวะ มจพ.

บูธในงานที่สนใจก็คือบูทของ FRECON

ซึ่งบูธซึ่งเป็นบูธที่เกี่ยวข้องกับมอเตอร์ไฟฟ้าทั้งในรูปแบบของ Inverter หรือ Servo Motor




ภาพ Oscilloscope ที่จับสัญญาณจาก Inverter


ภาพภายในของ Inverter


ภาพมอเตอร์ที่ต่อกับ Inverter ซึ่งเป็นแบบไร้แปรงถ่าน


ภาพตัวอย่างมอเตอร์แบบปกติ
 

ภาพ Servo Motor พร้อมตัวควบคุม


ภาพตัวควบคุม Servo Motor


ภาพ Servo Inverter


ภาพ Servo Motor


    เหตุผลที่บูธนี้น่าสนใจก็เพราะว่าชุมควบคุม Servo Motor และ ระบบ Inverter นั้นเริ่มมีให้เห็นในชีวิตประจำวันของเราบ้างโดยส่วนใหญ่จะเป็น Inverter เช่นใน แอร์ เป็นต้น และสิ่งของเหล่านี้ก็มีความเกี่ยวข้องทางด้านคอมพิวเตอร์อยู่บ้าง ในส่วนของชุดควบคุม Servo Motor นั้นมีหน้าจอที่ใช้ในการควบคุมชุด Servo Inverter และ Servo Motor ซึ่งต้องใช้โปรแกรมในการเขียนควบคุมนั่นเองโดยจากตัวอย่างที่ได้เห็นนั้นการหมุนของ Servo Motor ทั้งสองตัวมีความแม่นยำและความเร็วสูงมาก
Read more ...

วันพุธที่ 11 ธันวาคม พ.ศ. 2556

สรุป Django w6-2

ความรู้พื้นฐานในการใช้งาน Django: The Web framework ประกอบด้วยส่วนหลักๆ 6 ส่วนดังนี้

1.Models (Apps) คือ การสร้าง Web Application แบบง่ายๆซึ่งมีความสามารถในการเก็บข้อมูล (Database) ได้ใน 1 Project สามารถมีมากกว่า 1 Models (Apps) ได้
ศึกษาการใช้งาน Models (Apps) คลิกที่นี่

2.Admin คือ หน้าของผู้ดูแลระบบ สามารถแก้ไข, เพิ่ม, ดู, ลบ ข้อมูลต่างๆที่อยู่ใน Database ได้ซึ่งหน้าแอดมินมีการจัดรูปแบบการแสดงผลได้หลายรูปแบบ
ศึกษาการใช้งาน Admin คลิกที่นี่

3.Views คือ Python Code มีไว้เพื่อจัดการรูปแบบการแสดงผลของหน้าเว็บเพจ ซึ่งจะประกอบด้วยฟังก์ชั่นให้ Urls เรียกใช้เวลามีการเรียกเว็บเพจขึ้นมาแสดงผล
ศึกษาการใช้งาน Views จาก Django Tutorial คลิกที่นี่ หรือจาก Djangobook คลิกที่นี่

4.Urls คือ ส่วนที่ใช้จัดการตรวจสอบเช็ค Address ว่าตรงกับ Address ที่ระบุไว้หรือไม่หากตรงก็จะไปเรียกฟังก์ชั่นใน Views ขึ้นมาแสดงผลทาง Browser หากไม่ตรงก็จะ Error Page not found
ศึกษาการใช้งาน Urls จาก Django Tutorial คลิกที่นี่ หรือจาก Djangobook คลิกที่นี่

5.Templates คือ โครงร่างรูปแบบของ HTML Code ที่ใช้ในการแสดงผลซึ่งมีประโยชน์ในด้านความยืดหยุ่นของข้อมูลที่จะแสดงผลสูงเนื่องจากใช้ตัวแปรเป็นตัวกำหนดค่า
ศึกษาการใช้งาน Templates จาก Django Tutorial คลิกที่นี่ หรือจาก Djangobook คลิกที่นี่

6.Form คือ การสร้าง User Input ผ่านทาง Web browser ใน HTML Code ซึ่ง Input ที่รับค่ามานั้นเราสามารถนำไปใช้ได้ตามต้องการขึ้นกับฟังก์ชั่นที่เรากำหนด
ศึกษาการใช้งาน Form คลิกที่นี่
Read more ...

วันอังคารที่ 10 ธันวาคม พ.ศ. 2556

Djangobook - Templates

ในบทความนี้นั้นเราจะมาทดลองการใช้งาน Template ใน Django กันครับโดยเริ่มต้นให้สร้าง Folder ที่ชื่อ Templates ขึ้นใน Project ของเราก่อนจากนั้นให้ไปแก้ไขในไฟล์ setting.py โดยเพิ่มโค้ดเข้าไปดังนี้

TEMPLATE_DIRS = (
"/home/wittawin/Kim/Stamp/Templates",
# From Django book
# Always use forward slashes, even on Windows.
# Don’t forget to use absolute paths, not relative paths.
)

    โดยใน String ที่ใส่เพิ่มเข้าไปนั้นให้แก้ไขตาม Directory ที่แต่ละคนสร้างไว้เพื่อเก็บ Templates ซึ่งเหตุผลที่ต้องเพิ่มโค้ดชุดนี้เข้าก็เพื่อเป็นการกำหนดให้ Django รู้ว่าเราจะเก็บ Templates ไว้ที่ไหนเพื่อให้ Django รู้ที่อยู่แล้วเข้าไปอ่านไฟล์ Templates ในนั้นได้

จากนั้นให้เข้าไปเพิ่มโค้ดเข้าไปในไฟล์ urls.py ดังนี้

    url(r'^calendar/$', 'Stamp.views.Years_Calendar'),
    url(r'^calendar(\d+)/$', 'Stamp.views.Years_Calendar'),

จากนั้นไปแก้ไขไฟล์ views.py โดยเพิ่มโค้ดเหล่านี้เข้าไป

from django.shortcuts import render_to_response
import calendar

def Years_Calendar(request,years=2013):
    mycal = calendar.HTMLCalendar(calendar.SUNDAY)
    monthsq1 = ["January","Febuary","March"]
    monthsq2 = ["April","May","June"]
    monthsq3 = ["July","August","September"]
    monthsq4 = ["October","November","December"]
    return render_to_response('Calendar_Template.html', {'listofdate': mycal.yeardayscalendar(int(years)), 'year_show' : years, 'monthq1' : monthsq1, 'monthq2' : monthsq2, 'monthq3' : monthsq3, 'monthq4' : monthsq4, 'value' : 0})

และในโฟลเดอร์ Templates ที่สร้างไว้ตอนต้นให้สร้างไฟล์ที่ชื่อ Calendar_Template.html จากนั้นภายใน Calendar_Template.html ให้ใส่โค้ดดังต่อไปนี้

<html>
    <head>
        <title>Calendar {{ year_show }}</title>
    </head>
    <body bgcolor="skyblue">
        <center><br><font color="white" size = "10">
        Calendar {{ year_show }}</font><br><br>
        <table border="0" cellpadding="2">
    {% for quarters in listofdate %}
        <tr valign="top">
        {% ifequal forloop.counter 1 %}
            {% for month in monthq1 %}
            <td><center><font color="white" size = "6">{{ month }}</font></center></td>
            {% endfor %}
            </tr><tr valign="top">
        {% endifequal %}
        {% ifequal forloop.counter 2 %}
            {% for month in monthq2 %}
            <td><center><font color="white" size = "6">{{ month }}</font></center></td>
            {% endfor %}
            </tr><tr valign="top">
        {% endifequal %}
        {% ifequal forloop.counter 3 %}
            {% for month in monthq3 %}
            <td><center><font color="white" size = "6">{{ month }}</font></center></td>
            {% endfor %}
            </tr><tr valign="top">
        {% endifequal %}
        {% ifequal forloop.counter 4 %}
            {% for month in monthq4 %}
            <td><center><font color="white" size = "6">{{ month }}</font></center></td>
            {% endfor %}
            </tr><tr valign="top">
        {% endifequal %}
        {% for months in quarters %}
            <td><table border="5" cellpadding="10"><tr><td align="center"><font color="white" size = "3">Sun</font></td><td align="center"><font color="white" size = "3">Mon</font></td><td align="center"><font color="white" size = "3">Tue</font></td><td align="center"><font color="white" size = "3">Wed</font></td><td align="center"><font color="white" size = "3">Thu</font></td><td align="center"><font color="white" size = "3">Fri</font></td><td align="center"><font color="white" size = "3">Sat</font></td></tr>
            {% for weeks in months %}
                <tr>
                {% for days in weeks %}
                    {% ifnotequal days 0 %}
                        <td align="right"><font color="white" size = "4">{{ days }}</font></td>
                    {% else %}
                        <td> </td>
                    {% endifnotequal %}
                {% endfor %}
                </tr>
            {% endfor %}
            </table></td>
           
        {% endfor %}
        </tr>
    {% endfor %}
    </table>
        </center>
    </body>
</html>

    หลักการใช้ Template นั้นประกอบไปด้วยสองส่วนนั่นคือ template และ context โดย template นั้นก็หมายถึงไฟล์ HTML ที่ได้เขียนไว้สำหรับการใช้เป็น template นั่นเองส่วน context คือส่วนที่ระบุว่าตัวแปรใน template ที่รอค่าเข้าไปใส่ในตอนใช้งาน template นั้นมีค่าตรงกับตัวแปรใดหรือค่าเท่าใด โดยทั้งสองส่วนนั้นมีความสำคัญสำหรับการใช้ template อย่างมากหากขาดอย่างใดอย่างนึงก็ไม่สามารถใช้ template ได้เมื่อมีครบทั้งสองส่วนแล้วเราก็ต้องทำการ render

    ซึ่งต้องเริ่มด้วยการ import render_to_response เป็นหนึ่งใน API ที่มาจาก django.shortcuts ซึ่งทำหน้าที่ในการนำ context ที่มีไป render ในไฟล์ HTML ที่เป็น template อยู่จากนั้นจึงส่งกลับไปแสดงผลที่ Browser ทันทีเหมือนกับการใช้คำสั่ง HttpResponse เพียงแต่เพิ่มการ render context เข้าไปใน template ก่อนจะ return
return render_to_response('Calendar_Template.html', {'listofdate': mycal.yeardayscalendar(int(years)), 'year_show' : years, 'monthq1' : monthsq1, 'monthq2' : monthsq2, 'monthq3' : monthsq3, 'monthq4' : monthsq4, 'value' : 0})
 จากตัวอย่างจะเห็นว่าส่วนแรกคือชื่อของ template ที่เราจะเป็นโครงในการนำ context ไป render ส่วนต่อมาคือ context จะเห็นว่าตัวทางซ้ายของเครื่องหมาย : คือชื่อของตัวแปรที่อยู่ใน template ส่วนตัวทางขวาของเครื่องหมาย : คือค่าหรือตัวแปรที่จะนำไปใช้นั่นเอง

    ส่วน Calendar นั้นเป็น API ของ python ที่มีมาให้อยู่แล้วซึ่งเราจะใช้ในการสร้าง List ที่เก็บวันที่ของทั้งปีไว้ภายในโดยใช้คำสั่ง mycal.yeardayscalendar(int(years)) เป็น List ที่ประกอบด้วย 4 Quarter ในแต่ละปีและใน List ของแต่ละ Quarter ก็จะประกอบได้เดือน 3 เดือนจากนั้นในแต่ละเดือนก็จะเก็บค่าของสัปดาห์ในเดือนนั้นๆ และในแต่ละสัปดาห์ก็จะเก็บวันที่ของในสัปดาห์นั้นๆโดยเริ่มจากวันที่เรากำหนดให้เป็นวันแรกของสัปดาห์ไว้ตอนสร้าง object
mycal = calendar.HTMLCalendar(calendar.SUNDAY) อย่างในตัวอย่างกำหนดให้เป็นวันอาทิตย์ไว้ จะสังเกตเห็นว่าใน Function def Years_Calendar(request,years=2013): years=2013 นั้นมีไว้ใส่ค่าเป็นค่า พื้นฐานให้หากไม่มีการส่งค่าจาก Urls แต่หากส่งมาก็จะนำค่านั้นมาใช้แทน

ภาพตัวอย่างเมื่อเรียกเพจ 127.0.0.1/calendar


ภาพตัวอย่างเมื่อเรียกเพจ 127.0.0.1/calendar2020


    จากการใช้ Template ในข้างต้นนั้นประการแรกเลยจะเห็นได้ว่าปัญหาอย่างนึงที่ลดลงไปเลยก็คือความสับสนในด้าน Code HTML ที่ผสมกับ python ซึ่งเราจะเจอปัญหานี้ถ้าเราไม่ใช้  Template แบบในตัวอย่างของ Djangobook -  Dynamic Urls and views ซึ่งในตัวอย่าง Code HTML ยังมีจำนวนไม่มาก หากมีจำนวนมากกว่านี้ต้องเกิดความสับสนขึ้นอย่างแน่นอน

    ประการที่สองเราสามารถนำ Template มาใช้ซ้ำได้อีกเพราะ Template เป็นเพียงแค่แบบในการกำหนดโครงสร้างของโค้ดต่างๆโดยสิ่งที่จะนำมาแสดงขึ้นกับ context ที่นำไป render ล้วนๆดังนั้น หากเปลี่ยนค่าของ context ที่จะนำไป render ก็จะได้หน้าต่างที่แสดงผลต่างจากแบบเดิมแล้ว
Read more ...

Djangobook - Dynamic Urls and Views

มาเริ่มต้นกันโดยเปิดไฟล์ urls.py ในโปรเจคของเราจากนั้นแก้ไขโค้ดภายในดังนี้

from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url(r'^time/$', 'Stamp.views.display_time'),
    url(r'^time/plus_m/(\d+)/$', 'Stamp.views.minutes_ahead'),
)

จากนั้นเข้าไปเพิ่มโค้ด ในไฟล์ views.py ดังนี้

from django.http import HttpResponse,Http404
import time,datetime

def display_time(request):
    now = time.localtime()
    return HttpResponse("""
<html>
    <head>
        <title>Test</title>
    </head>
    <body bgcolor="skyblue"><font color="brown" size="10">
    <center>Year : """ + str(now[0]) + """<br><br>
    Month : """ + str(now[1]) + """<br><br>
    Day : """ + str(now[2]) + """<br><br>
    Time : """ + str(now[3]) + ":" + str(now[4]) + ":" + str(now[5]) + """
    </center>
    </body>
    </html>""")

def minutes_ahead(request, offset):
    try:
        offset = int(offset)
    except ValueError:
        raise Http404()
    dt = datetime.datetime.now() + datetime.timedelta(minutes=offset)
    html = """<html><body bgcolor="skyblue"><center><font color="brown" size="10">In %s minute(s), it will be %s.</font><center></body></html>""" % (offset, dt)
    return HttpResponse(html)

จะสังเกตได้ว่าในโค้ดนีี้มีรูปแบบของ Urls อยู่สองแบบคือ

url(r'^time/$', 'Stamp.views.display_time'),
url(r'^time/plus_m/(\d+)/$', 'Stamp.views.minutes_ahead'),

    ซึ่งจะเห็นว่าแบบแรกนั้นหากเราพิม 127.0.0.1/time ก็จะแสดงรูปแบบของเพจออกมาได้เพียงแบบเดียวซึ่งเพจแบบนี้เรียกว่า Static เพจซึ่งการทำ Web Application ส่วนใหญ่จะใช้เพจแบบ Dynamic ซึ่งจะเป็นแบบที่สอง 127.0.0.1/time/plus_m/1 ก็จะเป็นการโชว์เวลาที่เพิ่มไปอีก 1 นาทีตามที่ได้เขียนไว้ใน Function minutes_ahead ใน Views โดยหากเพิ่มเป็น 127.0.0.1/time/plus_m/2 ก็จะเพิ่มเวลาไปอีก 2 นาทีเช่นที่เขียนใน Function


 
    โดย url(r'^time/plus_m/(\d+)/$', 'Stamp.views.minutes_ahead'), นั้นจะเห็นว่ามี (\d+) ซึ่งในส่วนนี้จะเป็นส่วนที่ทำให้โค้ดของเรา Dynamic เพราะในส่วนนี้นั้นจะเป็นการรับค่าจาก Url ที่พิมเข้าไปให้ Function minutes_ahead โดยค่าที่ส่งไปจะเป็นค่าของตัวแปร offset และนำไปใช้ใน Function ในส่วนของ Function นั้น จะมีโค้ด
    try:
        offset = int(offset)
    except ValueError:
        raise Http404()
ซึ่งทำหน้าที่ในการเช็คว่าค่าที่รับมาจาก Url นั้นเป็นตัวแปรประเภท int หรือไม่หาก ไม่ใช่ int ก็จะเกิด exception แล้วเพจจะเด้งไปที่หน้า Page not found 404 แทนเพราะหากไม่ใช่ตัวแปรที่เป็น int เมื่อนำไปคำนวณในบรรทัด
dt = datetime.datetime.now() + datetime.timedelta(minutes=offset)
ไม่ได้ซึ่ง exception นั้นมีไว้เพื่อป้องกันเหตุการณ์นี้โดยเฉพาะ


    โดย API ที่ใช้ใน Views มี 3 API คือ time , datetime และ HttpResponse , Http404 ซึ่ง time ใช้ใน Function display_time โดยเป็นการดึงเวลาในปัจจุบัน ณ ขณะเรียกเพจขึ้นมาแสดงผล

    datetime ใช้ใน Function minutes_ahead โดยเรียกเวลา ปัจจุบันขึ้นมาแล้วเพิ่มด้วยเวลาที่เพิ่มจากเวลาในปัจจุบันไปอีกตามค่าของ offset เป็นนาที

    HttpResponse ใช้ในการส่ง String กลับไปแสดงผลใน HTML ซึ่งจะเป็นรูปแบบตามในแต่ละ Function และ Http404 จะเรียก Page not found 404 มาแสดงผลแทนการส่ง String กลับไปแสดงผลใน HTML

    ดังนั้นในไฟล์ views นั้นเราสามารถใช้ในการกำหนดรูปแบบที่จะเอาไว้ใช้ในการแสดงผลโดยการเขียน Function ไว้ในนั้นและใช้ urls ในการเรียกใช้ Function ใน views มาแสดงผลออกทาง HTML
Read more ...

วันอาทิตย์ที่ 8 ธันวาคม พ.ศ. 2556

Django Tutorial Part 4 - Form & Generic Views

    เข้าสู่ Part 4 ของ Tutorial กันแล้วโดยในส่วนนี้จะนำ Form ของภาษา HTML เข้ามาใช้ใน Templates ที่เราได้สร้างไว้ใน Part 3 ก่อนหน้านี้พร้อมทั้งสามารถโหวต Choice ต่างๆของเราผ่านทาง Browser และบันทึกค่าลงใน Database ของเราได้อีกด้วยแถมท้ายด้วยการใช้ Generic View เพื่อให้โค้ดที่เขียนนั้นสั้นลงจากเดิม

---Form---

1.เริ่มต้นด้วยการแก้ไข template detail.html ที่สร้างไว้ใน Part 3 กันเสียก่อนโดยแก้ตามนี้

<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>

    จาก Template ที่แก้ไขนั้นจะแสดงผลเป็น HTML โดยหากมี error_message ก็จะแสดงออกมาทาง Browser ด้วยและเป็นตัวหนาจากนั้นในส่วนของ form tag action มีหน้าที่เมื่อกดปุ่ม Vote จากโค้ด <input type="submit" value="Vote" /> แล้วจะเรียกหน้า vote ขึ้นมา ในส่วนของ method="post" ใส่เพื่อเป็นการบอกว่าข้อมูลจาก form นี้นำเข้าไปให้ทางฝั่ง server และ {% csrf_token %} มีไว้เพื่อป้องกัน Cross Site Request Forgeries ซึ่ง Cross Site Request Forgeries คือ รูปแบบของอันตรายของเว็บโดยส่งคำสั่งที่ไม่ได้รับอนุญาตจากผู้ใช้ที่เว็บไซต์

    จากนั้นเข้า loop for poll.choice_set.all ซึ่งก็คือ List ที่มี Choice ทั้งหมดของ poll นั้นๆผ่านตัวแปร choice จากนั้นสร้างปุ่มกดแบบ Radio และมี label เพื่อบอกว่าปุ่ม Radio นั้นเป็นปุ่มของ choice ไหน



2.จากนั้นเข้าไปแก้ไข Function vote ในไฟล์ views.py ใน polls/views.py ดังนี้

          def results(request, poll_id):
              poll = get_object_or_404(Poll, pk=poll_id)
              return render(request, 'polls/results.html', {'poll': 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,)))


    ซึ่ง Function vote เมื่อเรียกใช้แล้วจะดึง Objects ของ poll ที่ pk ตรงกับ poll_id ออกมาเก็บใน p หากไม่มี Objects นั้นก็จะแสดงหน้า Page not found 404 แบบที่ได้อธิบายไว้ใน Part 3 แล้วจากนั้น p.choice_set.get(pk=request.POST['choice']) จะได้ choice ที่เราทำการเลือกในหน้า detail โดย request.POST['choice'] จะได้ค่าของ String ซึ่งเป็น ID ของ choice ออกมาโดยเมื่อได้ choice ที่เลือกออกมาแล้วก็ให้ selected_choice ชี้ไว้ แต่หากไม่สามารถหา choice นั้นได้ก็จะกลับไปแสดงหน้า detail อีกครั้งผ่าน render โดยมี error_message กลับไปแสดงด้วย แต่ถ้าหากหาได้แล้วก็ให้บวกค่า votes ของ choice นั้น 1 แต้มแล้วทำการ save ลง Database จากนั้นก็จะ Redirect ไปยังหน้า results ของ poll นั้นเองโดยอัตโนมัติ

    ส่วน Function results นั้นจะดึง Objects ของ poll ที่ pk ตรงกับ poll_id ออกมาเก็บใน p หากไม่มี Objects นั้นก็จะแสดงหน้า Page not found 404 แบบที่ได้อธิบายไว้ใน Part 3 แล้วจากนั้นจะ render template results.html ขึ้นมาแสดงผล



3.เพิ่ม template results.html โดยภายใน 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>


    โดยรูปแบบที่แสดงจะเริ่มด้วยคำถามของ poll นั้นๆเป็น Header จากนั้นจึงเข้าไปอ่านค่าใน choice ทั้งหมดของ poll นี้โดยนำทั้ง choice และจำนวนของการ vote ออกมาแสดงผลทั้งหมด จากนั้นมีลิ้งค์ขึ้นมาถามว่า Vote again? หาคลิกที่ลิ้งค์ก็จะกลับไปหน้า detail ของ poll นี้เพื่อเลือกโหวตอีกครั้ง



---Generic Views---


4.การที่โค้ดของเรานั้นอยู่ในรูปแบบ generic และ สั้นๆ ถือเป็น โค้ดที่ดีกว่าดังนั้นเราจะแก้ไขไฟล์ดังต่อไปนี้

    4.1 แก้ไขไฟล์ polls/urls.py ในส่วนของ urlpatterns ดังนี้

          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'),


    4.2 แก้ไขและเพิ่มบรรทัด import ในไฟล์ polls/views.py ดังนี้

          from django.views import generic

          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'


    จากโค้ดที่ได้เปลี่ยนแปลงไปข้างต้นนั้นในส่วนของ views.py เราได้ import API ที่ชื่อ generic จาก django.views มาซึ่งเป็น API สำหรับการทำ generic views มาให้โดย template_name ในแต่ละ Class นั้นเอาไว้กำหนดไฟล์ templates ที่จะเอามาใช้ในการ render ส่วน context_object_name เอาไว้กำหนดชื่อของตัวแปรที่ใช้ใน context นี้สำหรับ model เอาไว้แสดงข้อมูลใน Objects ที่ระบุไว้

    ในส่วนของ urls.py จะเห็นว่ามี .as_view() ต่อท้ายชื่อ Class ที่เราสร้างไว้ใน views.py ซึ่ง .as_view() มีหน้าที่ในการจัดการกับ request ที่เข้ามาแล้วตอบกลับไปซึ่งสิ่งที่ตอบกลับไปก็คือหน้า HTML ที่ render แล้วอีกส่วนที่เปลี่ยนไปก็คือ (?P<poll_id>\d+) ของ detail และ results เปลี่ยนไปเป็น (?P<pk>\d+) เพราะ DetailView นั้นสามารถจับ Primary Key จาก url ได้หรือที่เรียกกันว่า pk นั่นเองจึงเป็นเหตุผลให้เปลี่ยนไปเป็นแบบหลัง

    จาก Tutorial Part 4 นี้ทำให้เรารู้จักการใช้ Form ใน HTML ผสมกับการใช้ Template ใน Django ไปด้วยซึ่งสามารถใช้ Form เป็น Input ในการเก็บข้อมูลเข้าไปยัง Database ของเราหรือจะเอามาเพิ่มแต้ม Vote แบบในตัวอย่างก็ได้ นอกจากนี้ยังมีส่วนของ Generic View ใช้เพื่อลดความยาวของโค้ดให้อ่านง่ายสบายตาขึ้นจากแบบเก่า

ข้อมูลเพิ่มเติมเรื่อง Cross Site Request Forgeries จากเว็บ wikipedia.org
ข้อมูลเพิ่มเติมเรื่อง Generic View แบบ Detail View จากเว็บ djangoproject.com
ข้อมูลเพิ่มเติมเรื่อง Generic View แบบ List View จากเว็บ djangoproject.com
Read more ...

Django Tutorial Part 3 - Views, Urls and Templates

    ในส่วนของ Part 3 นี้เราจะศึกษาในส่วนของ การใช้งาน views.py, urls.py และ Templates ใน App polls ที่ได้สร้างใน Part 2

---Views, Urls---

1.เข้าไปในแก้ไขไฟล์ polls/views.py ดังนี้

from django.http import HttpResponse
def index(request):
    return HttpResponse("Hello, world. You're at the poll index.")

2.สร้างไฟล์ที่ชื่อว่า urls.py ไว้ในโฟลเดอร์ polls จะได้เป็น polls/urls.py และเขียนข้อความในไฟล์ดังนี้

from django.conf.urls import patterns, url
from polls import views
urlpatterns = patterns('',
    url(r'^$', views.index, name='index')
)

3.เข้าไปแก้ไฟล์ในส่วนของ Tutorial/urls.py โดยการเพิ่ม

url(r'^polls/', include('polls.urls')),

เข้าไปในส่วนของ urlpatterns

    เมื่อมีการเรียก url เป็น http://127.0.0.1:8000/polls/ ซึ่งการทำงานเริ่มต้นจะเช็ค urls ที่ไฟล์ Tutorial/urls.py ก่อนเนื่องจาก ใน Tutorial/setting.py ได้มีการตั้งค่าไว้ว่า ROOT_URLCONF = 'Tutorial.urls' นั่นเอง

    ซึ่งจากข้อ 3 ที่ได้เพิ่มโค้ดเข้าไปนั้นเราได้เขียนไว้หาก urls ลิ้งค์ไปที่ polls ให้ไปเรียก polls.urls หรือก็คือ ไฟล์ polls/urls.py ในข้อ 2 นั่นเองซึ่งจะเรียกต่อไปยังไฟล์ polls/views.py ซึ่งฟังก์ชั่น index ใน polls/views.py นี้จะทำการ return ค่ากลับไปแสดงผลทาง Browser ว่า "Hello, world. You're at the poll index."


4.เพิ่มโค้ดข้างล่างนี้เข้าไปใน polls/views.py

def detail(request, poll_id):
    return HttpResponse("You're looking at poll %s." % poll_id)
def results(request, poll_id):
    return HttpResponse("You're looking at the results of poll %s." % poll_id)
def vote(request, poll_id):
    return HttpResponse("You're voting on poll %s." % poll_id)

5.และในส่วนของ polls/urls.py ก็ให้เพิ่มโค้ดข้างล่างนี้เข้าไปใน urlpatterns

url(r'^(?P<poll_id>\d+)/$', views.detail, name='detail'),
url(r'^(?P<poll_id>\d+)/results/$', views.results, name='results'),
url(r'^(?P<poll_id>\d+)/vote/$', views.vote, name='vote'),

    จากข้อ 4 และ 5 เมื่อเราทำการเพิ่มโค้ดไปแล้วนั้น urls ของเราจะมีรูปแบบในการเข้าใช้งานเพิ่มขึ้นอีก 3 แบบคือ

    1.เพิ่มเลขเข้าไปหลัง polls เช่น http://127.0.0.1:8000/polls/34 จะได้ output ดังนี้


    2.เพิ่มเลขเข้าไปหลัง polls แล้วตามด้วย results เช่น http://127.0.0.1:8000/polls/34/results จะได้ output ดังนี้


    3.เพิ่มเลขเข้าไปหลัง polls แล้วตามด้วย vote เช่น http://127.0.0.1:8000/polls/34/vote จะได้ output ดังนี้


    โดยส่วนที่ทำให้รับค่าตัวเลขได้คือ (?P<poll_id>\d+) โดยที่ ?P<poll_id> เป็นส่วนที่เอาไว้ระบุว่าค่าที่รับนั้นไปเป็นตัวแปรไหนซึ่งในที่นี้คือ poll_id ส่วน \d+ คือ regular expressions ซึ่ง d+ หมายถึงตัวเลขกี่หลักก็ได้

    Regular Expressions คือ ลำดับของตัวอักษรซึ่งเป็นรูปแบบหรือ pattern ส่วนใหญ่ใช้เช็คว่ามีรูปแบบตรงกับที่เรากำหนดหรือไม่

---Templates---

6.ในโฟลเดอร์ polls ให้เราสร้างโฟลเดอร์ใหม่ที่ชื่อ templates และในโฟลเดอร์ templates ที่สร้างใหม่ให้สร้างโฟลเดอร์ที่ชื่อ polls อีกครั้งจากนั้นให้สร้างไฟล์ index.html ไว้ภายในโดยภายในไฟล์ index.html มีโค้ดดังนี้

{% if latest_poll_list %}
    <ul>
    {% for poll in latest_poll_list %}
        <li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>No polls are available.</p>
{% endif %}

รูปแบบของโฟลเดอร์จะสรุปได้ดังนี้ polls > templates > polls > index.html

7.จากนั้นแก้ไข Functions index และเพิ่มการ import ของไฟล์ views.py ใน polls ดังนี้

from polls.models import Poll
def index(request):
    latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
    context = {'latest_poll_list': latest_poll_list}
    return render(request, 'polls/index.html', context)

    ซึ่งรูปแบบของ template index.html นี้หากใน latest_poll_list นั้นไม่มี Poll เลยก็จะแสดงผลว่า No polls are available. ที่ Browser ของเราแต่หากมีก็จะสร้างลิ้งค์ให้ผู้ใช้สามารถกดเข้าไปดูต่อได้ซึ่งจะเป็นการลิ้งค์แบบ polls/เลข id โดยจะเรียก Functions detail ออกมาแสดงผล

    ในส่วนของ views.py ที่แก้ไขนั้นได้ทำการ import Poll เข้ามาเพื่อใช้ในการเข้าถึงข้อมูลใน database ที่เก็บไว้ใน Functions index โดยตัวแปร latest_poll_list จะเป็นการสร้าง List ที่เก็บ Objects ของ Poll ไว้ 5 ตัวโดยเรียงลำดับตาม pub_date ที่มีการเพิ่มเข้ามาล่าสุดหากมีเกิน 5 ตัวก็จะนำมาแสดงเพียง 5 ตัวเท่านั้นจากนั้นในตัวแปร context มีไว้เพื่อกำหนดตัวแปร latest_poll_list ให้ตรงกับ 'latest_poll_list' ที่อยู่ใน templates index.html

    จากนั้นจึง เรียกใช้คำสั่ง render(request, 'polls/index.html', context) โดย render นั้นคือการเรียกไฟล์ templates index.html มาแล้วส่งตัวแปรทั้งหมดใน context ไปแปลงเป็นโค้ด HTML จากนั้นส่งโค้ดทั้งหมด return กลับไปแสดงผล


8.เข้าไปแก้ไข polls/views.py อีกครั้งโดยแก้ไขตามนี้

from django.shortcuts import render, get_object_or_404
def detail(request, poll_id):
    poll = get_object_or_404(Poll, pk=poll_id)
    return render(request, 'polls/detail.html', {'poll': poll})

9.จากนั้นสร้าง template ขึ้นมาอีกอันชื่อ detail.html เก็บไว้ใน polls > templates > polls > detail.html (ที่เดียวกับที่เก็บ templates index.html) โดยภายในมีรายละเอียดดังนี้

<h1>{{ poll.question }}</h1>
<ul>
{% for choice in poll.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>

    จากการแก้ไขในข้อ 9 และ 10 จะเมื่อลองเข้าไปที่ http://127.0.0.1:8000/polls/1 จะแสดงผลออกมาเป็น Choice ทั้งหมดของ polls What's up? ซึ่งคือ Poll ตัวแรกหรือ pk = 1 โดยในส่วนของ views.py จะเห็นว่ามีการ import get_object_or_404 เข้ามาซึ่ง get_object_or_404 มีไว้เพื่อให้ Functions นี้ดึง Objects จาก Poll โดยที่ pk = poll_id ที่รับค่ามาโดยหาก poll_id ที่ได้รับนั้นไม่มีอยู่ใน Poll แล้วจะเด้งไปยังหน้า Page not found 404 แทนโดยที่ทำแบบนี้เพื่อเป็นเงื่อนไขในการดักหากมีการส่งค่า poll_id ที่ไม่มีใน Poll ก็จะเป็นการบอกผู้ใช้ได้ในทันทีว่าไม่มี Objects นั้นอยู่แต่หากมีค่าก็จะได้ค่าเป็น Objects Poll กลับมาใช้ในการ render ได้เลยหากเทียบแล้วจริงๆจะพบว่า get_object_or_404 นั้นให้ผลเหมือนกัน โค้ดด้านล่างนี้

try:
    poll = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
    raise Http404

จะเห็นได้ว่าหาก มีการ get Objects แล้ว Objects นั้นไม่มีอยู่ก็จะเด้งไปหน้า Page not found 404 เช่นเดียวกับการใช้คำสั่ง get_object_or_404 เลย ซึ่งทั้ง render และ get_object_or_404 นั้นทั้งคู่เป็น API ที่ทางผู้สร้าง django สร้างไว้ให้เราเรียกใช้ได้ทันที

    ในส่วนของ templates detail.html นั้นจะเป็นการแสดงผลโดยจะใช้ชื่อคำถามของ Poll เป็น Header จากนั้นจึงเข้าไปอ่านข้อมูล Choice ทั้งหมดใน Poll นั้นๆและนำมาแสดงเป็นข้อๆผ่านทาง Browser ซึ่งใช้ render ในการนำข้อมูลใส่ลงใน templates เช่นกัน


10.แก้ไขไฟล์ Tutorial/urls.py จาก

url(r'^polls/', include('polls.urls')),

ให้เป็นแบบนี้

url(r'^polls/', include('polls.urls', namespace="polls")),

11.เข้าไปแก้ไข templates index.html ของ polls โดยแก้บรรทัด

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

ให้เป็นแบบนี้

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

    ผลที่ได้จากการแก้นั้นคือการลดการใช้ Code แบบตายตัวใน templates หากในอนาคตเราเปลี่ยนรูปแบบลิ้งค์ของ detail เราก็ไม่จำเป็นที่จะต้องเข้ามาแก้ไขใน templates เองเพราะ templates เราจะเรียกรูปแบบของลิ้งค์จาก urls.py เองหรือเรียกว่าลิ้งค์แบบ Dynamic โดย polls นั้นมาจากชื่อของ namespace ใน Tutorial/urls.py และ detail นั้นมากจากชื่อของ name ใน polls/urls.py

    ในส่วนของ urls.py ที่เพิ่ม namespace เข้าไปก็เพื่อลดความสับสนที่อาจเกิดขึ้นในอนาคตได้หากมี App หลายๆตัวสังเกตุได้จาก {% url 'polls:detail' poll.id %} หากเราไม่ใส่ namespace ใน url แบบแรกเราก็สามารถใช้ {% url 'detail' poll.id %} แบบนี้แทนได้ซึ่งก็ Dynamic เหมือนกันแต่อย่างที่กล่าวไว้ข้างต้นหากเรามี App มากๆเราอาจจะสับสนได้ว่า detail นี้คือของอันไหนนั่นเอง

    จาก Tutorial Part 3 นี้จะเห็นได้ว่า เราสามารถใช้ templates เพื่อแก้ปัญหาในส่วนของการสร้างไฟล์ HTML เองหลายๆไฟล์ได้โดย django จะเรียก templates ที่เราเขียนไว้มา render ออกเป็น Output แสดงผลทาง Browser ให้ผู้ใช้สามารถดูได้โดยที่เราไม่ต้องเขียน HTML ของ poll ทั้งหมดเอง และนอกจากนี้ ในส่วนของ urls เรายังสามารถดึงค่าจาก urls มาใช้ใน Functions เพื่อเลือก Objects หรือรูปแบบการแสดงผลต่างๆได้

ข้อมูลเพิ่มเติมของ Regular Expressions จาก wikipedia.org
Read more ...

วันอาทิตย์ที่ 1 ธันวาคม พ.ศ. 2556

Django Tutorial Part 2 - Admin site

    เริ่มต้นเปิด terminal แล้วทำการ cd ไปยัง Directory ที่เก็บไฟล์ manage.py ของ Project เอาจากนั้นพิม python manage.py runserver จะได้ดังรูป


    จากลองเข้าไปที่ 127.0.0.1:8000/admin จะปรากฏหน้าให้ Login เข้าระบบหากใครจำได้ใน Part 1 นั้นเราได้ทำการสร้าง Superuser เอาไว้แล้วนำ Username พร้อม Password ที่ตั้งไว้มาใส่ได้เลย


    จากนั้นไปแก้ไขไฟล์ admin.py ที่อยู่ใน polls/admin.py ของ Project ของเราเพื่อให้ สามารถแสดง App polls ที่เราสร้างใน Tutorial 1 ได้โดยแก้ไขให้เป็นดังนี้

from django.contrib import admin
from polls.models import Poll
admin.site.register(Poll)

แล้วลองเข้าไปที่ admin ใน Browser อีกครั้งจะได้ดังรูป



จากนั้นเข้าไปที่ Polls จะพบ What's up? ซึ่งเป็นข้อมูลที่เราได้สร้างไว้ใน Tutorial 1 คลิกเข้าไปเพื่อลองแก้ไข


จากนั้นลองแก้ไขในส่วนของ Date published เป็นเท่าไหร่ก็ได้


เมื่อแก้ไขเสร็จกด Save แล้วลองกดที่ History ดูจะเห็นข้อมูลว่าเราแก้ไขอะไรไป


การปรับเปลี่ยนรูปแบบการแสดงผล

    หากเราต้องการจะปรับแต่งรูปแบบการแสดงผลของการเข้าไปแก้ไขข้อมูลของ admin ก็สามารถทำได้โดยเพิ่ม Class เข้าไปในไฟล์ admin.py ใน polls/admin.py

แบบที่ 1 เลือกรูปแบบการจัดอันดับโดยเรียงตามลำดับข้อมูลใน list fields


class PollAdmin(admin.ModelAdmin):
    fields = ['pub_date', 'question'] 
admin.site.register(Poll, PollAdmin)


แบบที่ 2 แยกข้อความออกเป็น 2 บล็อก


class PollAdmin(admin.ModelAdmin):
    fieldsets = [
          (None,                    {'fields': ['question']}),
          ('Date information', {'fields': ['pub_date']}),
    ] 


แบบที่ 3 ต่อจากแบบที่ 2 นอกจากแยก 2 บล็อกแล้วยังซ่อนไว้ได้อีกด้วย


class PollAdmin(admin.ModelAdmin):
    fieldsets = [
         (None,                    {'fields': ['question']}),
         ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]


การเพิ่มObjectที่สัมพันธ์กันเข้ามาในหน้า Admin

    หากใครจะได้ว่าใน Tutorial Part 1 นั้นเรามี Choice ด้วยดังนั้นเราจะเพิ่ม Choice เข้ามาในส่วนของ Admin ได้ก็ต้องแก้ไขในไฟล์เดิม admin.py ใน polls/admin.py

from django.contrib import admin
from polls.models import Choice, Poll
class ChoiceInline(admin.StackedInline):
    model = Choice
    extra = 3
class PollAdmin(admin.ModelAdmin):
    fieldsets = [
         (None,                    {'fields': ['question']}),
         ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]
    inlines = [ChoiceInline]
admin.site.register(Poll, PollAdmin)

    โดยจากโค้ดที่เขียนไปจะทำให้ เราสามารถเพิ่มหรือ แก้ไข Choice ใน Poll ได้เลยโดยเพิ่มได้สูงสุด 3 Choice ซึ่งโค้ดนี้เป็นการบอก admin ว่า Choice นั้นให้มาแก้ไขใน Poll ได้เลย


    จากบรรทัดนี้ class ChoiceInline(admin.StackedInline):ในส่วนของ StackedInline นั้นเป็นรูปแบบของหน้าต่าง Choice ที่เพิ่มเข้าหากเราเปลี่ยนไปใช้เป็น
class ChoiceInline(admin.TabularInline): ก็จะได้รูปแบบการจัดเป็นอีกแบบ


การปรับเปลี่ยนแก้ไขในส่วนของ admin change list
    ในส่วนของ Class Poll ใน Tutorial Part 1 นั้นเราจะมี 2 Variable 1 Method ซึ่งเราสามารถแสดงทั้งหมดนั้นในหน้า admin change list ได้โดยการเพิ่มโค้ดข้างล่างนี้ไปไว้ล่างสุดของ class PollAdmin ใน admin.py

list_display = ('question', 'pub_date', 'was_published_recently')


    จากการเพิ่มโค้ดเข้าไปแล้วนอกจากจะแสดงผลแบบที่เราต้องการแล้วยังสามารถเรียงตามลำดับโดยหัวข้อได้อีกด้วยแต่มี 1 ช่องที่เรียงไม่ได้คือ was_published_recently ดังนั้นวิธีแกก็คือการเพิ่มโค้ดเข้าไปในไฟล์ model.py ล่างสุดของ Class Poll


was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'




    และนอกจากนี้เรายังสามารถเพิ่ม Filter และช่อง Serach ได้อีกโดยใส่โค้ดเพิ่มไปในไฟล์ admin.py ใต้ class PollAdmin

list_filter = ['pub_date']search_fields = ['question']



    จาก Tutorial Part 2 นี้เราสามารถที่จะปรับแต่งหน้า admin ของเราให้แสดงผลในรูปแบบตามที่ต้องการได้ เช่น เรียงลำดับตามการแก้ไขก่อนหลัง, การใช้ filter ในการช่วยค้นหาข้อมูล เป็นต้น เราสามารถเพิ่ม , ลบ หรือ แก้ไข Database ของ Apps แต่ละตัวได้ โดยการแก้ไขในไฟล์ admin.py 
Read more ...

Mercurial - Version Control System App

เริ่มต้นกันด้วยการ Install Mercurial ใน Ubuntu กันก่อนนะครับ
เปิด Terminal แล้วพิม sudo apt-get install mercurial


    จากนั้น cd ไปยัง Directory ที่ต้องการให้ Mercurial จัดการให้ และพิม hg init เพื่อเป็นการให้ Mercurial เริ่มทำงานจากนั้นลองพิม hg status จากนั้นพิม hg add จะสังเกตุเห็นว่าหน้าชื่อจะมีสัญลักษณ์ 2 แบบคือ ? กับ A ซึ่ง A หมายถึงว่าไฟล์นี้ได้ถูกเลือกเพื่อทำการจัดเก็บแล้วส่วน ? นั่นคือเรายังไม่ได้เลือกว่าจะให้ทำอย่างไรกับไฟล์เหล่านั้น



hg add เป็นคำสั่งเลือกไฟล์ให้ Mercurial จัดการโดยมีรูปแบบดังนี้

1.hg add เลือกไฟล์ทั้งหมดทุกไฟล์เข้าระบบ
2.hg add filename เลือกเฉพาะไฟล์ที่ตรงกับ filename เท่านั้น

จากนั้นลองพิม hg revert ./Tutorial1/*.pyc และ hg revert ./polls/*.pyc


hg revert ยกเลิกการเลือกไฟล์เข้าระบบโดยการยกเลิกมีรูปแบบดังนี้

1.hg revert * ยกเลิกการเลือกไฟล์ทั้งหมด
2.hg revert filename จะยกเลิกการเลือกไฟล์ที่ตรงกับ filename นั้นๆ

ซึ่งไฟล์ที่ไม่ควรเก็บก็จะมีไฟล์พวก .pyc .elc เป็นต้นซึ่งเราจะแก้ปัญหานี้โดยการเพิ่มไฟล์ .hgignore เข้าไปแต่ก่อนอื่นให้เราพิมคำสั่งใน terminal ว่า hg serve -p 9000


และลองเปิด Browser ขึ้นมาจากนั้นไปยัง address 127.0.0.1:9000/ จะโหลดหน้าของ Mercurial ขึ้นไปยังเมนูด้านซ้ายคลิกที่ help>hgignore จากนั้นลงไปล่างสุด Copy ตัวอย่างโค้ดของ hgignore ไว้


 จากนั้นกลับไปสร้างไฟล์ .hgignore โดยใช้โค้ดที่เราก็อปมาเมื่อกี้ใส่ลงในไฟล์ดังรูป


จากนั้นกลับไปที่ Terminal แล้วลองพิม hg status ดูจะพบว่าไม่มีไฟล์ .pyc อยู่ในรายชื่อเลยเนื่องจากไฟล์ .hgignore ที่เราสร้างไว้สักครู่เป็นตัวกรองออกไปจากนั้นพิม hg add เพื่อเลือกไฟล์ทุกไฟล์


 จากนั้นให้พิม hg commit -m "Description" -u Author จากตัวอย่าง Description ใช้เป็น Start Project และ Author เป็น jinkatana ซึ่งคำสั่ง commit นี้ใช้ในการสั่งให้ Mercurial เก็บค่าของไฟล์ในขณะนั้นเป็น 1 Version ของเรา


ลองแก้ไขไฟล์อะไรก็ได้ไฟล์นึงใน Project ของเราจากนั้นลองพิม hg status จะมีชื่อไฟล์ที่เราแก้ไขโผล่ขึ้นมาพร้อมตัวอักษร M นำหน้าหมายถึงว่าไฟล์ถูกแก้ไขไปวิธีการอัพเดทให้ Mercurial เก็บค่าล่าสุดของ Project ก็พิมคำสั่ง hg commit -m "Description" -u Author เช่นเดิม


เมื่อ commit เสร็จแล้วลองเปิด Browser เข้าไปที่ 127.0.0.1:9000 เช่นเดิมจะพบว่ามี Versions ใหม่เพิ่มเข้ามาโดยเราสามารถกดเข้าไปดูได้ว่ามีการเปลี่ยนแปลงอะไรไปบ้างในแต่ละ Versions ครับ


---เพิ่มความแตกต่างระหว่างเวอร์ชั่นให้ดู
Read more ...