D J A N G O

Django ในโปรเจกต์จริง: Best Practice 8 ข้อที่มือใหม่เกือบทุกคนพลาด

Django ในโปรเจกต์จริง: Best Practice 8 ข้อที่มือใหม่เกือบทุกคนพลาด

เปิดโปรเจกต์ Django ให้รันได้ไม่ใช่เรื่องยาก เพราะเฟรมเวิร์กนี้มากับของครบมือ ทั้ง ORM, Admin, Authentication และระบบเทมเพลต แต่พอถึงเวลาที่ต้องขึ้นระบบให้ผู้ใช้ใช้งานจริง ๆ สิ่งที่ทำให้เว็บหนึ่งอยู่รอดได้ยาว ๆ กับอีกเว็บหนึ่งถึงคราวสาหัส มักไม่ใช่ฟีเจอร์ใหญ่โตที่เขียนในวันแรก หากเป็นรายละเอียดเล็ก ๆ ที่สะสมทีละนิดจนกลายเป็นหนี้เทคนิคที่ต้องจ่ายดอกเบี้ยในภายหลัง บทความนี้รวบรวม Best Practice จากประสบการณ์ลงโปรเจกต์จริงของทีมที่พัฒนาเว็บด้วย Python-Django ลองไล่เช็คดูว่าโปรเจกต์ของคุณครบกี่ข้อแล้ว

โครงสร้างโปรเจกต์: แบ่งตั้งแต่ต้น ยิ่งเล็กยิ่งดูแลง่าย

ข้อผิดพลาดยอดฮิตของมือใหม่คือการสร้างแอปพลิเคชันเดียวแล้วใส่ทุกอย่างไว้ข้างใน ไม่ว่าจะเป็นเมนู ออเดอร์ โปรโมชัน หรือข้อมูลพนักงาน แรก ๆ สะดวกดี แต่พอฟีเจอร์โตขึ้น models.py ก็ยาวเป็นพันบรรทัด ใครแตะใครโดน แก้จุดหนึ่งพังอีกจุดหนึ่ง

แนวทางที่ใช้ได้จริงคือแยกเป็นแอปตามความรับผิดชอบ เช่น menu, orders, promotions, staff ยิ่งแยกให้ตรงกับขอบเขตธุรกิจเท่าไร ยิ่งง่ายต่อการให้เพื่อนร่วมทีมมือใหม่เข้ามาแก้ไข และเวลาต้องการถอดฟีเจอร์ไหนทิ้งก็ไม่ต้องกลัวพังทั้งระบบ

อีกเรื่องที่ควรทำตั้งแต่โปรเจกต์แรกคือการแยกตั้งค่า (settings) ตามสภาพแวดล้อม อย่างน้อยแยก development กับ production และเก็บความลับทั้งหมด ตั้งแต่ SECRET_KEY, ข้อมูลเชื่อมต่อฐานข้อมูล ไปจนถึงคีย์จากบริการภายนอก ไว้ในตัวแปรสภาพแวดล้อม ห้าม hard-code ลงโค้ดเด็ดขาด ไม่ว่าจะใช้ django-environ หรือ python-decouple หลักการสำคัญคือ “โค้ดไปได้ทุกเครื่อง แต่ความลับอยู่แค่กับเครื่องที่ควรรู้เท่านั้น”

กับดัก N+1 Query: ตัวร้ายที่ทำให้เว็บช้าเงียบ ๆ

ถ้าต้องเลือกแก้บั๊กตัวเดียวที่คุ้มค่าที่สุดกับการใช้ Django ในโปรเจกต์จริง หลายคนจะชี้ไปที่ปัญหา N+1 Query คือการสั่งเรียกข้อมูลซ้ำ ๆ หลายรอบทั้งที่ควรจบในรอบเดียว

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

orders = Order.objects.all()
for order in orders:  # แต่ละรอบ loop สร้าง query ใหม่
    print(order.customer.name)

เปลี่ยนเป็นแบบนี้ แล้วผลลัพธ์ได้จาก query เดียว:

orders = Order.objects.select_related('customer')
for order in orders:
    print(order.customer.name)
  • ใช้ select_related() เมื่อเชื่อมแบบ ForeignKey เพราะดึงข้อมูลมารวมกันใน query เดียว
  • ใช้ prefetch_related() สำหรับความสัมพันธ์แบบหลายต่อหลาย เช่น รายการอาหารในแต่ละออเดอร์
  • หมั่นสังเกตจำนวน query จากเครื่องมืออย่าง django-debug-toolbar ตอนพัฒนา
  • เพิ่ม index ในคอลัมน์ที่ใช้กรองหรือเรียงลำดับบ่อย ๆ เช่น เวลาสร้างออเดอร์

ความปลอดภัยที่ Django ให้ฟรี อย่าเผลอปิด

Django ขึ้นชื่อเรื่องความปลอดภัยในตัว เช่น ป้องกัน CSRF และ XSS มาให้พร้อม แต่ถ้า configure ผิด โปรเจกต์ก็ยังรั่วได้ เริ่มจากของง่ายที่สุดคือ อย่าลืมปิด DEBUG=False ในโปรดักชัน เพราะหน้า error page จะโชว์เส้นทางไฟล์และตัวแปรภายในให้ผู้ไม่หวังดีศึกษาระบบได้ฟรี จากนั้นเปิดการตั้งค่าเหล่านี้:

  • SECURE_SSL_REDIRECT: บังคับให้ทุกหน้าเว็บเข้าผ่าน HTTPS เท่านั้น
  • SECURE_HSTS_SECONDS: สั่งให้เบราว์เซอร์ใช้ HTTPS ต่อเนื่องตลอด
  • SESSION_COOKIE_SECURE และ CSRF_COOKIE_SECURE: รับส่ง cookie ผ่านช่องทางปลอดภัยเท่านั้น

พูดถึง SSL Certificate สักเล็กน้อย เพราะเป็นเพื่อนสนิทกับ Django ในโปรเจกต์จริง ข้อดีชัดเจนคือเข้ารหัสข้อมูลระหว่างผู้ใช้กับเว็บ ป้องกันข้อมูลหลุดตอนเดินทางผ่านเครือข่าย สร้างความน่าเชื่อถือให้ URL และเป็นปัจจัยหนึ่งที่ SEO ให้คะแนน ส่วนข้อเสียที่หลายคนลืมคิดคือ ใบรับรองแบบจ่ายเงินมีค่าใช้จ่ายรายปี และถ้าใช้ใบรับรองฟรีอย่าง Let's Encrypt ก็ต้องมีระบบจัดการต่ออายุให้ไม่ขาดตอน อีกทั้ง HTTPS มีค่าใช้จ่ายฝั่งประมวลผลเล็กน้อย แก้ได้ด้วย HTTP/2 และต้องระวังปัญหา mixed content คือรูปหรือสคริปต์บางไฟล์ยังโหลดผ่าน HTTP อยู่ ทำให้หน้าเว็บดู “ไม่ปลอดภัย” ทั้งที่ติดตั้ง SSL แล้ว

จากเว็บที่ต้องกด Refresh ไปสู่ระบบ Real-time ด้วย WebSocket

ประเด็นที่โปรเจกต์ธุรกิจถามหามากที่สุดในระยะหลังคือความสามารถแบบ real-time เพราะ Django พื้นฐานรองรับการสื่อสารแบบ request-response เท่านั้น ผู้ใช้ต้องโหลดหน้าใหม่ทุกครั้งถึงจะเห็นข้อมูลที่อัปเดต

ถ้าธุรกิจของคุณต้องการประสบการณ์แบบ “ข้อมูลขยับเองทันที” เช่น แอปสั่งอาหารที่ลูกค้าอยากเห็นสถานะออเดอร์เปลี่ยนจาก “กำลังทำอาหาร” เป็น “ไรเดอร์กำลังเดินทาง” แบบสด ๆ หรือร้านค้าอยากเห็นออเดอร์ใหม่โผล่ขึ้นบนหน้าจอ dashboard ทันทีโดยไม่ต้องกดปุ่มรีเฟรช การใช้ WebSocket ร่วมกับ Django Channels คือคำตอบที่ใช้จริงแล้วในระบบหลายธุรกิจไทย

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

ข้อควรระวัง: WebSocket ต่างจาก HTTP ตรงที่เปิด connection ค้างไว้ตลอดเวลา เมื่อมีผู้ใช้พร้อมกันจำนวนมาก ต้องวางสถาปัตยกรรมให้ดี เช่น ใช้ Redis เป็น channel layer สำหรับกระจายข้อความระหว่างเซิร์ฟเวอร์หลายเครื่อง และตั้งค่า Nginx ให้ถูกต้องเป็น proxy หน้า มิฉะนั้นจะเจอปัญหาแปลก ๆ เช่น ข้อความล่าช้าเมื่อคนเข้าพร้อมกันจนเซิร์ฟเวอร์โหลดสูง

การ Deploy ที่พังได้ แต่ฟื้นคืนเร็ว

ปิดท้ายด้วยเรื่องที่เห็นพลาดซ้ำ ๆ ในการขึ้นระบบจริงคือการจัดการฐานข้อมูลและสภาพแวดล้อม:

  • ก่อน run migrate บนโปรดักชันทุกครั้ง ให้สำรองฐานข้อมูลไว้เสมอ เผื่อ migration ผิดพลาดจะได้ย้อนกลับได้ง่าย
  • มี staging environment ที่ใกล้เคียงโปรดักชันที่สุด ก่อนปล่อยของจริงทุกเวอร์ชัน
  • ตั้ง logging ตั้งแต่โปรเจกต์เริ่มต้น อย่ารอให้ error เกิดแล้วค่อยมาเพิ่ม ทิ้ง log ไว้ในไฟล์หรือบริการเก็บ log กลางเพื่อไล่บั๊กได้เร็ว
  • ในโปรดักชันควรใช้ Gunicorn รับ request แล้วให้ Nginx เสิร์ฟ static files และทำ reverse proxy อย่าให้ Django รับทุกอย่าอย่างตรง ๆ ด้วยตัวมันเอง

Django จะแข็งแรงแค่ไหนก็ยังต้องอาศัยการตัดสินใจเล็ก ๆ ให้ถูกจุด ทั้งโครงสร้างโปรเจกต์ ประสิทธิภาพ query ความปลอดภัย และการรองรับผู้ใช้จำนวนมาก สิ่งเหล่านี้คือส่วนต่างระหว่างเว็บที่ “ทำเสร็จ” กับเว็บที่ “ใช้งานได้จริงอย่างยั่งยืน”

ถ้าทีมของคุณกำลังจะเริ่มโปรเจกต์ Python-Django หรือมีเว็บที่เริ่มดูแลยากขึ้นเรื่อย ๆ ทีมงาน pythonthailand.com (Para-Studio เชียงใหม่) พร้อมช่วยเหลือ ทั้งการรับเขียนโปรแกรมและเว็บไซต์ด้วย Python-Django รวมถึงพัฒนาระบบ AI อัตโนมัติต่อยอดจากเว็บเดิมที่คุณมีอยู่ ที่สำคัญเราวางสถาปัตยกรรมและ Best Practice เหล่านี้ไว้ตั้งแต่ต้น เพื่อให้เว็บของคุณเติบโตไปได้ไกลโดยไม่ชนเพดานทีหลัง แวะมาพูดคุยและขอคำปรึกษาได้ที่หน้า /contact ครับ


หากชอบบทความดีๆ โปรดติดตามพวกเราด้วยนะคะ 🙏