Python Django CBV下的通用视图函数
ListView
TemplateView
DetailView
?
之前的代碼實例基本上都是基于FBV的模式來撰寫的,好處么,當然就是簡單粗暴。。正如:
def index(request):return HttpResponse('hello world')上面的寫法,基本接觸不到視圖函數里面的通用視圖。只是在介紹CBV的時候稍微介紹了下引用,大概用法。
?
導入
之前的導入一直用的是
from django.views import View這里從view下鉆一下會發現:
from django.views.generic.base import View__all__ = ['View']對頭、view視圖函數基本都來自于generic里面,此篇blog具體講述的內容也是generic內部的幾個通用視圖:ListView、DetailView、TemplateView。
?
?
View
基礎類視圖:
from django.http import HttpResponse from django.views import Viewclass MyView(View):def get(self, request):return HttpResponse('ok') urlpatterns = [path('index/',views.MyView.as_view(), name='index'), ]as_view()方法會返回一個函數來處理請求和響應,還可以將類視圖中定義的屬性作為該方法參數,覆蓋類視圖中的屬性值。?
?
基本視圖
基本視圖包括三類:View、TemplateView和RedirectView。用戶可繼承基本類視圖來定義視圖,所有的通用視圖也都繼承與這三類基本視圖實現,因此相比于通用視圖,基本視圖提供的功能較少。
View
View是所有類視圖的父類,可以直接從from django.views中導入,如:
from django.views import Viewclass MyView(View):def get(self,request):passhttp請求的方法
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']as_view():該方法是一個類方法,被@classonlymethod修飾,是http請求和響應的入口,用于url配置。在Http請求和響應的過程中,會將request對象和其他參數作為參數傳入該方法,內部調用dispatch()方法后返回一個Response對象。
?
TemplateView
繼承結構:
class TemplateView(TemplateResponseMixin, ContextMixin, View):TemplateView視圖通過給定的模板進行渲染。
實例
class StudentDetailTemplate(TemplateView): # 繼承TemplateViewtemplate_name = 'student_template.html' # 模版名稱def get_context_data(self, **kwargs):context = super().get_context_data(**kwargs) # 繼承父類里面的get_context_data,返回上下文數據context['name'] = 'dandy' # 添加新的數據context['data'] = {'age': 18, # 添加新的字典'flag': 'aaa'}context['data1'] = models.Student.objects.all() # 添加新的querysetreturn context # 返回更新過的上下文文數據url:
path('templateview/', views.StudentDetailTemplate.as_view(), name='student_template'),?
其他為涉及到的屬性或方法:
get_template_names()
除了使用template_name指定模板文件,也可通過該方法指定模板文件:
def get_template_names(self):return "student_template.html"extra_content
除了在get_context_data()中添加上下文信息外,也可以在url配置時在as_view()方法中指定extra_context屬性來添加上下文信息,如:
path('templateview/', views.StudentDetailTemplate.as_view(extra_context={"extra": "。。。。"}), name='student_template'),CBV正常是需要在下面定義一個get或之類的方法,用來匹配method,但是此處是不需要的,因為查看TemplateView內部時會發現:
class TemplateView(TemplateResponseMixin, ContextMixin, View):"""Render a template. Pass keyword arguments from the URLconf to the context."""def get(self, request, *args, **kwargs):context = self.get_context_data(**kwargs)return self.render_to_response(context)內部已經寫好了這個get方法,一方面TemplateView的基礎需求其實就是返回模版給瀏覽器的。當然了,因為繼承了TemplateView,這里還是可以重寫這個get方法,進行自定義數據。
def get(self, request, *args, **kwargs):context = self.get_context_data(**kwargs)context['end'] = 'ending'new_data ={'a': 'b'}context.update(new_data)return self.render_to_response(context)?
RedirectView
用來進行跳轉, 默認是永久重定向(301),可以直接在urls.py中使用,非常方便:
path('', views.IndexPage.as_view(), name='baidu'), class ArticleCounterRedirectView(RedirectView):url = ' # 要跳轉的網址,# url 可以不給,用 pattern_name 和 get_redirect_url() 函數 來解析到要跳轉的網址 permanent = False #是否為永久重定向, 默認為 Falsequery_string = True # 是否傳遞GET的參數到跳轉網址,True時會傳遞,默認為 Falsepattern_name = 'article-detail' # 用來跳轉的 URL, 看下面的 get_redirect_url() 函數# 如果url沒有設定,此函數就會嘗試用pattern_name和從網址中捕捉的參數來獲取對應網址# 即 reverse(pattern_name, args) 得到相應的網址,def get_redirect_url(self, *args, **kwargs):article = get_object_or_404(Article, pk=kwargs['pk'])article.update_counter() # 更新文章點擊數,在models.py中實現return super(ArticleCounterRedirectView, self).get_redirect_url(*args, **kwargs)RedirectView源碼:
class RedirectView(View):"""Provide a redirect on any GET request."""permanent = Falseurl = Nonepattern_name = Nonequery_string = Falsedef get_redirect_url(self, *args, **kwargs):"""Return the URL redirect to. Keyword arguments from the URL patternmatch generating the redirect request are provided as kwargs to thismethod."""if self.url:url = self.url % kwargselif self.pattern_name:url = reverse(self.pattern_name, args=args, kwargs=kwargs)else:return Noneargs = self.request.META.get('QUERY_STRING', '')if args and self.query_string:url = "%s?%s" % (url, args)return urldef get(self, request, *args, **kwargs):url = self.get_redirect_url(*args, **kwargs)if url:if self.permanent:return HttpResponsePermanentRedirect(url)else:return HttpResponseRedirect(url)else:logger.warning('Gone: %s', request.path,extra={'status_code': 410, 'request': request})return HttpResponseGone()def head(self, request, *args, **kwargs):return self.get(request, *args, **kwargs)def post(self, request, *args, **kwargs):return self.get(request, *args, **kwargs)def options(self, request, *args, **kwargs):return self.get(request, *args, **kwargs)def delete(self, request, *args, **kwargs):return self.get(request, *args, **kwargs)def put(self, request, *args, **kwargs):return self.get(request, *args, **kwargs)def patch(self, request, *args, **kwargs):return self.get(request, *args, **kwargs) View Code看完應該就會一目了然。
path('', RedirectView.as_view(pattern_name='backend:index')),?
?
通用顯示視圖
ListView
繼承關系:
?
ListView,用于顯示一個對象列表的視圖,包含一個屬性值object_list,表示對象的列表。因此在模板文件中可以通過遍歷該屬性來顯示model的所有數據。
class StudentList(ListView):model = models.Student # orm的modeltemplate_name = 'student_list.html' # 要返回的模版文件context_object_name = 'student_obj' # orm數據實例化對象,前端調用的名稱extra_context = {'name': 'dandy'} # 額外的上下文數據信息def get(self, request, *args, **kwargs): # 重寫get方法response = super().get(request, *args, **kwargs)return responsedef get_context_data(self, *, object_list=None, **kwargs): # 重寫get_context_data方法context = super().get_context_data(**kwargs) # 拿到返回值context并更新或者擴充context['num'] = 11return contextdef get_queryset(self):# query_set = super().get_queryset()# query_set = super().get_queryset()[:1]self.kwargs['name'] = 'dandy'cate = get_object_or_404(models.Student, name=self.kwargs.get('name'))return super().get_queryset().filter(name=cate)上面有一個參數沒有設計到:
queryset = Student.objects.filter(name='zhangsan')該屬性表示該視圖顯示項的集合,可以通過get_queryset()方法來進行定義。
所以上面的這一句篩選跟上面的get_queryset自定義的篩選,其實差不多。
context_object_name
在模板中使用object_list是一個不太友好的方法,因為不知道object_list具體指的是哪個模板的數據,因此在通用視圖中還提供了一個屬性:context_object_name來制定一個上下文,如:
class showStu(ListView):...context_object_name = "student"看一下模版內:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body><h3>{{ name }}</h3><table><thead><td>姓名</td><td>年齡</td></thead><tbody>{% for student in student_obj %}<tr><td>{{ student.name }}</td><td>{{ student.age }}</td></tr>{% endfor %}</tbody></table><br><h2>{{ num }}</h2> </body> </html> View Code?
?
DetailView
繼承關系:
?
DetailView用于顯示一個特定類型對象的詳細信息。DetailView的大部分屬性和方法和ListView相同。不同的是該視圖沒有object_list屬性,因為該視圖負責顯示一個特定對象的詳細信息,因此有一個object屬性,表示model的一個對象(或一條記錄)。
class StudentDetailView(DetailView):model = models.Student # orm的modeltemplate_name = 'student_detail.html' # 調用的模版文件context_object_name = 'aaa' # 模版文件里面對應的orm數據對象的名稱def get(self, request, *args, **kwargs):response = super().get(request, *args, **kwargs) # 同樣的重寫的方法可以做一些自定義,比如訪問量+1等等的return responsedef get_object(self):obj = super().get_object()return obj # 這里的obj其實已經是指向一條數據了;比如一篇文章,可以進行一些修改之類的操作,obj.aa = 'dandy', obj.save()def get_context_data(self, **kwargs):context = super().get_context_data(**kwargs) # 重寫,獲取返回數據classes = self.object.classes_set.all() # 反向獲取所有關聯數據context.update({ # 添加新的上下文信息'classes': classes,'test_name': 'dandy'})return context這里需要注意的是url,因為明確表面了這個通用視圖的目的,所以url固定的指向了某個具體的事物的id
path('detailview/<int:pk>/', views.StudentDetailView.as_view(), name='student_detail'),?
內部形成處理。
默認情況下,DetailView 使用<appname>/<model name>_detail.html的模板,如果沒有該模板,則應該通過”template_name”指定一個模板。
?
轉載于:https://www.cnblogs.com/wuzdandz/p/9448310.html
總結
以上是生活随笔為你收集整理的Python Django CBV下的通用视图函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: postgresql安装指南
- 下一篇: 图论:Dinic算法