django.views.generic.base.View
是主要的类视图,所有的类视图都是继承自他。如果我们写自己的类视图,也可以继承自他。然后再根据当前请求的method,来实现不同的方法。
例如:这个视图只允许get请求方式,那么就可以在这个类中定义get(self,request,*args,**kwargs)
方法。
from django.http import HttpResponse
from django.views.generic import View
class InfoListView(View):
def get(self, request, *args, **kwargs):
return HttpResponse('Info list View')
当要访问这个类视图时便只能用get
请求方式来访问了。
除了get
,post
方法,View还支持一下方法
['get','post','put','patch','delete','head','options','trace']
如果用户访问了View中没有定义的方法。如你的类视图支持get方法,却出现了post请求,那么View会吧这个请求转发给http_method_not_allowed
.
栗子:
class InfoDetaialView(View):
def post(self, request, id_card):
return HttpResponse('编号%s的信息' % id_card)
def http_method_not_allowed(self, request, *args, **kwargs):
return HttpResponse("当前使用的是%s请求,但是不支持此请求" % request.method)
当用户以post以外的请求方式请求时,就会返回http_method_not_allowed
方法中返回的东西。
其实不管是get
请求还是post
请求,都会走django.views.generic.base.View
中dispatch(request,*args,**kwargs)
方法,所以如果实现这个方法,将能够对所有请求都处理到。
django.views.generic.base.TemplateView
,这个类视图是专门用来返回模版的。在这个类中,有两个属性是经常需要用到的,一个是template_name
,这个属性是用来存储模版的路径,TemplateView
会自动的渲染这个变量指向的模版。另外一个是get_context_data
,这个方法是用来返回上下文数据的,也就是在给模版传的参数的
栗子:
新建一个aboutMe.html
的文件,
<body>
This is about me page.
</body>
然后直接在urls中渲染这个模板:
from django.views.generic import TemplateView
# 如果渲染的模板不需要传递任何参数,那么建议在urls中使用TemplateView直接进行渲染
path('about/',TemplateView.as_view(template_name='aboutMe.html')),
而我们又想使用这个TemplateView进行渲染模板,又想传递少许参数,这个时候我们就可以定义一个类,继承至TemplateView
在views.py
中新建一个类继承至TemplateView
from django.views.generic import TemplateView
class AboutMeView(TemplateView):
template_name = 'aboutMe.html'
def get_context_data(self, *args, **kwargs):
context = super(AboutMeView, self).get_context_data()
context.update({
'name': 'AugustRush',
'age': '18',
})
我们也需要在aboutMe.html
文件中接收传入的数据
<body>
这是关于我们的页面
name = {{ name }}
age = {{ age }}
</body>
然后将上面的映射注释掉,添加新的映射
path('about/',views.AboutView.as_view()),
这里我们就传递了两个参数name
和age
过去。
在网站开发中,经常会出现需要列出某个表中的一些数据作为列表展示出来。比如文章列表,图书列表等等。在Django中可以使用ListView来帮我们快速实现这种需求。
栗子:
首先添加url映射
path('list/',views.InfoListView.as_view()),
然后我们新建一个list.html
的文件,写入代码:
<ul>
{% for article in articles %}
<li>{{ article.title }}</li>
{% endfor %}
</ul>
接下来我们新建一个类视图:
class InfoListView(ListView):
model = models.Article # 重写model类属性,指定模型的列表
template_name = 'list.html' # 指定这个列表的模板。
context_object_name = 'articles' # 指定这个列表模型在模板中的参数名称。
paginate_by = 10 # 每一页需要展示多少条数据
ordering = 'create_time' # 以时间进行排序展示
输入网址,就能查看效果了,并且当前页面只有10条数据。
而如果我们向访问后面的页面,我们只需要在输入的网址后面以GET的方式添加一个page=x
的参数就行了
例如:我们的网址是
http://127.0.0.1:8000/list/
那么我想访问第二页,我就应该这样输入网址
http://127.0.0.1:8000/list/?page=2
以此类推,后面的也是一样的了,因为我们只添加了101条数据,所以只有11页,而我们如果让page=12的话,就会找不到页面。如果我们在网址后面没有传递page参数,默认返回的就是第一页。
而如果我们不想使用page
作为参数,而是换一个p
作为参数,那么就可以使用page_kwarg
这个属性了
示例:将默认参数page
改为p
class InfoListView(ListView):
model = models.Article # 重写model类属性,指定模型的列表
template_name = 'article_list.html' # 指定这个列表的模板。
context_object_name = 'articles' # 指定这个列表模型在模板中的参数名称。
paginate_by = 10 # 每一页需要展示多少条数据
ordering = 'create_time' # 以时间进行排序展示
page_kwarg = 'p' # 指定换页面的参数 默认为page 以GET的方式传递参数
这样,我们就不能使用page作为参数了,而是只能使用p作为参数了。
还有2个比较常用的方法get_context_data
和get_queryset
get_context_data
:获取上下文的数据。并且可以添加自己的参数,例如下面的username在上面定义的类中添加这个方法class InfoListView(ListView):
model = models.Article # 重写model类属性,指定模型的列表
template_name = 'article_list.html' # 指定这个列表的模板。
context_object_name = 'articles' # 指定这个列表模型在模板中的参数名称。
paginate_by = 10 # 每一页需要展示多少条数据
ordering = 'create_time' # 以时间进行排序展示
page_kwarg = 'p' # 指定换页面的参数 默认为page 以GET的方式传递参数
# 重写父类的get_context_data方法,添加自己的参数
def get_context_data(self,**kwargs):
# 我们需要先继承至父模板的get_context_data方法,否则我们有很多方法将不能使用
context = super(InfoListView,self).get_context_data(**kwargs)
# 然后添加自定义的参数
context['username'] = 'augustrush'
print(context)
return context
我们就能在控制台看到打印出来的东西了。 里面包含了很多东西,有我们常用的paginator类、page_obj类和我们自定义的一些参数等。
get_queryset
:如果你提取数据的时候,并不是要把所有数据都返回,那么你可以重写这个方法。将一些不需要展示的数据给过滤掉。class InfoListView(ListView):
# 设置需要返回的数据
def get_queryset(self):
# 没有重写方法默认返回所有的数据
# return models.Article.objects.all()
return models.Article.objects.filter(id__lte=93)
总结:上面类中的属性和方法说明:
model:重写model类属性,指定这个列表是给哪个模型的。
queryset:跟model一样,二选一。设定基础的数据集,Model的设定没有过滤的功能。
template_name:指定这个列表的模板。
paginate_by:指定这个列表一页中展示多少条数据。
context_object_name:指定这个列表模型在模板中的参数名称。
ordering:指定这个列表的排序方式。
page_kwarg:获取第几页的数据的参数名称。默认是page。
get_context_data:获取上下文的数据。
get_queryset:如果你提取数据的时候,并不是要把所有数据都返回,那么你可以重写这个方法。将一些不需要展示的数据给过滤掉。
Paginator
和Page
类都是用来做分页的。他们在Django中的路径为django.core.paginator.Paginator
和django.core.paginator.Page
。
count:总共有多少条数据。
num_pages:总共有多少页。
page_range:页面的区间。比如有三页,那么就range(1,4)。
class InfoListView(ListView):
model = models.Article # 重写model类属性,指定模型的列表
template_name = 'article_list.html' # 指定这个列表的模板。
context_object_name = 'articles' # 指定这个列表模型在模板中的参数名称。
paginate_by = 10 # 每一页需要展示多少条数据
ordering = 'create_time' # 以时间进行排序展示
page_kwarg = 'p' # 指定换页面的参数 默认为page 以GET的方式传递参数
# 重写父类的get_context_data方法,添加自己的参数
def get_context_data(self,**kwargs):
# 我们需要先继承至父模板的get_context_data方法,否则我们有很多方法将不能使用
context = super(ArticleListView,self).get_context_data(**kwargs)
# 然后添加自定义的参数
context['username'] = 'augustrush'
# print(context)
paginator = context.get('paginator') # paginator类
print(paginator.count) # 获取数据的个数
# print(paginator.num_pages) # 获取页数
# print(paginator.page_range) #或缺页数的范围,要前不要后
return context
# 设置需要返回的数据
# def get_queryset(self):
# # 没有重写方法默认返回所有的数据
# # return models.Article.objects.all()
# return models.Article.objects.filter(id__lte=89)
page类的常用属性和方法:
has_next: 是否有下一页
has_previous: 是否有上一页
next_page_number: 下一页的页码数
previous_page_number: 上一页的页码数
number:当前页的页码数
只有这一个是属性,其他都是方法
start_index:当前这一页的第一条数据的索引值。
end_index:当前这一页的最后一条数据的索引值。
class InfoListView(ListView):
model = models.Article # 重写model类属性,指定模型的列表
template_name = 'article_list.html' # 指定这个列表的模板。
context_object_name = 'articles' # 指定这个列表模型在模板中的参数名称。
paginate_by = 10 # 每一页需要展示多少条数据
ordering = 'create_time' # 以时间进行排序展示
page_kwarg = 'p' # 指定换页面的参数 默认为page 以GET的方式传递参数
# 重写父类的get_context_data方法,添加自己的参数
def get_context_data(self,**kwargs):
# 我们需要先继承至父模板的get_context_data方法,否则我们有很多方法将不能使用
context = super(ArticleListView,self).get_context_data(**kwargs)
# 然后添加自定义的参数
context['username'] = 'augustrush'
# print(context)
paginator = context.get('paginator') # paginator类
page_obj = context.get('page_obj') # page_obj类
# print(paginator.count) # 获取数据的个数
# print(paginator.num_pages) # 获取页数
# print(paginator.page_range) #或缺页数的范围,要前不要后
print(page_obj.number)
print(page_obj.start_index())
print(page_obj.end_index())
print(page_obj.has_next())
print(page_obj.has_previous())
print(page_obj.next_page_number())
print(page_obj.previous_page_number())
return context
# 设置需要返回的数据
# def get_queryset(self):
# # 没有重写方法默认返回所有的数据
# # return models.Article.objects.all()
# return models.Article.objects.filter(id__lte=89)
在开发中,有时候需要给一些视图添加装饰器。如果用函数视图那么非常简单,只要在函数的上面写上装饰器就可以了。但是如果想要给类添加装饰器,那么可以通过以下两种方式来实现:
需求:在访问个人中心页面的时候,如果没有登录,我们就让它跳转到登录页面,登录之后才能访问个人中心。
这里我们就是用get请求来模拟是否登录了,即如果我们在访问网址的时候使用get方法传递了一个username的参数,我们就认为已经登录, 否则的话就没有登录。
首先在view中定义个人中心的类视图和登录页面的函数视图:
# 个人中心的类视图
class ProfileView(View):
# 只能通过GET请求来访问
def get(self, request):
return HttpResponse("个人中心页面")
# 因为所有的请求方法在类视图中最终都会通过diapatch这个方法,
# 所以我们需要重写dispatch方法,并且继承至父类的dispatch方法。
def dispatch(self, request, *args, **kwargs):
return super(Profileview,self).dispatch(request,*args,**kwargs)
# 登录视图
def login(request):
return HttpResponse("登录页面")
在上面我们已经说到了所有的请求方法在类视图中最终都会通过diapatch这个方法,所以我们需要重写dispatch方法,并且继承至父类的dispatch方法。然后再使用装饰器将dispatch装饰,就达到了对类视图进行装饰的目地了,所以我们需要先写一个装饰器:
def login_required(func):
def wrapper(request, *args, **kwargs)
username = request.Get.get('username')
# 判断是否得到username这个值,如果得到了,就认为已经登录成功了,否则就没有登录
if username:
return func(request, *args, **kwargs)
else:
# 没有登录 重定向到登录页面
return redirect('login')
return wrapper
然后我们就将我们写的装饰器对dispatch进行装饰,这里我们需要使用到django中对类视图装饰的方法了:
from django.utils.decorators import method_decorator
对类视图进行装饰我们一般都使用这个方法。
然后我们使用这个方法对dispatch进行装饰,在dispatch函数的上面一行写入:
@method_decorator(login_required)
装饰完之后ProfileView
这个类视图的完整代码为:
# 个人中心的类视图
class Profileview(View):
# 只能通过GET请求来访问
def get(self,request):
return HttpResponse('个人中心页面')
# 因为所有的请求方法在类视图中最终都会通过diapatch这个方法,
# 所以我们需要重写dispatch方法,并且继承至父类的dispatch方法。
@method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
return super(Profileview,self).dispatch(request,*args,**kwargs)
这样我们就实现了第一种方法对类视图进行装饰了。 就可以输入url进行测试了,例如我的个人中心网址是:
http://127.0.0.1:8000/class/prfile/
当我进行访问的时候,他就会给我们跳转至登录页面,因为我们没有传入一个值username进去,就认为我们没有登录,所以我们想要访问个人中心就需要传入username进去。
http://127.0.0.1:8000/class/prfile/?username=username
这样,我们就能访问到我们的个人中心了,说明我们的装饰器也起到了相应的效果了。
但是上面的方法并不太好,因为我们在写类视图的时候,绝大多数就不会去重写dispatch方法,比如说我使用get请求,那么我就重写get方法就行了,使用post请求,重写post方法,而不用去重写dispatch方法。
那么怎样直接装饰在整个类上面呢,非常简单,只需要在类视图上面添加语句代码就行了
# 个人中心的类视图
@method_decorator(login_required,name='dispatch')
class Profileview(View):
# 只能通过GET请求来访问
def get(self,request):
return HttpResponse('个人中心页面')
# 因为所有的请求方法在类视图中最终都会通过diapatch这个方法,
# 所以我们需要重写dispatch方法,并且继承至父类的dispatch方法。
# @method_decorator(login_required)
# def dispatch(self, request, *args, **kwargs):
# return super(Profileview,self).dispatch(request,*args,**kwargs)
这样,我们就不用重写dispatch方法了,只需要在后面添加一个参数name指定装饰的类中的哪一个方法既可以了。
当然,如果我们有多个装饰器,我们还可以指定一个列表,
@method_decorator([login_required,xx_required],name='dispatch')
基于Nginx+Supervisord+uWSGI+Django1.11.1+Python3.6.5构建