สำรวจโครงสร้าง Django 2

เราจะทำการสำรวจโครงสร้างของ django app ที่ทำหน้าที่เก็บ config

ให้เปิด file openchef/settings.py และลองพิจารณาเนื้อหาภายใน

1 Review Database

DATABASES = {
    'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

2 Register templates folder ให้เรียบร้อย

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        ...
    },
]

3 สร้าง Database

$ python manage.py migrate

4 สร้าง Super User

python manage.py createsuperuser

สร้าง Application

สร้าง application โดยการใช้คำสั่ง python manage.py startapp

$ python manage.py startapp myrestaurants
$ cd myrestaurants
$ ls 
db.sqlite3  manage.py  myrestaurants  openedu

$ tree  myrestaurants

myrestaurants/
├── admin.py
├── apps.py
├── __init__.py
├── migrations
│   └── __init__.py
├── models.py
├── tests.py
└── views.py

เพิ่ม Django app ใน settings.py โดยการเพิ่มใน INSTALLED_APPS

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'myrestaurants',
]

เพิ่ม django app ให้ admin

from django.contrib import admin
import models

admin.site.register(models.Restaurant)
admin.site.register(models.Dish)
admin.site.register(models.RestaurantReview)

เพิ่ม Data models ให้แก่ myrestaurants/models.py ที่ได้จากการออกแบบ

from django.db import models
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from datetime import date

class Restaurant(models.Model):
    name = models.TextField()
    street = models.TextField(blank=True, null=True)
    number = models.IntegerField(blank=True, null=True)
    city = models.TextField(default="")
    zipCode = models.TextField(blank=True, null=True)
    stateOrProvince = models.TextField(blank=True, null=True)
    country = models.TextField(blank=True, null=True)
    telephone = models.TextField(blank=True, null=True)
    url = models.URLField(blank=True, null=True)
    user = models.ForeignKey(User, default=1)
    date = models.DateField(default=date.today)

    def __str__(self):
        return u"%s" % self.name

class Dish(models.Model):
    name = models.TextField()
    description = models.TextField(blank=True, null=True)
    price = models.DecimalField('Euro amount', max_digits=8, decimal_places=2, blank=True, null=True)
    user = models.ForeignKey(User, default=1)
    date = models.DateField(default=date.today)
    image = models.ImageField(upload_to="myrestaurants", blank=True, null=True)
    restaurant = models.ForeignKey(Restaurant, null=True, related_name='dishes')

    def __str__(self):
        return u"%s" % self.name

class Review(models.Model):
    RATING_CHOICES = ((1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'), (5, 'five'))
    rating = models.PositiveSmallIntegerField('Rating (stars)', blank=False, default=3, choices=RATING_CHOICES)
    comment = models.TextField(blank=True, null=True)
    user = models.ForeignKey(User, default=1)
    date = models.DateField(default=date.today)

    class Meta:
        abstract = True

class RestaurantReview(Review):
    restaurant = models.ForeignKey(Restaurant)

หลังจากนั้น จะทำการ update shema เพื่อเตรียมสร้าง database

$ python manage.py makemigrations myrestaurants
$ python manage.py migrate

Run Server อีกครั้ง

python manage.py runserver

เปิด Browser ไปยัง http://127.0.0.1:80000/admin

กำหนด urls.py ให้แก่ application

เพิ่ม บรรทัดใน settings.py โดยการใช้ include() myrestuarants.urls เข้ามา

from django.urls import include, path
from django.contrib import admin

urlpatterns = [
    path('admin/', admin.site.urls),
    path('myrestaurants/', include('myrestaurants.urls', name='myrestaurants')),
]

โดย urls.py เป็น python module เพื่อให้สำหรับการควบคุม routing

ใช้ include() function อ้างอังไปยัง URLconfs อื่น เมื่อ Django ใช้ include(), จะตัดส่วนของ URL matched จนถึง slash และจะส่งส่วนที่เหลือ ไปยัง URLConf ที่ include มาเพื่อประมวลผลต่อๆไป

The idea behind include() is to make it easy to plug-and-play URLs. Since polls are in their own URLconf (polls/urls.py), they can be placed under “/polls/”, or under “/fun_polls/”, or under “/content/polls/”, or any other path root, and the app will still work.

from django.urls import include, path
from django.utils import timezone
from django.views.generic import DetailView, ListView, UpdateView
from models import Restaurant, Dish
from forms import RestaurantForm, DishForm
from views import RestaurantCreate, DishCreate, RestaurantDetail

urlpatterns = [

# List latest 5 restaurants: /myrestaurants/
    path('', 
        ListView.as_view(
            queryset=Restaurant.objects.filter(date__lte=timezone.now()).order_by('date')[:5],
            context_object_name='latest_restaurant_list',
            template_name='myrestaurants/restaurant_list.html'),
        name='restaurant_list'),

# Restaurant details, ex.: /myrestaurants/restaurants/1/
    path('restaurants/<int:pk>',
        RestaurantDetail.as_view(),
        name='restaurant_detail'),

# Restaurant dish details, ex: /myrestaurants/restaurants/1/dishes/1/
    path('restaurants/<int:pkr>/dishes/<int:pk>',
        DetailView.as_view(
            model=Dish,
            template_name='myrestaurants/dish_detail.html'),
        name='dish_detail'),

# Create a restaurant, /myrestaurants/restaurants/create/
    path('restaurants/create/',
        RestaurantCreate.as_view(),
        name='restaurant_create'),

# Edit restaurant details, ex.: /myrestaurants/restaurants/1/edit/
    path('restaurants/<int:pk>/edit/',
        UpdateView.as_view(
            model = Restaurant,
            template_name = 'myrestaurants/form.html',
            form_class = RestaurantForm),
        name='restaurant_edit'),

# Create a restaurant dish, ex.: /myrestaurants/restaurants/1/dishes/create/
    path('restaurants/<int:pk>/dishes/create/',
        DishCreate.as_view(),
        name='dish_create'),

# Edit restaurant dish details, ex.: /myrestaurants/restaurants/1/dishes/1/edit/
    path('restaurants/<int:pkr>/dishes/<int:pk>/edit/',
        UpdateView.as_view(
            model = Dish,
            template_name = 'myrestaurants/form.html',
            form_class = DishForm),
        name='dish_edit'),

# Create a restaurant review, ex.: /myrestaurants/restaurants/1/reviews/create/
# Unlike the previous patterns, this one is implemented using a method view instead of a class view
    path('restaurants/<int:pk>/reviews/create/',
        'myrestaurants.views.review',
        name='review_create'),

django.urls function URLconf

path() เป็น function ที่เรียกใช้เพื่อเชื่อม path url เข้ากับ views มีโครงสร้างการใช้งานดังนี้

path(route, view, kwargs=None, name=None)
  • route argument เป็น ค่าของ string หรือ เป็นผลจากฟังก์ชั่น gettext_lazy() เป็นการบอกรูปแบบของ URL pattern string และสามารถที่จะมีกำหนด ตัวแปรที่ต้องการรับค่าจาก URL ไว้ใน angle brackets < > (เช่น <username> )และจะส่งไปให้กับ views ในรูปแบบของ keywork argument

  • ในส่วนของ anble brackets สามารถชนิดของข้อมูลเป็นชนิดอื่นได้เช่น <int:section> ทำให้เป็นการ จำกัดชนิดของข้อมูลที่จะส่งไปให้กับ view จากตัวอย่าง <int:section> จะทำสองอย่าง คือ รับข้อมูลที่เป็นตัวอักษรที่เป็นตัวเลข และทำการแปลง (Converter) ให้เป็น integer ก่อนที่จะส่งไปให้กับ views

ประเภทของ Convertors

  • str ประเภท สตริงที่ไม่เป็น non-empty string โดยแยกด้วยการใช้ '/' เป็น separator และเป็นค่า default ของ converter หากไม่มีการระบุ
  • int จะmatch กับ zero และ ตัวเลข ที่เป็น positive integer และ จะ return ค่าเป็น int
  • slug จะmatch กับ slug string เป็นตัวอักษร (ASCII-letter หรือตัวเลข รวมไปถือ underscore และ hyphen) เช่น building-your-1st-django-site

  • uuid จะ match ชนิด UUID เพื่อป้องกัน ไม่ให้ mutiple URLs มายัง page เดียวกัน เช่น 075194d3-6885-417e-a8a8-6c931e272f00

วิธีการ ที่ Django process request ที่เข้ามา

1 Django ใช้ module ชื่อ URLconf module ในการจับคู่ URL และ views เมื่อมี Request เข้ามา Django จะทำการสร้าง object ขึ้นมาเรียกว่า HttpRequest ที่มีข้อมูล meta data อยู่ภายใน รวมถือมีค่าของ attribute urlconf ของ request ที่ต้องการ โดยค่า attribute จะกำหนดจาก middle ware

2 Django จะทำการโหลด python module และอ่าน urlpatterns จะเป็นตัวแปร ชนิด list ที่ได้จาก django.urls.path() หรือ django.urls.re_path()

  1. Django จะทำการเปรียบเทียบ แต่ละ URL pattern เรียงตามลำดับ order และจะหยุดเมือเจอกับ pattern แรก

  2. Django จะทำการ Call ไปยัง python function หรือ Class-base view โดย view จะได้รับข้อมูลดังต่อไปนี้

  3. Instance ของ HttpRequest

  4. positional argument
  5. keywork argument
ตัวอย่าง
from django.urls import path

from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]
  • `/aricles/2005/04 จะเรียก function view.month_archive โดย Django จะทำการเรียก views.month_archive(request, year=2005,month=3)

  • /articles/2003 Django จะทำการเรียก บรรทัดแรก ที่ match views.special_case_2003(request)

  • /articles/2003 จะไม่ match กับอะไร เนื่องจาก แต่ละ pattern จะต้อง การ url ที่ลงท้ายด้วย slash (/)

  • /articles/2003/03/building-a-django-site/ Django จะทำการเรียก views.article_detail(request,

    year=2003,month=3,slug="building-a-django-site"

โดย middleware เป็น framework ที่จะทำการ hook เข้ากับกระบวนการ request/response processing ทำหน้าที่แบบ low-level plugin ของระบบ

results matching ""

    No results matching ""