
## 類視圖
在寫視圖的時候,Django除了使用函數作為視圖,也可以使用類作為視圖。使用類視圖可以使用類的一些特性,比如繼承等。
### View
django.views.generic.base.View是主要的類視圖,所有的類視圖都是繼承自他。如果我們寫自己的類視圖,也可以繼承自他。然后再根據當前請求的method,來實現不同的方法。比如這個視圖只能使用get的方式來請求,那么就可以在這個類中定義get(self,request,*args,**kwargs)方法。以此類推,如果只需要實現post方法,那么就只需要在類中實現post(self,request,*args,**kwargs)。
```
from django.views import View
class BookDetailView(View):
def get(self,request,*args,**kwargs):
return render(request,'detail.html')
```
類視圖寫完后,還應該在urls.py中進行映射,映射的時候就需要調用View的類方法as_view()來進行轉換。自動查找指定方法。
```
urlpatterns = [
path("detail/<book_id>/",views.BookDetailView.as_view(),name='detail')
]
```
除了get方法,View還支持以下方法['get','post','put','patch','delete','head','options','trace']。
如果用戶訪問了View中沒有定義的方法。比如你的類視圖只支持get方法,而出現了post方法,那么就會把這個請求轉發給http_method_not_allowed(request,*args,**kwargs)。
```
class AddBookView(View):
def post(self,request,*args,**kwargs):
return HttpResponse("書籍添加成功!")
def http_method_not_allowed(self, request, *args, **kwargs):
return HttpResponse("您當前采用的method是:%s,本視圖只支持使用post請求!" % request.method)
```
urls.py中的映射如下
```
path("addbook/",views.AddBookView.as_view(),name='add_book')
```
### TemplateView
django.views.generic.base.TemplateView,這個類視圖是專門用來返回模版的。在這個類中,有兩個屬性是經常需要用到的,一個是template_name,這個屬性是用來存儲模版的路徑,TemplateView會自動的渲染這個變量指向的模版。另外一個是get_context_data,這個方法是用來返回上下文數據的,也就是在給模版傳的參數的。
```
from django.views.generic.base import TemplateView
class HomePageView(TemplateView):
template_name = "home.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['username'] = "juran"
return context
```
在urls.py中的映射代碼如下
```
from django.urls import path
from myapp.views import HomePageView
urlpatterns = [
path('', HomePageView.as_view(), name='home'),
]
```
如果在模版中不需要傳遞任何參數,那么可以直接只在urls.py中使用TemplateView來渲染模版。
```
from django.urls import path
from django.views.generic import TemplateView
urlpatterns = [
path('about/', TemplateView.as_view(template_name="about.html")),
]
```
### ListView
在網站開發中,經常會出現需要列出某個表中的一些數據作為列表展示出來。比如文章列表,圖書列表等等。在Django中可以使用ListView來幫我們快速實現這種需求。
```
class ArticleListView(ListView):
model = Article
template_name = 'article_list.html'
paginate_by = 10
context_object_name = 'articles'
ordering = 'create_time'
page_kwarg = 'page'
def get_context_data(self, **kwargs):
context = super(ArticleListView, self).get_context_data(**kwargs)
print(context)
return context
def get_queryset(self):
return Article.objects.filter(id__lte=89)
```
對以上代碼進行解釋:
<ol>
<li>首先<code>ArticleListView</code>是繼承自<code>ListView</code>。 </li>
<li><code>model</code>:重寫<code>model</code>類屬性,指定這個列表是給哪個模型的。 </li>
<li><code>template_name</code>:指定這個列表的模板。 </li>
<li><code>paginate_by</code>:指定這個列表一頁中展示多少條數據。 </li>
<li><code>context_object_name</code>:指定這個列表模型在模板中的參數名稱。 </li>
<li><code>ordering</code>:指定這個列表的排序方式。 </li>
<li><code>page_kwarg</code>:獲取第幾頁的數據的參數名稱。默認是<code>page</code>。</li>
<li><code>get_context_data</code>:獲取上下文的數據。 </li>
<li><code>get_queryset</code>:如果你提取數據的時候,并不是要把所有數據都返回,那么你可以重寫這個方法。將一些不需要展示的數據給過濾掉。</li>
</ol>
### Paginator和Page類
Paginator和Page類都是用來做分頁的。他們在Django中的路徑為django.core.paginator.Paginator和django.core.paginator.Page。以下對這兩個類的常用屬性和方法做解釋:
### Paginator常用屬性和方法
```
count:總共有多少條數據。
num_pages:總共有多少頁。
page_range:頁面的區間。比如有三頁,那么就range(1,4)。
```
### Page常用屬性和方法
```
has_next:是否還有下一頁。
has_previous:是否還有上一頁。
next_page_number:下一頁的頁碼。
previous_page_number:上一頁的頁碼。
number:當前頁。
start_index:當前這一頁的第一條數據的索引值。
end_index:當前這一頁的最后一條數據的索引值。
```
**示例分頁代碼**
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<ul>
{% for i in articles %}
<li>{{ i.id }}-{{ i.name }}</li>
{% endfor %}
</ul>
<ul class="pagination">
{% if page_obj.has_previous %}
<li>
<a href="{% url 'list' %}?page={{ page_obj.previous_page_number }}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% else %}
<li class="disabled">
<a href="javascript:void(0)" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<li class="active"><a href="{% url 'list' %}?page={{ i }}">{{ i }}</a></li>
{% else %}
<li><a href="{% url 'list' %}?page={{ i }}">{{ i }}</a></li>
{% endif %}
{% endfor %}
<!--<li><a href="#">2</a></li>-->
<!--<li><a href="#">3</a></li>-->
<!--<li><a href="#">4</a></li>-->
<!--<li><a href="#">5</a></li>-->
{% if page_obj.has_next %}
<li>
<a href="{% url 'list' %}?page={{ page_obj.next_page_number }}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% else %}
<li class="disabled">
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% endif %}
</ul>
</body>
</html>
```
### 通用分頁代碼
**article1.html**
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<ul>
{% for i in articles %}
<li>{{ i.id }}-{{ i.name }}</li>
{% endfor %}
</ul>
<ul class="pagination">
{% if page_obj.has_previous %}
<li>
<a href="{% url 'list' %}?page={{ page_obj.previous_page_number }}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% else %}
<li class="disabled">
<a href="javascript:void(0)" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% endif %}
{% if left_has_more %}
<li><a href="{% url 'list' %}?page=1">1</a></li>
<li><a href="javascript:void(0)">...</a></li>
{% endif %}
{% for i in left_range %}
<li><a href="{% url 'list' %}?page={{ i }}">{{ i }}</a></li>
{% endfor %}
<li><a href="">{{ page_obj.number }}</a></li>
{% for i in right_range %}
<li><a href="{% url 'list' %}?page={{ i }}">{{ i }}</a></li>
{% endfor %}
{% if right_has_more %}
<li><a href="javascript:void(0)">...</a></li>
<li><a href="{% url 'list' %}?page={{ paginator.num_pages }}">{{ paginator.num_pages }}</a></li>
{% endif %}
{% if page_obj.has_next %}
<li>
<a href="{% url 'list' %}?page={{ page_obj.next_page_number }}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% else %}
<li class="disabled">
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% endif %}
</ul>
</body>
</html>
```
**views.py**
```
class ArticleListVies(ListView):
model = Publisher
template_name = 'article_list1.html'
paginate_by = 5
context_object_name = 'articles'
# ordering = 'create_time'
page_kwarg = 'page'
def get_context_data(self, *, object_list=None, **kwargs):
context = super(ArticleListVies, self).get_context_data(**kwargs)
paginator = context.get("paginator")
page_obj = context.get("page_obj")
# print(paginator.count)
# print(page_obj.has_next())
paginator_date = self.get_page(paginator,page_obj)
context.update(paginator_date)
return context
def get_page(self,paginator,page_obj,page_offset=2):
current_page = page_obj.number
left_has_more = False
right_has_more = False
# 3 4 5 6 7
if current_page <= page_offset + 2:
left_range = range(1,current_page)
else:
left_has_more = True
left_range = range(current_page-page_offset,current_page)
# 7 10
if current_page >= paginator.num_pages - page_offset - 1:
right_range = range(current_page+1, paginator.num_pages+1)
else:
right_has_more = True
right_range = range(current_page+1,current_page+page_offset+1)
return {
'left_range':left_range,
'right_range':right_range,
'right_has_more':right_has_more,
'left_has_more':left_has_more
}
```
- 空白目錄
- 1-Django前導知識
- 1-1-虛擬環境
- 1-2-Django框架介紹與環境搭建
- 2-URL與視圖
- 2-1-URL與視圖
- 3-模板
- 3-1-模板介紹
- 3-2-模板變量
- 3-3-常用標簽
- 3-4-模板常用過濾器
- 3-5-模板結構優化
- 3-6-加載靜態文件
- 4-數據庫
- 4-1-操作數據庫
- 4-2-圖書管理系統
- 4-3-ORM模型介紹
- 4-4-ORM模型的增刪改查
- 4-5-模型常用屬性
- 4-6-外鍵和表
- 4-7-查詢操作
- 4-8-QuerySet的方法
- 4-9-ORM模型練習
- 4-10-ORM模型遷移
- 5-視圖高級
- 1-Django限制請求method
- 2-頁面重定向
- 3-HttpRequest對象
- 4-HttpResponse對象
- 5-類視圖
- 6-錯誤處理
- 6-表單
- 1-用表單驗證數據
- 2-ModelForm
- 3-文件上傳
- 7-session和cookie
- 1-session和cookie
- 8-memcached
- 1-memcached
- 9-阿里云部署
- 阿里云部署