2015年7月12日 星期日

Python筆記:Django(6) Model View

HttpRequest

所有的View function(有跟某URL對應的函式)都應該以HttpRequest物件作為第一個參數。這是因為HttpRequest物件(之後會以request代稱HttpRequest)含有關於本次web request及使用者的重要資訊,所以,沒有request,我們對於使用者的情況和需求以及提供的資訊會一無所知。

URL訊息:
下面範例將介紹request包含了哪些有用的URL訊息.

# mysite/restaurants/menu.html
# 以上略...

    <body>
        <p>您現在的位置在{{ path }}</p>  # 加入本行

        {% for r in restaurants %}
            <h2>{{ r.name }}</h2>
            {% if r.food_set.all %}
                <p>本餐廳共有{{ r.food_set.all|length }}道菜</p>
# 以下略...

我們看到在模版上多出了一個{{ path }}變量,我們必須在視圖函式中準備好該變量:

# mysite/restaurants/views.py
# 以上略...

def menu(request):
    path = request.path  # 加入本行

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

會發現在首行出現了位置的資訊,request就是知道這些!如果你需要提示使用者在哪個位置,就不需要將位置資訊寫死到模版中了,透過request.path我們可以知道除了網域名稱以外的請求路徑。

enter image description here

META

request物件裡面還有一個記錄header訊息的字典,叫做META,無論是使用者瀏覽器的資訊或是客戶端的IP位址,都可以查詢的到。要把資料列印出來的方法很簡單,先設定url對應,再撰寫視圖函式.

Ex.

def meta(request):
    values = request.META.items()  # 將字典的鍵值對抽出成為一個清單

    values.sort()                  # 對清單進行排序

    html = []
    for k, v in values:
        html.append('<tr><td>{0}</td><td>{1}</td></tr>'.format(k, v))
    return HttpResponse('<table>{0}</table>'.format('\n'.join(html)))

GET與POST

這兩個方法負責提交使用者表單的數據,表現上的差別在:GET方法會透過在請求路徑後面添增查詢字符來提交數據,而POST方法是隱性地傳送數據的鍵值對.兩者在請求上的不同:

GET     www.restaurants.com/restaurant/?id=1
POST    www.restaurants.com/restaurant

這使得POST方法更適合拿來做資訊需隱密的請求,而GET方法則能漂亮的提供一個查詢相同頁面的URL(每次使用這個URL總是能獲得一個id=1的頁面,POST方法可能就不行了),GET方法適合用來取得數據和對應的頁面,POST方法適合利用提交數據去更動資料庫.

這兩個方法所提交的數據都會以鍵值對的方式儲存於request物件中,分別存於request.GETrequest.POST,分別都是一個類似於字典的物件。

在這邊我們要將之前建立的Model顯示在網頁上.

# Dinbendon/urls.py
...
url(r'^store/$', store_list, name='store_list'),
...

利用stores = Store.objects.all()取出所有的 store objects 後,在 render 的最後面增加一個參數。這個參數為 render 提示了額外的 context data,可以在處理 template 時使用。

# stores/views.py
#...
from .models import Store

def store_list(request):
stores = Store.objects.all()
return render(request, 'store_list.html', {'stores': stores})
#...

template tags for 與 endfor。這是 Django templates 中表示迴圈的方法。在 templates 裡沒辦法用縮排表示階層,所以我們是用一個 endfor 標籤來標示迴圈結束。取用物件內 attributes 的方法仍然是用一個點,不過我們必須在旁邊加上兩組大括弧,來標注這是 template 語法,而不是真的要在 HTML 中印出 store.name 這個字串。

{# stores/templates/store_list.html #}

<!DOCTYPE html>
<html>
<head>
<title>店家列表 | 午餐系統</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
</head>

<body>
<nav class="navbar navbar-default navbar-static-top" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="{% url 'home' %}">午餐系統</a>
</div>
</div>
</nav>

<div class="container">
{% for store in stores %}
<div class="store">
<h2>{{ store.name }}</h2>
<p>{{ store.notes }}</p>
</div>
{% endfor %}
</div>

</body>
</html>

執行runserver,在http://..../store/中會出現我們原本在/admin中增加的store.
enter image description here

新增每個store的獨立頁面

第一步:如何把網址對應到合適的頁面。Django 的做法就是用 capturing groups,pk在這裡指 primary key

# Dinbendon/urls.py
...
url(r'^store/(?P<pk>\d+)/$', store_detail, name='store_detail'), # 新增這行
url(r'^admin/', include(admin.site.urls)),
)
# stores/views.py

from django.http import Http404

def store_detail(request, pk):
     try:
         store = Store.objects.get(pk=pk)
     except Store.DoesNotExist:
         raise Http404
     return render(request, 'store_detail.html', {'store': store})
<!DOCTYPE html>
<html>
<head>
<title>{{ store.name }} | 午餐系統</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
</head>

<body>
<nav class="navbar navbar-default navbar-static-top" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="{% url 'home' %}">午餐系統</a>
</div>
</div>
</nav>

<div class="container">
<h1>{{ store.name }}</h1>
<p>{{ store.notes }}</p>
<table class="table">
<thead>
<tr><th>品項</th><th>單價</th></tr>
</thead>
<tbody>
{% for item in store.menu_items.all %}
<tr><td>{{ item.name }}</td><td>{{ item.price }}</td></tr>
{% endfor %}
</tbody>
</table>
</div>

</body>
</html>

另外在store_list.html中 的 <h2> 那行改成這樣:

<h2><a href="{% url 'store_detail' pk=store.pk %}">{{ store.name }}</a></h2>

使用 url tag,不過這次除了 name 之外多加了一個參數。這裡傳入的參數會被用在 URL 的 capturing group 上,所以這樣就可以得到某個 store 的 URL!

執行runserver:
enter image description here


enter image description here

參考:
http://dokelung-blog.logdown.com/posts/220833-django-notes-7-forms

Python筆記:Django(5) Admin

Django 內建了一個 admin 介面,方便你快速產生一個簡單的管理平台。


建立一個超級使用者帳號(用來登入管理介面):

python manage.py createsuperuser

會要求設定帳號密碼,設定完之後執行runserver

python2.7 manage.py runserver 192...

在瀏覽器輸入網址:http://192.168.0.4:8000/admin會出現登入頁面.
enter image description here

為了在管理者畫面能夠看到你設定的model,將下面的code加入admin.py

註冊model

admin管理平台的功能或是頁面呈現的樣子都是預設的,但我們其實可以針對我們理想中的介面進行客製化。這有賴於註冊模型於admin上時,要採用繼承於ModelAdmin的自定義類別。
透過admin.site.register方法,便可以在admin介面中新增、檢視、編輯、刪除我們模型中的資料。

from django.contrib import admin
from .models import MenuItem, Store

@admin.register(MenuItem)
class MenuItemAdmin(admin.ModelAdmin):
    list_display = ('name', 'price',)

@admin.register(Store)

定義了一個繼承自MenuItem的MenuItemAdmin類別,list_display這個元組變數,此元組裡面的每個元素都是一個字串而且要是模型欄位的名字。只要有指定在此元組的欄位,都會被顯示在admin中的全檢視頁面中。

再設定任何一個元組的時候,如果只有一個元素,請務必要加上一個,來避免誤會

list_filter: 過濾器能夠針對特定欄位的值,進行過濾,在全檢視頁面中只顯示特定欄位值的資料。
Ex.

 list_filter = ('CharField',)

search_fields: 當資料漸漸龐大,而想要檢視某部分特定的資料時
Ex.

 search_fields = ('name',)

用 Django admin 內建的 inline admin 功能,把 MenuItem 的 admin 嵌到 Store 的 admin 頁面裡。

class MenuItemInline(admin.StackedInline):
model = MenuItem
extra = 1

結果:

#stores/admin.py
from django.contrib import admin
from .models import MenuItem, Store

class MenuItemInline(admin.TabularInline):
    model = MenuItem
    extra = 1

@admin.register(MenuItem)
class MenuItemAdmin(admin.ModelAdmin):
    list_display = ('name', 'price',)

@admin.register(Store)
class StoreAdmin(admin.ModelAdmin):
    list_display = ('name', 'notes',)
    inlines = (MenuItemInline,)

留空白

在資料庫中,有兩種值都可能被稱為空白,一種是NULL,另外一種是空字串。有的時候這種差異和不一致會造成麻煩,舉例來說,我想找出所有有空白欄位的資料,我們對於使用NULL來檢查或是空字串來檢查可能會有疑義。

為了統一,Django在模型生成的時候會自動將各欄位設置為非NULL:NOT NULL

對於留白的欄位,我們便知道Django會寫入空字串到資料庫中,而不會是NULL了。但是這又產生了另外一個問題,日期跟時間的欄位是不允許空字串輸入的,為了留空,他必須允許NULL值的填入,解決的辦法是在模型撰寫時,用參數null=True來允許表格為NULL,結合以上兩點,對於一個可允許留空的時間日期欄位,我們必須同時指定blank=Truenull=True。不過對於已經生成好的資料表而言,我們若是回過頭要加入null=True的特性,又牽扯到資料表結構的異動,這部份便要留待之後說明。

 date = models.DateField(blank=True, null=True)

欄位名稱還有一個玄機,我們會發現,Django會用以下規則為模型在admin中的欄位名稱命名。

欄位名稱 = 屬性名稱首字大寫 + 以空白取代屬性中的底線
e.g. phone_number => Phone number

如果大家不滿意這種命名規則,可以在模型中利用verbose_name來指定想要的名稱:

 phone_number = models.CharField(max_length=15,verbose_name='poneNum')

admin管理功能與自定義ModelAdmin

admin管理平台的功能或是頁面呈現的樣子都是預設的,但我們其實可以針對我們理想中的介面進行客製化。這有賴於註冊模型於admin上時,要採用繼承於ModelAdmin的自定義類別。

列表顯示

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

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

admin.site.register(Restaurant,RestaurantAdmin)
admin.site.register(Food)

定義了一個繼承自admin.ModelAdmin的RestaurantAdmin類別,裡面我們使用了list_display這個元組變數,此元組裡面的每個元素都是一個字串而且要是模型欄位的名字。

設定任何一個元組的時候,如果只有一個元素,請務必要加上一個,來避免誤會,切記切記。admin設置如果有誤可以先檢查一下是不是有單一元素的tuple沒有給定逗號。

class FoodAdmin(admin.ModelAdmin):
    list_display = ('name', 'restaurant', 'price')
    list_filter = ('is_spicy',)
    search_fields = ('name',)
    fields = ('price','restaurant') #這將會使得price欄位出現在restaurant欄位之前,而且name、is_spicy和comment欄位都不會出現,不能被編輯。
    ordering = ('-price',)

列表過濾: 檢視頁面中的右側加入了過濾器,對於is_spicy這個布林資料來說,他可以過濾出is_spicy為True的資料或是is_spicy為False的資料。
搜尋欄位: 在restaurant的檢視畫面上方看到一個搜尋欄位,而此欄位的搜尋將以name欄位為主,使用者們可以同時設定多個欄位。
排序: 設定ordering元組,指定欄位名稱,資料便會依照指定欄位進行排序,加入一個減號可以實現降序排序。
自定義編輯欄位: 當我們點擊了一筆資料之後,便會進入編輯頁面,admin預設開放所有的欄位進行編輯,而順序也依照欄位當初被設置的順序,為了客製化這一點,可以利用fields元組。fields元組的元素也是資料欄位的名稱,其順序就是編輯頁面欄位出現的順序,而沒有出現在fields元組中的欄位,將不出現在編輯頁面中,無法被編輯。這可以有效地防止一些特定的資料無法被手動新增或修改。

Python筆記:Django(4) Model

Model

利用 Django Model 定義資料庫的結構 ( Schema ),並透過 Django 指令創建資料庫、資料表及欄位。

python的模型是ORM(object-relational mapping)的機制,透過操作python的類型與物件就能建立資料表和存取資料。在 Django 中,一個 model 就是一個 class。所有的 Django models 都必須繼承django.db.models.Model。
Store 類別:分別儲存店家名稱與其他資訊。
MenuItem 類別:一個用來存圖片檔案位置,另一個則是圖片標題(用在 HTML alt tag)。MenuItem 有一個指向Store 的 foreign key,叫做 store;這個 foreign key 在 Store 的 reverse attribute 則叫做menu_items。
#stores/models.py

class Store(models.Model):  

    name = models.CharField(max_length=20)  
    notes = models.TextField(blank=True, default='')  

class food(models.Model):  

    store = models.ForeignKey('Store', related_name='food')  
    name = models.CharField(max_length=20)  
    price = models.IntegerField()  
CharField 對應到資料庫的 VARCHAR。max_length 參數代表 VARCHAR 的長度。
TextField 對應到 TEXT。blank=True 代表本欄位可空白(注意不是可為 NULL!可為NULL 的欄位是使用 null=True);default 代表如果你在建立Store 物件時沒有輸入本欄位,預設會使用的值。
DecimalField,支援了浮點數的資料,如果是整數則把decimal_places設為0。
BooleanField真假值的資料
ForeignKey 是 Django 專門用來管理 foreign key 的 model field。
store = models.ForeignKey('Store', related_name='menu_items')
餐廳是一個資料表,但這裡面存在著一個關係,一家餐廳有多種食物,而每個食物都只屬於一家餐廳。這屬於一種Many-to-one的關係(n個food會對應到一家餐廳),這時我們需要使用ForeignKey(外鍵)來描述,這會使得每一個store能夠找到他所屬的所有食物,同樣的每一種Food也可以找到他屬於的餐廳。
現在程式已經可以認得這兩種 models 了。所有的模型都是繼承自django.db.models.Model的class,在之後我們會看到一個模型類別會對應到資料庫中的一張資料表,而實體化自此類別的物件就是資料表中的一筆一筆資料。
Django會把這些model的設定翻譯成各種資料庫的語言,這就好像是使用python對sql等語法做一個包覆(wrapper)而已。
python manage.py makemigrations stores告訴 Django 我們更新了 stores 中的 models。
$ python manage.py makemigrations stores
Migrations for 'stores':
  0001_initial.py:
    - Create model food
    - Create model Store
    - Add field store to food

migration資料檔

下述指令會對指定的應用做migration的檢查,如果模型有任何異動,則會產生新的migration檔,並放置在APP底下的migration資料夾;若不提供參數APP_NAME,則Django會對所有安裝好的APP做migration的檢查。
$ python manage.py makemigrations "APP_NAME"                                
Ex. Django 偵測到剛剛的 0001_initial 尚未與資料庫同步,並成功執行它。0001_initial.py,這代表了資料庫模型的第一版(0001)
$ python manage.py migrate stores
Operations to perform:
  Apply all migrations: stores
Running migrations:
  Rendering model states... DONE
  Applying stores.0001_initial... OK

寫 view,把前面製作的 model 顯示出來。

# Dinbendon/urls.py

from django.conf.urls import patterns, include, url
from django.contrib import admin
from stores.views import home,, store_list, store_detail

urlpatterns = [
     url(r'^$', home, name='home'),
     url(r'^store/$',store_list, name='store_list'),  #新增這行
     url(r'^store/(?P<pk>\d+)/$', store_detail, name='store_detail'), # 新增這行
     url(r'^admin/', include(admin.site.urls)),
     ]
接著是 store_list function。為了把店家列表顯示在這個頁面上要使用 Django 的 ORM query。
stores = Store.objects.all()
其中 Store.objects 會回傳一個 model manager。這個 manager 提供了 all method,回傳一個 query 物件。所以 stores 包含的是一個 query 物件,其中包含一個 SQL 指令,大致等同於下面的格式:
SELECT * FROM "stores";
#stores/views.py

from django.http import Http404 #在找不到對應物件時回應 404 Not Found
from django.shortcuts import render
from .models import Store


def home(request):
    return render(request, 'home.html')


def store_list(request):
    stores = Store.objects.all()
    return render(request, 'store_list.html', {'stores': stores})


def store_detail(request, pk):
    try:
        store = Store.objects.get(pk=pk)
    except Store.DoesNotExist:
        raise Http404
    return render(request, 'store_detail.html', {'store': store})
參考:
http://dokelung-blog.logdown.com/posts/220606-django-notes-5-model-and-database
https://docs.djangoproject.com/en/1.7/ref/models/fields/

2015年7月10日 星期五

Python筆記:Django(3) Views&Template

Views

當 Django 收到一個 HTTP request 時,會先確認該 request 的 URI 應該對應到哪個 view,並把 request 交給它。View 要負責處理這個 request,並回傳一個 HTTP response.

簡單來說在Django 中,每個 view 其實就是一個 function。這個 function 接受一個 request 參數,回傳django.http.HttpResponse 物件。

要完成一個可以回應給使用者的頁面,主要有兩個步驟:

1. 設定urls.py
2. 撰寫view function

設定urls.py

在urls.py 新增一個 URL pattern,讓 Django 知道如何把網址導向至 view 的 function:

from django.conf.urls import patterns, include, url
from django.contrib import admin
from stores.views import home # 從views.py中匯入home這個function

urlpatterns = patterns(
'',
url(r'^$', home, name='home'),   # 加入此行
url(r'^admin/', include(admin.site.urls)),
)

對r’^home/$’ 做個解釋,這是Python中正規表達式的寫法,^號代表配對開始,$號代表配對結束,所以這行是說網域後的字串要”完全”等於/home/才算配對成功,home前面並沒有寫出/,這是因為Django預設會幫你加上這個slash。另外,代表配對結束,使用標準路徑來import

如果寫成url(r'^home/$', home)就是告訴Django,看到網域後面出現/home/就去call views.py裡面的functionhere

撰寫view function

在子目錄stores下面產生一個views.py並完成home這個function.

#stores/views.py
from django.shortcuts import render

def home(request):
    return render(request, 'home.html')

Home function: request是一個有關使用者請求的物件HttpRequest,要這樣想,有求才有應,有問才有答,你的回應一定伴隨著一個要求,所以任何action都把request設為第一個參數吧。第二個參數是 template 的位置。HttpResponse會負責處理 template,產生一個合法的 HTML 檔案,並依此建立 HTTP response。

HttpResponse物件,參數可以是一個字串或一個完整的html.

別忘了要在settings中加入stores這個app. 執行runserver後就會發現原本的畫面變成我們設定的畫面了.如果想輸出中文的話…
Ex.

# -*- coding: utf-8 -*-  #加入此行

from django.http import HttpResponse

def here(request):
    return HttpResponse('我在這!')

Template

Template的概念是預先完成骨架,會預先在上面挖幾個洞(變數),再根據接收到的資料把肉(參數)填上去.關於使用模版的理由,Django Book列出了以下幾點:

  1. Any change to the design of the page requires a change to the Python code. The design of a site tends to change far more frequently than the underlying Python code, so it would be convenient if the design could change without needing to modify the Python code.

  2. Writing Python code and designing HTML are two different disciplines, and most professional Web development environments split these responsibilities between separate people (or even separate departments). Designers and HTML/CSS coders shouldn’t be required to edit Python code to get their job done.

  3. It’s most efficient if programmers can work on Python code and designers can work on templates at the same time, rather than one person waiting for the other to finish editing a single file that contains both Python and HTML.

就是想要將html和python code分開來寫,不但不會混亂還能同時進行。更重要的是,改一邊可以不用動到另一邊。這邊舉一個範例是如果不使用Template的話,想把HTML的內容呈現出來,會寫在views.py裡.
Ex.

# .../views.py

from datetime import datetime
from django.http import HttpResponse


def hello_world(request):
    output = """
        <!DOCTYPE html>
        <html>
            <head>
            </head>
            <body>
                Hello World! <em style="color:LightSeaGreen;">{current_time}</em>
            </body>
        </html>
    """.format(current_time=datetime.now())

    return HttpResponse(output)

創建與填寫Template

實作一樣有兩個步驟

1. 創建Template
2. 填寫Template

一個模版主要由下表所列的元素構成:
enter image description here

Ex.

$ python manage.py shell

>>> from django import template
>>> t = template.Template('I love {{ name }}.')
>>> c = template.Context({'name':'SNSD'})
>>> print t.render(c)
I love SNSD.

name必須在{{}}裡面才會被當成變量。利用Context物件來填寫他,字典的key會對應到相同名稱的變量,而值會成該變量的值,簡單來說就是在模版中看到{{ name }}變量就替喚為字串’SNSD’。

Template物件中的render方法執行的就是填寫的動作,會將Context的鍵找到對應的變量位置並且填入該鍵對應的值。

建立資料夾Template

在stores中新增一個資料夾templates專門放置模版。接著在templates目錄下新增一個檔案home.html,然後我們將模版內容移到home.html中.架構則如下所示.

Dinbendon
├── Dinbendon
│ ├── settings.py
│ ├── __init__.py
│ ├── urls.py
│ └── wsgi.py
├── stores
│ ├── migrations
│ │ └── __init__.py
│ ├── templates
│ │ └──home.html
│ ├── __init__.py
│ ├── admin.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
└── manage.py

建立第一個 Template home

{# stores/templates/home.html #}
<!DOCTYLE html>
<html>
<head>
<meta charset="utf-8">
<title>訂便當</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
</head>

<body>
<nav class="navbar navbar-default navbar-static-top" role="navigation">
<div class="container">
  <div class="navbar-header">
    <a class="navbar-brand" href="{% url 'home' %}">午餐系統</a>
  </div>
</div>
</nav>
</body>
</html>

django.shortcuts.render

Render:產生 HttpResponse 物件。Django的模板系統的基本規則:寫模板,創建template對象,創建context,調用render()方法。

我們 import 了 django.shortcuts.render,這個 function 可以幫助我們讀取 template 之後,把變數以 python dictionary 的方式傳入 template 當中,最後再 render 出來並且回傳到瀏覽器中。
(範例可以參考在上面的”撰寫view function“)

{% url ‘home’ %} 是什麼?

這叫 template tag。因為不能在 template 中寫 Python(all hail PHP!),所以如果你需要在 template 中使用任何邏輯(JavaScript 不算),就必須使用 template tags。

Django 的 template tag 語法是下面這樣:

{% tag_name [ argument ... ] %}

所以上面那個例子中,我們呼叫了 url 這個 tag,並傳入一個參數’home’。這個 tag 會幫你找到名稱為 home 的 URL pattern,並輸出該 pattern 對應的網址。在這裡,輸出的就會是 /。

成果:
enter image description here

參考:
http://dokelung-blog.logdown.com/posts/220315-django-notes-3-templates
http://djangogirlstaipei.gitbooks.io/django-girls-taipei-tutorial/content/django/templates.html

Python筆記:Django(2)建立 Django application

Web Framework

簡單定義是說”開發 Web 應用程式時所用的框架”。
一個既定的程式骨架 – 你必須按照它的規範寫程式,例如把資料庫相關的程式與跟畫面溝通的程式分開,而不是全部寫在同一個檔案。這對於程式的開發速度、再利用性、和程式可讀性等等都有相當大的好處。
強大且豐富的函式庫 ( Libraries ) – 通常會提供一些開發網站所需要且常用的功能,例如使用者認證、安全機制、URL mapping、資料庫連接等等。讓你在開發網站時可以直接使用函式庫,然後專注在客製化自己的功能。

Django簡介

Django使用了類似 MVC 的架構,只是在定義和解釋上略為不同,稱為 MTV ( Model–Template–View ),我們可以透過下面這張圖來了解其運作方式:
  • Models通常是用來與資料庫溝通,與MVC相同。
  • Templates 代表把東西呈現給使用者的媒介。
  • Views 用來處理 models,以將其呈現於 templates 中,或者處理使用者送來的資料(以 HTTP POST等方式),並存入 models。
Django templates 比較像 MVC 的 views,但是比起後者,templates只負責資料呈現,幾乎不包含任何邏輯(除非是用來呈現的邏輯)。Django views 則介於 MVC 的 views 與 controllers 之間。但 MVC 中 controllers 的邏輯不全然包含在 Django views;Django 通常習慣把部分邏輯放在 models,並且提供了一些額外的工具,來簡化 views 需要承擔的責任。但即使如此,Django views 仍然會像 MVC 的 controllers 一樣,負責連結 models、templates、以及 Django 提供的其他工具。
enter image description here
Template: 大部分都是 HTML 的程式碼,只有資料的部份會用特殊的 Django template 格式來取代,當然還有一些控制的機制例如 for 迴圈、if else 判斷等。這樣一來,網頁設計的部份就和資料的處理分離,不論是資料處理或是網頁的部份,程式碼看起來都乾淨許多。
Django運作方式: 主要就是先對照 url,找到適當程式後,進入該程式;接著處理完資料部份後,就將樣板叫出來,並把資料的部份放上去,接著回傳。

Django 環境設定

首先假設我們利用django-admin.py來建置django的專案:
$ django-admin.py startproject mysite
專案結構如下:

settings.py

settings.py是整個專案的主設定檔,檔案中有很多使用大寫的變數.
在settings.py中,對於該專案的基本路徑已經設定好了
 BASE_DIR = os.path.dirname(os.path.dirname(__file__))
這裡的BASE_DIR指的是專案目錄的路徑.
在Python中,_file _ 指的是當下該命令檔的檔名,而使用os.path.dirname(_file _)會找出該檔所在目錄的路徑.即為子目錄mysite,而連續使用兩次得到的路徑(子目錄的目錄)就會是上層mysite.

除錯模式設定

Django中有非常強大的除錯模式,在建置專案時是預設打開的
DEBUG = True
TEMPLATE_DEBUG = True
要記得的事在網站上真正上線時,絕對要將DEBUG關閉.

資料庫設定

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
Django預設是使用 SQLite 3,不過如果你的機器裡有 PostgreSQL、MySQL 或 Oracle,Django 也有官方支援(還有些非官方的模組支援其他的)。因為網站正式部署時也會和你本機用的不同,所以我們同樣要把這段放到 local.py 裡。如果你想用其他資料庫,請參考官方文件(https://docs.djangoproject.com/en/1.7/ref/databases/)。
注意你必須安裝合適的 Python 函式庫:
PostgreSQL:pip install psycopg2
MySQL(或 MariaDB):pip install mysqlclient
Oracle:pip install cx_Oracle

語言與時區

預設設定都是美國時間,如下:
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
我們可以將LANGUAGE_CODE的值改為zh-TW就能將主語言改成中文,並將TIME_ZONE改為Asia/Taipei.
LANGUAGE_CODE = 'zh-TW'
TIME_ZONE = 'Asia/Taipei'

App安裝

settings.py中,INSTALLED_APPS這個元組可以指定想要安裝的app,而預設在settings.py中的那些app都是Django內建的
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
)

ROOT URL配置

ROOT_URLCONF = 'mysite.urls'
預設的檔案就是當前目錄中(下層mysite)的urls.py,這裡的形式是匯入會用到的namespace形式,在這邊urls不加.py.
在資料庫裡建立預設需要的表格:(請 cd 到 manage.py 所在的目錄再執行)
python manage.py migrate

利用 startapp 建立 Django app

$ python manage.py startapp store
建立一個叫 stores 的目錄,用來包裝我們的 app. 。這個 app 主要負責管理店家.
Dinbendon
├──Dinbendon
│ ├── settings.py
│ ├── init.py
│ ├── urls.py
│ └── wsgi.py
├── stores
│ ├── migrations
│ │ └── init.py
│ ├── init.py
│ ├── admin.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
└── manage.py
來看看 stores 裡面各項目的用途:
  • migrations: 用來存放 database migration,也就是資料庫結構改變的資料。這些檔案通常不會直接被執行,而是在你透過Django 指令改變資料庫結構時,用來提示 Django 你的資料在某個時間點的結構。
  • admins.py: 是用來設定 Django admin。
  • models.py: 和 views.py 是用來放 models 和 views 的程式碼。
  • tests.py: 是用來放單元測試。
參考網址:
http://ithelp.ithome.com.tw/question/10157871

2015年7月4日 星期六

Octopress+Github 安裝教學

一開始會想轉到Octopress是因為想試著用看看markdown, 畢竟常常會po一些code上來.使用markdown就能夠有好的排版,而且Octopress是使用git來控制的.Octopress是使用Ruby架構的,另外Python的話可以考慮Pelican或只是Nikola, Node.JS則有台灣的Hexo. 考慮了之後覺得這Blog對我來說比較像是筆記,主要是紀錄而已不想弄得太複雜後來還是決定繼續使用Blogger.

環境設定

$ ruby -e "$(curl -fsSL https://rawgithubusercontent.con/Hombrew/install/master/install)" //安裝homebrew
$ curl -L https://get.rvm.io | bash -s stable --ruby //使用RVM安裝Ruby
$ ruby --version //2.0.0
安裝
$ cd Blog //mkdir Blog在你要的位置.
$ git clone git://github.com/imathis/octopress.git
如果沒問題的話接著
$ cd octopress
$ gem install bundler
$ bundle install
$ rake install
$ rake preview
enter image description here
就會在你本機開一個port 4000的web server起來,開瀏覽器起來輸入http://127.0.0.1:4000/可以看到畫面如下:
enter image description here

將 Octopress 發布到 Github Pages

在Github中建立一個新的repository如下,在Repository name中輸入Username.github.io,輸入完選Create repository.會得到一串網址.
enter image description here
接著輸入
$ rake setup_github_pages
輸入自己的Github Pages repository url,像我的就是:https://github.com/DatouHsu/DatouHsu.github.io.git。按下enter.

寫文章:

$ rake new_post[How-to-install-octopress] //每篇文章就是一個markdown檔,需要放在source/_posts底下.
mkdir -p source/_posts
Creating new post: source/_posts/2015-07-03-how-to-install-octopress.markdown
寫好了之後
把markdown轉成靜態html檔案了:
$ rake generate
$ rake deploy //發佈到github

//向github提交更新
$ git add .
$ git commit -m 'first commit'
$ git push origin source
enter image description here
參考網址:
http://shengmingzhiqing.com/blog/setup-octopress-with-github-pages.html/
http://blog.eddie.com.tw/2011/10/11/how-to-install-octopress-on-heroku/

2015年7月1日 星期三

Python筆記:Django(1)

安裝:

我是在Raspberry Pi上安裝Django,安裝步驟如下
0. pip安裝
如果要使用python3的話, python3.4.3 因為不是系統預設的python 所以安裝django 需要使用 pip3的協助。安裝pip:# sudo python3.4 get-pip.py



$ wget https://bootstrap.pypa.io/get-pip.py //下載get-pip.py,如果是用Mac請使用"curl -O [URL]"安裝
$ sudo python get-pip.py //pip會將套件安裝於/usr/local/... 所以安裝時需要sudo
$ pip install -U pip //更新
1. 安裝前先更新apt-get, 另外我們會使用到Python 3.4之後的版本,所以在這邊一併更新.



$sudo apt-get update
$sudo apt-get upgrade
//從網路上抓python3.4.3下來,參考https://www.python.org
$ wget https://www.python.org/ftp/python/3.4.3/Python-3.4.3.tgz
$ tar xvzf Python-3.4.2.tgz //解壓縮
$ cd Python-3.4.2/ && ./configure && make && sudo make install
//進資料夾,進行configure,make最後在install (這可能會花點時間)
$ rm 資料夾/檔案
2. 安裝Django



$ mkdir Dinbendon //建立資料夾
$ cd Dinbendon
$ python3 -m venv venv/Dinbendon

$ source venv/Dinbendon/bin/activate //進入虛擬環境 離開:$ deactivate
//如果要在虛擬機器中執行Django話 一定要先進入Venv在安裝Django不然會一直跳Error
$ pip install Django==1.8.3 //可直接進行這行

建立Django專案




$ django-admin startproject Dinbendon
執行完之後資料夾大概如下所示,第二個 Dinbendon 是由 django-admin 指令建立的.所有專案相關的東西都應該要在這個目錄裡面;如果你未來想要把這個專案放進版本控制系統,這應該就是專案的根目錄。
Dinbendon
├── Dinbendon
│   ├── Dinbendon
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   └── manage.py
└── venv
        └── [裡面是虛擬環境,略]

1. __init__.py:Python 用來標示某個目錄是 module 的檔案。lunch 裡面有這個檔案,就代表 lunch 本身是個合法的 Python module,其他程式可以用 import 把它載入。所有的全域變數都是用大寫與底線構成。這是 Django 設定的命名慣例。

2. settings.py:這個檔案是用來存放 Dinbendon 這個專案的設定。Django 的設定檔其實就是一個 Python 檔,裡面的變數會被當作設定值。除了你現在在 settings.py 裡看得到的內容外,Django 其實還有很多預設值。完整的 Django 設定列表可以在官網文件找到;如果某個設定值在設定檔裡沒有,則會使用內建的預設值。Django 在很多地方都提供了合理的預設值,所以在設定檔裡需要修改的項目並不多。我們之後會回來處理必要的設定。

3. urls.py:當伺服器收到網路要求時,要求裡面會有一個路徑資訊,也就是你在使用瀏覽器時看到的那個網址。這個檔案的內容是用來告訴 Django,當它收到某個(或某些)路徑的要求時,應該要呼叫哪個函式來處理。我們之後會再回來詳細討論路徑,以及 Django 怎麼把它對應到函式。

4. wsgi.py:這個檔案就是讓你的 Django 專案變成 WSGI 應用程式的關鍵。當 WSGI 伺服器收到請求時,就會執行這個檔案,以獲得一個 WSGI 應用程式。

Django Command:

manage.py 是 Django 提供的命令列工具,我們可以利用它執行很多工作,例如同步資料庫、建立 app 等等,指令的使用方式如下:



$ python manage.py <command> [options]

重點整理:

  1. __init__.py 用來告訴Python這個資料夾是一個模組,裡面通常是空的,不過也可以寫一些程式碼在裡面。
  2. manage.py 用來操作整個Django專案的小工具,例如啟動伺服器python manage.py runserver,或是同步資料庫python manage.py syncdb
  3. settings.py 設定檔
  4. urls.py 負責網站的路由。

啟動開發伺服器 -- runserver




$ python manage.py migrate //如果發生錯誤請先執行此行.
//在虛擬環境中不能執行的話,改成python2.7 manage.py migrate

$ python manage.py runserver //執行結果如下.
//如果想指定port,可執行
python manage.py runserver <port> //指定Raspberry PI的IP,沒指定IP的話預設為http://127.0.0.1:8000/



參考資料:
http://ithelp.ithome.com.tw/question/10157423
http://dokelung-blog.logdown.com/posts/220274-django-note-1-building-and-settings
https://docs.djangoproject.com/en/1.8/intro/tutorial01/
http://segmentfault.com/q/1010000000330200
https://www.djangoproject.com/download/
http://hugo-python3.blogspot.tw/2014/01/python-33-django-161.html