数据显示视图
数据显示视图是将后台的数据展示在网页上,数据主要来自模型,一共定义了四个视图类。
- RedirectView:用于实现HTTP重定向,默认只定义了GET请求的处理方法。
- TemplateView:视图类的基础视图,可将数据传递给HTML模板,默认只定义了GET请求的处理方法。
- ListView:在TemplateView的基础上将数据以列表显示,通常将某个数据表的数据以列表表示。
- DetailView:在在TemplateView的基础上将数据详细展示,通常获取数据表的单条数据。
1.重定向视图RedirectView
RedirectView用于实现HTTP重定向功能,即网页跳转功能。在Django的源码内可以看到RedirectView的定义过程。从源码中可以看到RedirectView类,定义了四个属性和八个类方法。
class RedirectView(View):
"""Provide a redirect on any GET request."""
permanent = False
url = None
pattern_name = None
query_string = False
def get_redirect_url(self, *args, **kwargs):
"""
Return the URL redirect to. Keyword arguments from the URL pattern
match generating the redirect request are provided as kwargs to this
method.
"""
if self.url:
url = self.url % kwargs
elif self.pattern_name:
url = reverse(self.pattern_name, args=args, kwargs=kwargs)
else:
return None
args = self.request.META.get("QUERY_STRING", "")
if args and self.query_string:
url = "%s?%s" % (url, args)
return url
def 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)
其中
- permanent:根据属性值的真假来选择重定向的方式,若为True,则HTTP状态码为301,False则为302。
- url:代表重定向的路径。
- pattern_name:代表重定向的路由命名,若已经设置了url,则不用设置该参数。
- query_string:是否将当前路由地址的请求参传递到重定向的路由地址。
- get_redirect_url():根据属性pattern_name所指向的路由命名来生成相应的路由地址。
- get():触发HTTP的GET请求所执行的响应处理。
- 其余类方法:是HTTP的不同请求方式,都由get()方法完成响应处理。
# app的urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('turnTo/', views.turmTO.as_view(), name='turnTo'),
]
# app的views.py
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
from django.views.generic import RedirectView
def index(request):
return HttpResponse('hello world')
class turmTO(RedirectView):
permanent = False
url = None
pattern_name = 'index:index'
query_string = False
def get_redirect_url(self, *args, **kwargs):
url = super().get_redirect_url(*args, **kwargs)
print(url)
return url
# index.html模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Redirect View</title>
</head>
<body>
<a href="{% url 'index:turnTo' %}">turn</a>
</body>
</html>
在app中定义了视图类turnTo,它继承父类RedirectView,对父类的属性和类方法进行重写,通过这样的方式可以扩展RedirectView的功能,从而满足开发需求。在定义路由时,使用视图类处理HTTP请求,则需要对视图类使用.as_view()方法(对视图类进行实例化处理),在开发时若需要对其他的HTTP请求进行处理,那么只需要重新定义相应的类方法即可。运行Django项目以上代码,可见
September 16, 2022 - 22:54:47
Django version 4.1.1, using settings 'djangoProject.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
[16/Sep/2022 22:54:48] "GET / HTTP/1.1" 200 11
redirect to /
[16/Sep/2022 22:54:51] "GET /turnTo/ HTTP/1.1" 302 0
[16/Sep/2022 22:54:51] "GET / HTTP/1.1" 200 11
2.基础视图TemplateView
视图类是所有视图类中的最基础的应用视图类,开发者可以直接调用应用视图类。它继承于多个父类,TemplateResponseMixin,ContextMixin和View,以下是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(),该方法调用get_context_data(),render_to_response()方法从而完成HTTP请求的响应过程,get()方法中所调用的方法来自TemplateResponseMixin,ContextMixin。
- ContextMixin类中的get_context_data()方法用于获取模板上下文内容,模板上下文是将视图里的数据传递到模板文件,再由模板引擎转换为HTML网页数据。
TemplateResponseMixin类中的render_to_response()方法用于实现响应处理,由响应类TemplateResponse处理。下面是TemplateResponseMixin类的定义。
class TemplateResponseMixin: """A mixin that can be used to render a template.""" template_name = None template_engine = None response_class = TemplateResponse content_type = None def render_to_response(self, context, **response_kwargs): """ Return a response, using the `response_class` for this view, with a template rendered with the given context. Pass response_kwargs to the constructor of the response class. """ response_kwargs.setdefault("content_type", self.content_type) return self.response_class( request=self.request, template=self.get_template_names(), context=context, using=self.template_engine, **response_kwargs, ) def get_template_names(self): """ Return a list of template names to be used for the request. Must return a list. May not be called if render_to_response() is overridden. """ if self.template_name is None: raise ImproperlyConfigured( "TemplateResponseMixin requires either a definition of " "'template_name' or an implementation of 'get_template_names()'" ) else: return [self.template_name]
- template_name = None:设置模板文件的文件名
- template_engine = None:设置模板文件的模板引擎
- response_class = TemplateResponse:设置HTTP请求的响应类,默认为TemplateResponse类
- content_type = None:设置响应内容的数据格式
- render_to_response():实现响应处理
- get_template_names():获取属性template_name的值
# app的urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index.as_view(), name='index'),
]
# app 的views.py
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
from django.views.generic import RedirectView, TemplateView
class index(TemplateView):
template_name = 'index.html'
template_engine = None
content_type = None
extra_context = {'title': 'this is get'}
def get_context_data(self, **kwargs):
context = super(index, self).get_context_data(**kwargs)
context['name'] = 'ronie'
return context
def post(self, request, *args, **kwargs):
self.extra_context['title'] = 'this is post'
print('set post')
return self.render_to_response(self.get_context_data(**kwargs))
!! index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Redirect View</title>
</head>
<body>
<h1>{{ title }}</h1>
<h1>{{ name }}</h1>
<form action="" method="post">
{% csrf_token %}
<input type="submit" value="submit">
</form>
</body>
</html>
上述代码将网站首页的index视图函数改为index视图类,自定义视图类index继承自TemplateView类,重设了四个属性,重写了两个类方法。
- template_name:设置模板文件的index.html
- template_engine:设置模板文件的模板引擎
- content_type:设置响应内容的数据格式,none即代表数据为默认的text/html
- get_context_data():继承并重写视图类TemplateView的类方法,在变量context里自定义name
- post():自定义post()请求的处理方法,当触发post请求时,重设属性值,并调用get_context_data()将属性extra_context写入,动态的改变模板的内容。
当使用get访问时
当使用点击post,使用post访问时
bash信息
September 17, 2022 - 19:39:26
Django version 4.1.1, using settings 'djangoProject.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
[17/Sep/2022 19:39:27] "GET / HTTP/1.1" 200 372
set post
[17/Sep/2022 19:40:16] "POST / HTTP/1.1" 200 373
3.列表视图ListView
视图是连接模板和路由的中心枢纽,同时视图还可以连接模型。模型指Django通过一定的规则来映射数据库,从而方便Django与数据库的交互。因为Django可以通过一定的规则来映射数据库,因此Django提供了视图类ListView,该视图类将数据表的数据以列表的形式显示,常用于数据库的查询。以下通过源码分析ListView的定义过程:
class MultipleObjectMixin(ContextMixin):
"""A mixin for views manipulating multiple objects."""
allow_empty = True
queryset = None
model = None
paginate_by = None
paginate_orphans = 0
context_object_name = None
paginator_class = Paginator
page_kwarg = "page"
ordering = None
def get_queryset(self):
"""
Return the list of items for this view.
The return value must be an iterable and may be an instance of
`QuerySet` in which case `QuerySet` specific behavior will be enabled.
"""
def get_ordering(self):
"""Return the field or fields to use for ordering the queryset."""
def paginate_queryset(self, queryset, page_size):
"""Paginate the queryset, if needed."""
def get_paginate_by(self, queryset):
"""
Get the number of items to paginate by, or ``None`` for no pagination.
"""
def get_paginator(
self, queryset, per_page, orphans=0, allow_empty_first_page=True, **kwargs
):
"""Return an instance of the paginator for this view."""
def get_paginate_orphans(self):
"""
Return the maximum number of orphans extend the last page by when
paginating.
"""
def get_allow_empty(self):
"""
Return ``True`` if the view should display empty lists and ``False``
if a 404 should be raised instead.
"""
def get_context_object_name(self, object_list):
"""Get the name of the item to be used in the context."""
def get_context_data(self, *, object_list=None, **kwargs):
"""Get the context for this view."""
class BaseListView(MultipleObjectMixin, View):
"""A base view for displaying a list of objects."""
def get(self, request, *args, **kwargs):
class MultipleObjectTemplateResponseMixin(TemplateResponseMixin):
"""Mixin for responding with a template and list of objects."""
template_name_suffix = "_list"
def get_template_names(self):
"""
Return a list of template names to be used for the request. Must return
a list. May not be called if render_to_response is overridden.
"""
class ListView(MultipleObjectTemplateResponseMixin, BaseListView):
"""
Render some list of objects, set by `self.model` or `self.queryset`.
`self.queryset` can actually be any iterable of items, not just a queryset.
"""
根据以上的继承关系可知,ListView的底层类是由TemplateResponseMixin,ContextMixin和View组成的,在这些底层类的基础上加入了模型的操作方法。通过分析得知,ListView类具有TemplateView类的全部属性和方法,此外i还新增了属性和方法。
- allow_empty = True:在模型查询数据不存在指导情况下是否显示页面,默认为True,若为false且数据不存在,则引发404异常。
- queryset = None:代表模型的查询对象,这是对模型对象进行查询操作所生成的查询对象。
- model = None:代表模型,一个模型代表一个数据表。
- paginate_by = None:代表每一页显示的数据量。
- paginate_orphans = 0:代表最后一页可以包含的溢出的数据量,防止最后一页数据量过少。
- context_object_name = None:设置模板上下文,即为模板变量命名。
- paginator_class = Paginator:设置分页的功能类,默认为内置分页Paginator。
- page_kwarg = "page":设置分页参数名称,默认为page。
- ordering = None:对属性queryset查询结果进行排序。
- get_context_data(self, , object_list=None, *kwargs):获取模板上下文(模板变量的内容)。
- get_context_object_name(self, object_list):设置模板上下文的名称,若未设置,则上下文名称由模型名称+‘_list’表示。
- get_allow_empty(self):获取属性allow_empty的属性值。
- get_paginate_orphans(self):获取最后一页可以包含的溢出的数据量。
- get_paginator():返回当前页数所对应的数据信息。
- get_paginate_by(self, queryset):获取每一页所显示的数据量。
- paginate_queryset(self, queryset, page_size):根据queryset的数据来进行分页处理。
- get_ordering(self):获取属性ordering的值
- get_queryset(self):获取queryset的值。
- get(self, request, args, *kwargs):定义HTTP的GET请求处理方式。
- get_template_names(self):获取属性template_name的值
# app的urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index.as_view(), name='index'),
]
# app的views.py
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
from django.views.generic import RedirectView, TemplateView, ListView
from .models import Person
class index(ListView):
template_name = 'index.html'
queryset = Person.objects.all()
extra_context = {'title': 'Person Info'}
paginate_by = 2
context_object_name = 'Person'
# app的models.py 记得执行makemigrations migrate,并向数据库中条件数据
from django.db import models
# Create your models here.
class Person(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
age = models.IntegerField()
!index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Redirect View</title>
</head>
<body>
<h1>{{ title }}</h1>
<table>
<td>name</td>
<td>age</td>
{% for data in Person %}
<tr>
<th>{{ data.name }}</th>
<th>{{ data.age }}</th>
</tr>
{% endfor %}
</table>
{% if page_obj.has_previous %}
<a href="/?page={{ page_obj.previous_page_number }}">previous page</a>
{% endif %}
<br>
{% if page_obj.has_next %}
<a href="/?page={{ page_obj.next_page_number }}">next page</a>
{% endif %}
<p>当前{{ page_obj.number }}页</p>
<p>共{{ page_obj.paginator.num_pages }}页</p>
</body>
</html>
Comments | NOTHING