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

沒有留言:

張貼留言