แผนการเรียนรู้
/

สัปดาห์ที่ 5: Views and Templates

สร้างหน้าเว็บแบบ Dynamic ด้วย Django Views และ Templates

วัตถุประสงค์

  • อธิบายรูปแบบการกำหนดการเข้าถึงและการแสดงผล (Function-Based View และ Class-Based View)
  • เขียนข้อกำหนดการเข้าถึงตามข้อกำหนดที่ระบุให้ได้
  • ประยุกต์ใช้ความรู้เพื่อแสดงผลตามข้อกำหนดที่ระบุให้ได้

เนื้อหาหลัก

  • Views: รับ HTTP request และส่ง HTTP response
  • Function-Based View (FBV): View ที่เขียนในรูปแบบ function
  • Class-Based View (CBV): View ที่เขียนในรูปแบบ class
  • Templates: ไฟล์ HTML ที่ใช้แสดงผลข้อมูล (Dynamic Content)
  • Django Template Language (DTL): ภาษาที่ใช้แทรกข้อมูลลงใน Template
  • URL Configuration: กำหนด URL patterns ที่ map กับ Views

Agenda

  • ทำความเข้าใจ Views และ Templates ใน Django
  • เขียน Function-Based Views (FBV)
  • เขียน Class-Based Views (CBV)
  • ใช้ Django Template Language (DTL) แสดงผลข้อมูล
  • กำหนด URL Configuration เพื่อ map URLs กับ Views
  • ตัวอย่างการใช้งานจริง และ Workshop

Views: หัวใจของการแสดงผล

Views ทำหน้าที่รับ Request และสร้าง Response ที่เหมาะสม

Request/Response Cycle

  • Request: ผู้ใช้ส่ง Request (เช่น คลิก link, submit form)
  • URL Dispatcher: Django ตรวจสอบ URL ที่ถูก Request
  • View: URL Dispatcher เรียก View ที่เกี่ยวข้อง
  • Process: View ประมวลผล Request (เช่น ดึงข้อมูลจาก database)
  • Response: View สร้าง Response (เช่น HTML page, JSON data)
  • Return: Django ส่ง Response กลับไปยังผู้ใช้

หน้าที่ของ View

  • รับ HTTP Request (GET, POST, etc.)
  • ประมวลผลข้อมูล (เช่น ตรวจสอบฟอร์ม, ดึงข้อมูลจาก Model)
  • เลือก Template ที่จะใช้แสดงผล
  • สร้าง Context (ข้อมูลที่ส่งให้ Template)
  • Render Template พร้อม Context
  • Return HTTP Response

Key Concepts

  • Views คือ Python functions หรือ classes ที่รับ request และ return response
  • Response มักจะเป็น HTML page ที่สร้างจาก Template
  • Context คือ dictionary ที่มีข้อมูลที่จะถูกส่งไปยัง Template

Function-Based Views (FBV)

เขียน Views ในรูปแบบ Function ที่เข้าใจง่าย

FBV คืออะไร?

  • Function ที่รับ request object เป็น argument
  • Return HttpResponse object
  • เหมาะสำหรับ View ที่ logic ไม่ซับซ้อน
  • อ่านและเขียนง่าย

ตัวอย่าง FBV

                
from django.shortcuts import render
from django.http import HttpResponse

def my_view(request):
  # Logic ของ View
  context = {'message': 'Hello from FBV!'}
  return render(request, 'my_template.html', context)

def another_view(request, name):
  # View ที่รับ argument จาก URL
  return HttpResponse(f"Hello, {name}!")
                
              

การใช้งาน FBV

  • กำหนด URL pattern ใน urls.py ที่ map กับ Function View
  • ใช้ render() เพื่อสร้าง HttpResponse จาก template
  • ใช้ HttpResponse() เพื่อ return ข้อความโดยตรง
  • สามารถรับ parameters จาก URL ได้

Class-Based Views (CBV)

เขียน Views ในรูปแบบ Class เพื่อจัดการ Logic ที่ซับซ้อน

CBV คืออะไร?

  • Class ที่ inherit จาก Django View classes (เช่น View, TemplateView, ListView, CreateView)
  • จัดการ HTTP methods (GET, POST, etc.) ด้วย method get(), post(), etc.
  • เหมาะสำหรับ View ที่ logic ซับซ้อนและต้องการ reuse code

myapp/views.py

                
from django.views import View
from django.shortcuts import render

class MyView(View):
  def get(self, request):
     # Logic สำหรับ GET request
     context = {'message': 'Hello from CBV!'}
    return render(request, 'my_template.html', context)

  def post(self, request):
     # Logic สำหรับ POST request
     # ...
     return HttpResponse("POST request received")
                
              

การใช้งาน CBV

  • ใช้ as_view() method ใน urls.py เพื่อ map URL กับ CBV
  • Override methods (get(), post(), etc.) เพื่อจัดการ HTTP methods
  • ใช้ Mixins เพื่อเพิ่ม functionality ให้กับ CBV

myapp/urls.py

                
urlpatterns = [
  path('myview/', MyView.as_view(), name='myapp:myview')
]
                
              

Templates: สร้างหน้าเว็บที่สวยงาม

แยก Logic และ Presentation ด้วย Django Templates

Templates คืออะไร?

  • ไฟล์ HTML ที่มี placeholders สำหรับใส่ข้อมูล
  • ใช้ Django Template Language (DTL) เพื่อแทรกข้อมูล
  • ช่วยแยก logic ของ application ออกจาก presentation
  • ทำให้ code อ่านง่ายและ maintain ง่ายขึ้น

ตัวอย่าง Template

                
<h1>Hello, {{ name }}!</h1>
<p>Today is {{ today }}.</p>

<ul>
  {% for item in items %}
    <li>{{ item }}</li>
  {% endfor %}
</ul>
                
              

การใช้งาน Templates

  • สร้าง template file ใน directory templates/
  • ใช้ render() function ใน View เพื่อ render template
  • ส่ง context (ข้อมูล) ให้กับ template
  • ใช้ DTL syntax ({{ variable }}, {% tag %}) เพื่อแทรกข้อมูล

Template Inheritance: {% extends %}

สร้าง Templates ที่ reusable ด้วย Template Inheritance

Template Inheritance คืออะไร?

  • สร้าง base template ที่มีโครงสร้างหลักของหน้าเว็บ
  • สร้าง child template ที่ extends base template และ override บางส่วน
  • ช่วยลด code ซ้ำซ้อนและทำให้ code maintain ง่ายขึ้น

Base Template (base.html)

                
<!DOCTYPE html>
<html>
<head>
  <title>{% block title %}My Site{% endblock %}</title>
<head>
<body>
  <h1>My Site</h1>
  {% block content %}{% endblock %}
</body>
</html>
                
              

* ใช้ {% block %} tag เพื่อกำหนดส่วนที่ child template สามารถ override ได้

Child Template (home.html)

                
{% extends 'base.html' %}

{% block title %}Home{% endblock %}

{% block content %}
  <p>Welcome to my site!</p>
{% endblock %}
                
              

* ใช้ {% extends %} tag เพื่อบอกว่า template นี้ extends base template * ใช้ {% block %} tag เพื่อ override ส่วนต่างๆ ใน base template

Template Reusability: {% include %}

นำ Template ส่วนย่อย มาใช้ซ้ำในหลายๆ Template

Template Reusability คืออะไร?

  • สร้าง template ส่วนย่อย (partial template) ที่สามารถนำไปใช้ซ้ำได้
  • เหมาะสำหรับส่วนประกอบที่ใช้ร่วมกัน (เช่น navigation bar, footer)
  • ช่วยลด code ซ้ำซ้อนและทำให้ code maintain ง่ายขึ้น

Reusable Template (navbar.html)

                
<nav>
  <a href="/">Home</a>
  <a href="/about/">About</a>
  <a href="/contact/">Contact</a>
</nav>
                
              

Include Template (home.html)

                
{% extends 'base.html' %}

{% block content %}
  {% include 'navbar.html' %}
  <p>Welcome to my site!</p>
{% endblock %}
                
              

* ใช้ {% include %} tag เพื่อนำ template ส่วนย่อย มาใส่ใน template หลัก

Django Template Language (DTL)

เรียนรู้ Syntax และ Features ต่างๆ ของ DTL

DTL คืออะไร?

  • Template engine ที่ใช้ใน Django
  • ใช้ในการแทรกข้อมูล, ทำ loops, conditionals ใน Templates
  • Syntax:
    • Variables: {{ variable }}
    • Tags: {% tag %}
    • Filters: {{ variable|filter }}

ตัวอย่าง DTL

                
<p>Hello, {{ user.name|upper }}!</p>

{% if user.is_authenticated %}
  <p>Welcome back!</p>
{% else %}
  <p>Please login.</p>
{% endif %}

<ul>
  {% for item in items %}
    <li>{{ item|default:"N/A" }}</li>
  {% endfor %}
</ul>
                
              

DTL Features

  • Variables: แสดงค่าของตัวแปร
  • Tags: ควบคุม logic ของ template (loops, conditionals, etc.)
  • Filters: แก้ไข format ของตัวแปร (uppercase, lowercase, date formatting, etc.)
  • Template Inheritance: สร้าง base template และ extend ใน template อื่นๆ

URL Configuration

กำหนด URL Patterns เพื่อเชื่อมต่อ URLs กับ Views

URL Configuration คืออะไร?

  • การกำหนด URL patterns ที่จะ map กับ Views
  • อยู่ในไฟล์ urls.py (project-level และ app-level)
  • ใช้ path() หรือ re_path() function

ตัวอย่าง URL Configuration

                
from django.urls import path
from myapp import views

urlpatterns = [
  path('', views.index, name='index'),
  path('about/', views.about, name='about'),
  path('articles/<int:year>/', views.articles_by_year, name='articles_by_year'),
]
                
              

URL Configuration Features

  • path(): ใช้สำหรับ simple URL patterns
  • re_path(): ใช้สำหรับ regular expression based URL patterns (advanced)
  • URL parameters: ส่งค่าจาก URL ไปยัง View (เช่น )
  • Name: กำหนดชื่อให้กับ URL pattern เพื่อใช้ใน reverse() function

แสดง Student List ด้วย FBV: students

สร้าง View และ URL Pattern เพื่อแสดง object_list ของ Student

View (myapp/views.py)

                
from django.shortcuts import render
from myapp.models import Student

def students(request):
  students = Student.objects.all()
  context = {'students': students}
  return render(request, 'student_list.html', context)
                
              

* ดึงข้อมูล Student ทั้งหมดจาก database * ส่งข้อมูลไปยัง template myapp/templates/myapp/student_list.html

URL Configuration (myapp/urls.py)

                
from django.urls import path
from . import views

urlpatterns = [
  path('students/', views.students, name='students'),
]
                
              

* Map URL /students/ ไปยัง view function students * กำหนดชื่อ URL pattern เป็น students

Template (myapp/templates/myapp/student_list.html)

                
<h1>Student List</h1>
<ul>
  {% for student in students %}
    <li>{{ student.name }} - {{ student.email }}</li>
  {% endfor %}
</ul>
                
              

* แสดง list ของ Student objects
* สามารถเพิ่มรายละเอียดเพิ่มเติม (เช่น dob) ได้

Paginator: แบ่งหน้า Student List ด้วย FBV

เพิ่ม Paginator เพื่อแบ่ง Student list เป็นหน้าๆ

View (myapp/views.py)

                
from django.shortcuts import render
from django.core.paginator import Paginator
from .models import Student

def students(request):
  student_list = Student.objects.all()
  paginator = Paginator(student_list, 10) # แสดง 10 รายการต่อหน้า

  page_number = request.GET.get('page')
  page_obj = paginator.get_page(page_number)

  context = {'page_obj': page_obj}
  return render(request, 'student_list.html', context)
                
              

* สร้าง Paginator object โดยระบุ list และจำนวนรายการต่อหน้า
* ดึงหมายเลขหน้าจาก request parameters (request.GET.get('page'))
* ใช้ get_page() เพื่อ get Page object
* ส่ง page_obj ไปยัง template

Template (myapp/templates/myapp/student_list.html)

                
<h1>Student List</h1>
<ul>
  {% for student in page_obj %}
    <li>{{ student.name }} - {{ student.email }}</li>
  {% endfor %}
</ul>

<div class="pagination">
  <span class="step-links">
    {% if page_obj.has_previous %}
      <a href="?page=1">« first</a>
      <a href="?page={{ page_obj.previous_page_number }}">previous</a>
    {% endif %}

    <span class="current">
      Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
    </span>

    {% if page_obj.has_next %}
      <a href="?page={{ page_obj.next_page_number }}">next</a>
      <a href="?page={{ page_obj.paginator.num_pages }}">last »</a>
    {% endif %}
  </span>
</div>
                
              

* ใช้ page_obj ในการวน loop และแสดงข้อมูล
* แสดง pagination links (first, previous, next, last)
* page_obj.has_previous, page_obj.has_next, page_obj.previous_page_number, page_obj.next_page_number, page_obj.number, page_obj.paginator.num_pages คือ properties ของ Page object

Paginator: แบ่งหน้า Student List ด้วย CBV (ListView)

ใช้ Class-Based View (ListView) เพื่อจัดการ Paginator อย่างง่ายดาย

View (myapp/views.py)

                
from django.views.generic import ListView
from myapp.models import Student

class StudentListView(ListView):
    model = Student
    template_name = 'student_list.html'  # ชื่อ Template
    context_object_name = 'students'  # ชื่อตัวแปรใน Template
    paginate_by = 10  # จำนวน Student ต่อหน้า
                
              

* Inherit จาก ListView
* กำหนด model, template_name, context_object_name, และ paginate_by
* ListView จัดการ Paginator ให้โดยอัตโนมัติ

URL Configuration (myapp/urls.py)

                
from django.urls import path
from . import views

urlpatterns = [
    path('students/', views.StudentListView.as_view(), name='students'),
]
                
              

* ใช้ .as_view() เพื่อ map URL ไปยัง CBV

Template (myapp/templates/myapp/student/list.html)

                
<h1>Student List</h1>
<ul>
  {% for student in page_obj %}
    <li>{{ student.name }} - {{ student.email }}</li>
  {% endfor %}
</ul>

<div class="pagination">
  <span class="step-links">
    {% if page_obj.has_previous %}
      <a href="?page=1">« first</a>
      <a href="?page={{ page_obj.previous_page_number }}">previous</a>
    {% endif %}

    <span class="current">
      Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
    </span>

    {% if page_obj.has_next %}
      <a href="?page={{ page_obj.next_page_number }}">next</a>
      <a href="?page={{ page_obj.paginator.num_pages }}">last »</a>
    {% endif %}
  </span>
</div>
                
              

* object_list คือชื่อ default ของ list ที่ส่งมาจาก ListView (หรือใช้ context_object_name เพื่อเปลี่ยนชื่อ)
* page_obj ยังคงใช้งานได้สำหรับการจัดการ pagination

สร้าง Blog Application

ลงมือสร้าง Blog Application อย่างง่าย เพื่อฝึกฝนสิ่งที่เรียนรู้

Workshop Steps

  1. สร้าง Django project และ app (blog)
  2. กำหนด Model สำหรับ Post (title, content, author, date)
  3. สร้าง Views สำหรับแสดง list ของ Posts และรายละเอียดของ Post แต่ละอัน (FBV หรือ CBV)
  4. สร้าง Templates สำหรับ Views
  5. กำหนด URL patterns ใน urls.py
  6. เพิ่มข้อมูล Post ใน database
  7. แสดงผล Post ใน Templates

Extra Challenges

  • เพิ่ม pagination ใน list ของ Posts
  • เพิ่ม filter สำหรับค้นหา Posts
  • เพิ่ม form สำหรับสร้างและแก้ไข Posts (ต้องใช้ CBV)
  • เพิ่ม User Authentication (login/logout)

Resources