2015年7月18日 星期六

Python Django:Dinbendon(1)

  1. 建立專案
$ mkdir Dinbendon
$ cd Dinbendon
  1. 建立虛擬環境
$ python3 -m venv venv/Dinbendon
$ source venv/Dinbendon/bin/activate #進入虛擬環境
  1. 建立專案
$ django-admin startproject Dinbendon
$ python manage.py migrate #第一次使用 初始化Database
  1. 建立APP
$ python manage.py startapp restaurants
# Dinbendon/Dinbendon
$ vi settings.py

INSTALLED_APPS = (
     ...
    'django.contrib.staticfiles',
    'restaurants', #新增這行
)

設定view.py

#Dinbendon/restaurants/views.py

# -*- coding: utf-8 -*-
from django.shortcuts import render_to_response
from restaurants.models import Restaurant, Food

def menu(request):
    restaurants = Restaurant.objects.all()
    return render_to_response('menu.html',locals())

設定urls.py

#
...
from restaurants.views import menu

urlpatterns = [
     ...
     url(r'^menu/$', menu),
 ]
  1. 建立model
#Dinbendon/restaurants/models.py
from django.db import models

class Restaurant(models.Model):
    name = models.CharField(max_length=20)
    phone_number = models.CharField(max_length=15)
    address = models.CharField(max_length=50, blank=True)

    def __unicode__(self):
        return self.name

class Food(models.Model):
    name = models.CharField(max_length=20)
    price = models.DecimalField(max_digits=3,decimal_places=0)
    comment = models.CharField(max_length=50, blank=True)
    is_spicy = models.BooleanField()
    restaurant = models.ForeignKey(Restaurant)

    def __unicode__(self):
        return self.name
  1. 同步資料表
$ python manage.py makemigrations restaurants
  1. 透過shell新增資料
    練習透過Shell的方式新增資料,但還是可以透過admin的頁面新增比較快,這邊算是一個練習.
$ python manage.py shell
>>> from restaurants.models import Restaurant, Food
>>> r1 = Restaurant(name='隔壁老王滷肉飯', phone_number='02-12345678', address='天龍國天龍區天龍路1 號')
>>> r1
<Restaurant: Restaurant object>

建立一個模型物件記得匯入app中models.py裡的模型,並以參數(模型中個資料欄位的名稱)將之實體化即可,如上例r1是一個Restaurant物件,也就是資料表中的一筆資料,不過切記,目前該筆資料尚未被寫入資料庫中。

將模型物件(資料)寫入資料庫,利用save方法可以將資料寫入資料庫,等我們關閉shell後,該筆資料仍然會存在:

>>> r1.save()

模型的objects.all()方法可以從模型對應的資料表中取得所有的資料,並會回傳一個對應的模型物件清單(list of model objects)
objects.get方法會回傳一個模型物件,也就是一筆資料,如果回傳的是多筆或是查詢結果失敗(空),都會引發例外,這可以利用try/expect來捕獲並處理。

過濾查詢
利用屬性名+__contains=值可以搜尋該屬性包含值的資料(包含的意思表示不需全等,部分有符合即可)

>>> restaurants = Restaurant.objects.filter(name__contains='餐廳')
[<Restaurant: 古意得餐廳>]

排序查詢
QuerySet是依照id排序的,利用objects管理器的order_by方法,可以自行指定資料欄位進行排序:

>>> r = Restaurant.objects.get(name='古意得餐廳')
>>> f1 = Food(name='宮保雞丁', price=120, comment='超級辣', is_spicy=True, restaurant = r)
>>> f1.save()
>>> f2 = Food(name='炒青菜', price=85, comment='每日不同', is_spicy=False, restaurant = r)
>>> f2.save()
>>> Food.objects.all()
[<Food: 宮保雞丁>, <Food: 炒青菜>]
>>> Food.objects.order_by('price')
[<Food: 炒青菜>, <Food: 宮保雞丁>]

order_by的參數是字串,不要誤植為order_by(price)了。
Ex.

>>> Food.objects.order_by('price','name')      # 先排price再排name
>>> Food.objects.order_by('-price')            # 反向排序

任何一個QuerySet都能夠繼續以order_by、filter、get等方法進行查詢:

>>> Food.objects.order_by('price').filter(is_spicy=True).get(name__contains='宮保')
<Food: 宮保雞丁>

更新與刪除資料庫數據

>>> food = Food.objects.get(name='宮保雞丁')
>>> food.price = 200
>>> food.save()
or
>>> Food.objects.filter(name='宮保雞丁').update(price=200)
1

update是QuerySet的方法,無法作用在單獨物件上,所以我們要偷偷用點技巧,使用filter來過濾出只含有宮保雞丁的QuerySet。

刪除資料可以用delete方法

>>> f = Food.objects.get(name='宮保雞丁')
>>> f.delete()
>>> Food.objects.all()
[<Food: 炒青菜>]
>>> Food.objects.all().delete()
[]
  1. 顯示app
#.../restaurants/templates/menu.html
<!doctype html>
<html>
    <head>
        <title> Menu </title>
        <meta charset='utf-8'>
    </head>
    <body>
        {% for r in restaurants %}
            <h2>{{ r.name }}</h2>
            {% if r.food_set.all %}
                <p>本餐廳共有{{ r.food_set.all|length }}道菜</p>
                <table>
                    <tr>
                        <th>菜名</th>
                        <th>價格</th>
                        <th>註解</th>
                        <th>辣不辣</th>
                    </tr>
                {% for food in r.food_set.all %}
                    <tr>
                        <td> {{ food.name }} </td>
                        <td> {{ food.price }} </td>
                        <td> {{ food.comment }} </td>
                        <td> {% if food.is_spicy %}{% else %} 不辣 {% endif %} </td>
                    </tr>
                {% endfor %}
                </table>
            {% else %}
                <p>本餐廳啥都沒賣</p>
            {% endif %}
        {% endfor %}
    </body>
</html>

enter image description here

  1. Admin
    建立admin的資料表, 驗證模型
$ python manage.py check
System check identified no issues (0 silenced).

建立superuser, 設定帳號密碼

$ python manage.py createsuperuser

註冊model, 透過admin.site.register方法,便可以在admin介面中新增、檢視、編輯、刪除我們模型中的資料。

#.../restaurants/admin.py
from django.contrib import admin
from restaurants.models import Restaurant, Food

class RestaurantAdmin(admin.ModelAdmin):
    list_display = ('name', 'phone_number', 'address')
    search_fields = ('name',) 

class FoodAdmin(admin.ModelAdmin):
    list_display = ('name', 'restaurant', 'price')
    list_filter = ('is_spicy',)
    fields = ('price','restaurant')
    ordering = ('-price',)

admin.site.register(Restaurant)
admin.site.register(Food)
  1. 數據提交訊息 - GET與POST
    加入一個歡迎頁面
# .../Dinbendon/urls.py
# 以上略...

from Dinbendon.views import welcome
from restaurants.views import menu

urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url(r'^menu/$', menu),
    url(r'^welcome/$', welcome),
)

然後準備一個視圖給要回應的頁面

#/Deinbendon/templates/welcome.html

<html>
    <head>
        <title> Welcome </title>
    </head>
    <body>
        <form action="" method="get">
            <label for="user_name">您的名字</label>
            <input id="user_name" type="text" name="user_name">
            <input type="submit" value="進入網站">
        </form>
    </body>
</html>

在表單中,我們選用了GET方法,這表示我們提交表單後,表單內容中的鍵值對會形成查詢字符付在請求頁面的後面。
如果user_name欄位中的名字填的是datou,表單提交後,會發出一個請求,這個請求的路徑是:

http://網域名/welcome/?user_name=datou

user_name=datou這個鍵值配對會被存入request.GET中,用request.GET['user_name']可以存取到’dokelung’(字串型態)這個值。

最後是撰寫對應的view function:

#.../Dinbendon/views.py   //自行新增

# -*- coding: utf-8 -*-
from django.shortcuts import render_to_response

def welcome(request):
    if 'user_name' in request.GET:
        return HttpResponse('Welcome!~'+request.GET['user_name'])
    else:
        return render_to_response('welcome.html',locals())
  1. 顯示welcome.html
    要讓Django知道這個template並不是在app的資料夾中,不然runserver的話,會一直出現TemplateDoesNotExist. 要對settings.py進行修改.
import os

PACKAGE_ROOT = os.path.abspath(os.path.dirname(__file__))
...
#set DIRS in TEMPLATES setting var:
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(PACKAGE_ROOT, 'template')], #新增這行.
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

enter image description here

參考:
https://github.com/uranusjr/django-tutorial-for-programmers
http://stackoverflow.com/

沒有留言:

張貼留言