Django的Generic View是非常強大而具有彈性的功能,
基本上如果應用簡單的話,
妳甚至可以不用在views.py寫任何一行程式碼,
只單單在URLconf (urls.py)進行網址改寫便可以實作出你的view,
這一點, 在Django Tutorial Part4已有詳細的說明.
不過其實撰寫Python程式碼向來不會是什麼苦差事,
所以我們真正通常關心的是要如何擴充並在view裡使用Generic View的功能.
以下我就用分頁功能來做個說明:
先假設底下這段是我們原本的view:
@login_required
def stb_list_template_view(request):
stb_list = Stb.objects.filter(stbSubGroupNum__pGroup=request.session["pGroup"])
return render_to_response('stb_list.html',{'stb_list': stb_list,})
這是一段非常標準的未使用Generic View的處理方法,
我們從Stb中取出屬於pgroup的stb_list資料,
並將之傳送到stb_list.html這個template裡. 來看看我們怎麼對這段程式碼改寫,
@login_required
def stb_list_template_view(request):
from django.views.generic import list_detail
return list_detail.object_list(
request,
queryset = Stb.objects.filter(stbSubGroupNum__pGroup=request.seession["pGroup"]),
template_object_name = "stb",
template_name = "stblist.html",
allow_empty = True,
)
疑!? 怎麼程式碼看起來更冗長了?
別急別急, 這是因為我們原先的template並沒有使用到generic views規劃的預設名稱,
否則template_object_name跟template_name這兩個參數是可以省略的,
不過別忘了python的哲學就是Explict is better than implicit,
寫長一點對於其他對generic view似懂非懂的人更好維護.
此外, 如果你原先沒有使用generic view的想法,
也可利用這兩個參數對你原有的template作最小幅度的修改.
好了, 我們還沒有做到我們原先說要作的功能, 就是替這個Stb資料列表作分頁,
那要怎麼做呢? 啊, generic view已經幫我們想好了!
請加上粗體的這行:
@login_required
def stb_list_template_view(request):
from django.views.generic import list_detail
return list_detail.object_list(
request,
paginate_by = 10, queryset = Stb.objects.filter(stbSubGroupNum__pGroup=request.seession["pGroup"]),
template_object_name = "stb",
template_name = "stblist.html",
allow_empty = True,
)
paginate_by = 10 這行表示每十筆資料分作一頁,
這樣就完成了! django的generic view會自動幫我們在每一個template裡面加入分頁所需的參數,
以下就是說明: (以下傳入參數的說明直接來自
Django官方generic view說明文件)
* results_per_page: The number of objects per page. (Same as the paginate_by parameter.)
* has_next: A boolean representing whether there's a next page.
* has_previous: A boolean representing whether there's a previous page.
* page: The current page number, as an integer. This is 1-based.
* next: The next page number, as an integer. If there's no next page, this will still be an integer representing the theoretical next-page number. This is 1-based.
* previous: The previous page number, as an integer. This is 1-based.
* pages: The total number of pages, as an integer.
* hits: The total number of objects across all pages, not just this page.
你可以自行在template編排並使用這些參數來作出你想要的分頁樣式.
(是的, 這項是可以交給前端Web Designer作的工作,
不過如果案子小或有不可抗力因素, 你可以自己動手作)
而你也可透過修改Urlconf或直接使用網址的get參數來做修改,
例如: http://yourdomain.com/obj_list/?page=3
便可觀看第三頁的內容. 這些在Django的
Generic View說明文件裡面都有解釋.
可是可是, 我們還想達到更強的功能, 那要怎麼做呢?
比如說, 我們希望在某分頁找不到時, 自動導向到沒有分頁的模式,
另外我們還想自己改變錯誤訊息(而非預設的404)的網頁,等等等等...
做得到嗎???
原始的generic view是做不到的,但是一切都是Python,我們只要進行改寫就可以了.
底下列出一段我應用在真實專案上的程式碼(略有修改):
@login_required
def stb_list_template_view(request):
#customize the paginate num
if 'paginate_by' in request.GET.keys():
paginate_by = int(request.GET.get('paginate_by', 1))
request.session['paginate_by'] = paginate_by
elif 'paginate_by' in request.session:
paginate_by = request.session['paginate_by']
else:
#default behavior
#you can turn off via set paginate_by = False
paginate_by = 10
queryset = Stb.objects.filter(stbSubGroupNum__pGroup=request.session["pGroup"])
from django.views.generic import list_detail
from django.core.paginator import ObjectPaginator, InvalidPage
try:
paginator = ObjectPaginator(queryset, paginate_by)
page = int(request.GET.get('page', 1))
object_list = paginator.get_page(page - 1)
except (InvalidPage, ValueError):
paginate_by = False
except:
problem = "page 404 problem!\n"+"\n".join(map(str,sys.exc_info()))
return HttpResponse(problem)
return list_detail.object_list(
request,
paginate_by = paginate_by,
queryset = queryset,
template_object_name = "stb", # default is object, context will
template_name = "stblist.html", # default name is Stb_list.html
allow_empty = True,
extra_context = {
'serverstat' : serverstat,
'session' : request.session,
})
這是Django的好處, 魔法很少, 一切都是我們熟知的Python.
只要我們需要, 隨時可以再花點精神擴充.
B-list上有一篇
延伸閱讀文章, 可以一起讀一讀.