django:视图类之RedirectView、TemplateView、ListView、DetailView的源码与示例

一,为什么需要视图类(Class Base Views)

面对功能和业务逻辑具有相同过程的需求时, 使用视图函数来完成的话,可能需要编写大量重复代码,而且视图函数过多时,不方便后期修护,所以django贴心地提供了视图类来封装一些列相同逻辑,开发者只需要继django提供的父类,就能使用更加完善、统一的功能。

二,django提供的数据显示视图类

用于将表单或模型的数据展示到网页中。

1,重定向视图RedirectView

**功能:**指定url与请求参数后,实现HTTP重定向哦功能。
**源码:**为了方便理解,所有源码都调整了顺序

源码:
class RedirectView(View):
    """Provide a redirect on any GET request."""
    permanent = False  # True,301。False,302。
    url = None	# 要重定向到的字符串作为字符串。如果是None引发410(Gone)HTTP错误。
    pattern_name = None 	# 要重定向到的URL名称。
    query_string = False	# 是否将GET查询字符串传递给新位置。如果 True,则查询字符串将附加到URL。如果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)


class View:
    """
    Intentionally simple parent class for all views. Only implements
    dispatch-by-method and simple sanity checking.
    """

    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

    def __init__(self, **kwargs):
        """
        Constructor. Called in the URLconf; can contain helpful extra
        keyword arguments, and other things.
        """
        # Go through keyword arguments, and either save their values to our
        # instance, or raise an error.
        for key, value in kwargs.items():
            setattr(self, key, value)

    @classonlymethod
    def as_view(cls, **initkwargs):
        """Main entry point for a request-response process."""
        for key in initkwargs:
            if key in cls.http_method_names:
                raise TypeError("You tried to pass in the %s method name as a "
                                "keyword argument to %s(). Don't do that."
                                % (key, cls.__name__))
            if not hasattr(cls, key):
                raise TypeError("%s() received an invalid keyword %r. as_view "
                                "only accepts arguments that are already "
                                "attributes of the class." % (cls.__name__, key))

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.setup(request, *args, **kwargs)
            if not hasattr(self, 'request'):
                raise AttributeError(
                    "%s instance has no 'request' attribute. Did you override "
                    "setup() and forget to call super()?" % cls.__name__
                )
            return self.dispatch(request, *args, **kwargs)
        view.view_class = cls
        view.view_initkwargs = initkwargs

        # take name and docstring from class
        update_wrapper(view, cls, updated=())

        # and possible attributes set by decorators
        # like csrf_exempt from dispatch
        update_wrapper(view, cls.dispatch, assigned=())
        return view

    def setup(self, request, *args, **kwargs):
        """Initialize attributes shared by all view methods."""
        self.request = request
        self.args = args
        self.kwargs = kwargs

    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)

    def http_method_not_allowed(self, request, *args, **kwargs):
        logger.warning(
            'Method Not Allowed (%s): %s', request.method, request.path,
            extra={
    
    'status_code': 405, 'request': request}
        )
        return HttpResponseNotAllowed(self._allowed_methods())

    def options(self, request, *args, **kwargs):
        """Handle responding to requests for the OPTIONS HTTP verb."""
        response = HttpResponse()
        response['Allow'] = ', '.join(self._allowed_methods())
        response['Content-Length'] = '0'
        return response

    def _allowed_methods(self):
        return [m.upper() for m in self.http_method_names if hasattr(self, m)]

官方示例:

官方示例:
urls.py:
from django.urls import path
from django.views.generic.base import RedirectView

from article.views import ArticleCounterRedirectView, ArticleDetail

urlpatterns = [
    path('counter/<int:pk>/', ArticleCounterRedirectView.as_view(), name='article-counter'),
    path('details/<int:pk>/', ArticleDetail.as_view(), name='article-detail'),
    path('go-to-django/', RedirectView.as_view(url='https://djangoproject.com'), name='go-to-django'),
]


views.py:
from django.shortcuts import get_object_or_404
from django.views.generic.base import RedirectView

from articles.models import Article

class ArticleCounterRedirectView(RedirectView):

    permanent = False
    query_string = True
    pattern_name = 'article-detail'

    def get_redirect_url(self, *args, **kwargs):
        article = get_object_or_404(Article, pk=kwargs['pk'])
        article.update_counter()
        return super().get_redirect_url(*args, **kwargs)

写自己的例子:

urls.py:
from django.urls import path
from index.views import *

urlpatterns = [
    # 定义路由
    path('', index, name='index'),
    path('turnTo', turnTo.as_view(url='https://djangoproject.com'), name='turnTo')
]


views.py:
from django.shortcuts import render
from django.views.generic.base import RedirectView

def index(request):
    return render(request, 'index.html')

class turnTo(RedirectView):
    permanent = False
    pattern_name = None
    query_string = True

    def get_redirect_url(self, *args, **kwargs):
        print('This is get_redirect_url:', self.url)
        return super().get_redirect_url(*args, **kwargs)

    def get(self, request, *args, **kwargs):
        print(request.META.get('HTTP_USER_AGENT'))
        return super().get(request, *args, **kwargs)


index.html:
<!DOCTYPE html>
<html>
	<body>
		<h3>Hello RedirectView</h3>
		<a href="{% url 'index:turnTo' %}">ToTurn</a>
	</body>
</html>

运行起来,点击链接会跳转到指定的页面:
在这里插入图片描述
成功跳转:
在这里插入图片描述
在这里插入图片描述

2,基础试图TemplateView

功能: 渲染模板。将关键字参数从URLconf传递到上下文。
源码:

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)


class TemplateResponseMixin:
    """
    A mixin that can be used to render a template.
    渲染模板
    """
    template_name = None	# 设置模板名
    template_engine = None	# 设置模板引擎
    response_class = TemplateResponse	# 设置HTTP请求响应类
    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.
        获取template_names值
        """
        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]


class ContextMixin:
    """
    A default context mixin that passes the keyword arguments received by get_context_data() as the template context.
    获取模板上下文内容。
    """
    extra_context = None

    def get_context_data(self, **kwargs):
        kwargs.setdefault('view', self)
        if self.extra_context is not None:
            kwargs.update(self.extra_context)
        return kwargs

官方示例:

views.py:
from django.views.generic.base import TemplateView
from articles.models import Article

class HomePageView(TemplateView):

    template_name = "home.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['latest_articles'] = Article.objects.all()[:5]
        return context


urls.py:
from django.urls import path
from myapp.views import HomePageView

urlpatterns = [
    path('', HomePageView.as_view(), name='home'),
]

写自己的例子:

views.py:
class index(TemplateView):
    template_name = 'index.html'
    template_engine = None
    content_type = None

    extra_context = {
    
    'title': '我是你刚点进来时从类中直接被传递过来的内容'}

    # 重新定义模版上下文的获取方式
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['value'] = '我一直叫小黑'
        return context

    # 定义HTTP的POST请求处理
    def post(self, request, *args, **kwargs):
        self.extra_context = {
    
    'title': '我是你点击submit后从类中直接被传递过来的内容'}
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)


urls.py:
from django.urls import path
from index.views import *

urlpatterns = [
    # 定义路由
    path('', index.as_view(), name='index'),
]


index.html:
<!DOCTYPE html>
<html>
<body>
<h3>Hello,{
    
    {
    
     title }}</h3>
<div>{
    
    {
    
     value }}</div>
<br>
<form action="" method="post">
    {
    
    % csrf_token %}
    <input type="submit" value="点我,我的来源就变了">
</form>
</body>
</html>

运行起来,会将指定的模板上下文内容传递给指定的模板:
在这里插入图片描述
在这里插入图片描述

3,列表视图ListView

前面的两个数据展示视图通常都是联系视图与模板的,django也提供了联系视图与模型的视图ListView。
**功能:**将数据表中的数据以列表形式显示。
源码:

扫描二维码关注公众号,回复: 11759366 查看本文章
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.
    """

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.
        """
        try:
            names = super().get_template_names()
        except ImproperlyConfigured:
            # If template_name isn't specified, it's not a problem --
            # we just start with an empty list.
            names = []
        # If the list is a queryset, we'll invent a template name based on the
        # app and model name. This name gets put at the end of the template
        # name list so that user-supplied names override the automatically-
        # generated ones.
        if hasattr(self.object_list, 'model'):
            opts = self.object_list.model._meta
            names.append("%s/%s%s.html" % (opts.app_label, opts.model_name, self.template_name_suffix))
        elif not names:
            raise ImproperlyConfigured(
                "%(cls)s requires either a 'template_name' attribute "
                "or a get_queryset() method that returns a QuerySet." % {
    
    
                    'cls': self.__class__.__name__,
                }
            )
        return names


class BaseListView(MultipleObjectMixin, View):
    """A base view for displaying a list of objects."""
    def get(self, request, *args, **kwargs):
        self.object_list = self.get_queryset()
        allow_empty = self.get_allow_empty()

        if not allow_empty:
            # When pagination is enabled and object_list is a queryset,
            # it's better to do a cheap query than to load the unpaginated
            # queryset in memory.
            if self.get_paginate_by(self.object_list) is not None and hasattr(self.object_list, 'exists'):
                is_empty = not self.object_list.exists()
            else:
                is_empty = not self.object_list
            if is_empty:
                raise Http404(_("Empty list and '%(class_name)s.allow_empty' is False.") % {
    
    
                    'class_name': self.__class__.__name__,
                })
        context = self.get_context_data()
        return self.render_to_response(context)


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			# 对queryset内容进行排序

    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.
        获取queryset 的值
        """
        if self.queryset is not None:
            queryset = self.queryset
            if isinstance(queryset, QuerySet):
                queryset = queryset.all()
        elif self.model is not None:
            queryset = self.model._default_manager.all()
        else:
            raise ImproperlyConfigured(
                "%(cls)s is missing a QuerySet. Define "
                "%(cls)s.model, %(cls)s.queryset, or override "
                "%(cls)s.get_queryset()." % {
    
    
                    'cls': self.__class__.__name__
                }
            )
        ordering = self.get_ordering()
        if ordering:
            if isinstance(ordering, str):
                ordering = (ordering,)
            queryset = queryset.order_by(*ordering)

        return queryset

    def get_ordering(self):
        """
        Return the field or fields to use for ordering the queryset.
        获取ordering 的值
        """
        return self.ordering

    def paginate_queryset(self, queryset, page_size):
        """
        Paginate the queryset, if needed.
        据queryset值进行分页处理
        """
        paginator = self.get_paginator(
            queryset, page_size, orphans=self.get_paginate_orphans(),
            allow_empty_first_page=self.get_allow_empty())
        page_kwarg = self.page_kwarg
        page = self.kwargs.get(page_kwarg) or self.request.GET.get(page_kwarg) or 1
        try:
            page_number = int(page)
        except ValueError:
            if page == 'last':
                page_number = paginator.num_pages
            else:
                raise Http404(_("Page is not 'last', nor can it be converted to an int."))
        try:
            page = paginator.page(page_number)
            return (paginator, page, page.object_list, page.has_other_pages())
        except InvalidPage as e:
            raise Http404(_('Invalid page (%(page_number)s): %(message)s') % {
    
    
                'page_number': page_number,
                'message': str(e)
            })

    def get_paginate_by(self, queryset):
        """
        Get the number of items to paginate by, or ``None`` for no pagination.
        """
        return self.paginate_by

    def get_paginator(self, queryset, per_page, orphans=0,
                      allow_empty_first_page=True, **kwargs):
        """
        Return an instance of the paginator for this view.
        """
        return self.paginator_class(
            queryset, per_page, orphans=orphans,
            allow_empty_first_page=allow_empty_first_page, **kwargs)

    def get_paginate_orphans(self):
        """
        Return the maximum number of orphans extend the last page by when paginating.
        
        """
        return self.paginate_orphans

    def get_allow_empty(self):
        """
        Return ``True`` if the view should display empty lists and ``False`` if a 404 should be raised instead.
        """
        return self.allow_empty

    def get_context_object_name(self, object_list):
        """
        Get the name of the item to be used in the context.
        """
        if self.context_object_name:
            return self.context_object_name
        elif hasattr(object_list, 'model'):
            return '%s_list' % object_list.model._meta.model_name
        else:
            return None

    def get_context_data(self, *, object_list=None, **kwargs):
        """
        Get the context for this view.
        """
        queryset = object_list if object_list is not None else self.object_list
        page_size = self.get_paginate_by(queryset)
        context_object_name = self.get_context_object_name(queryset)
        if page_size:
            paginator, page, queryset, is_paginated = self.paginate_queryset(queryset, page_size)
            context = {
    
    
                'paginator': paginator,
                'page_obj': page,
                'is_paginated': is_paginated,
                'object_list': queryset
            }
        else:
            context = {
    
    
                'paginator': None,
                'page_obj': None,
                'is_paginated': False,
                'object_list': queryset
            }
        if context_object_name is not None:
            context[context_object_name] = queryset
        context.update(kwargs)
        return super().get_context_data(**context)

官方示例:

views.py:
from django.utils import timezone
from django.views.generic.list import ListView
from articles.models import Article

class ArticleListView(ListView):

    model = Article
    paginate_by = 100  # if pagination is desired

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['now'] = timezone.now()
        return context


urls.py:
from django.urls import path

from article.views import ArticleListView

urlpatterns = [
    path('', ArticleListView.as_view(), name='article-list'),
]

		
article_list.html:
<h1>Articles</h1>
<ul>
{
    
    % for article in object_list %}
    <li>{
    
    {
    
     article.pub_date|date }} - {
    
    {
    
     article.headline }}</li>
{
    
    % empty %}
    <li>No articles yet.</li>
{
    
    % endfor %}
</ul>

自己的例子:

models.py:
from django.db import models
# Create your models here.
class PersonInfo(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    age = models.IntegerField()


views.py:
from django.views.generic import ListView
from .models import PersonInfo

class index(ListView):
	"""
	这里直接继承自ListView,由于它继承自BaseListView,故只能处理HTTP GET的能力,需要处理HTTP POST可以先直接在ListView中写出来。
	"""
    # 设置模版文件
    template_name = 'index.html'
    # 设置模型外的数据
    extra_context = {
    
    'title': '这是张人员信息表'}
    # 查询模型PersonInfo,产生查询结果对象
    queryset = PersonInfo.objects.all()
    # 每页的展示一条数据
    paginate_by = 1


index.html:
<!DOCTYPE html>
<html>
<head>
    <title>{
    
    {
    
     title }}</title>
<body>
    <h3>{
    
    {
    
     title }}</h3>
    <table border="1">
      {
    
    % for i in personinfo_list %}
          <tr>
            <th>{
    
    {
    
     i.name }}</th>
            <th>{
    
    {
    
     i.age }}</th>
          </tr>
      {
    
    % endfor %}
    </table>
    <br>
    {
    
    % if is_paginated %}
    <div class="pagination">
        <span class="page-links">
            {
    
    % if page_obj.has_previous %}
                <a href="/?page={
    
    { page_obj.previous_page_number }}">上一页</a>
            {
    
    % endif %}
            {
    
    % if page_obj.has_next %}
                <a href="/?page={
    
    { page_obj.next_page_number }}">下一页</a>
            {
    
    % endif %}
            <br>
            <br>
            <span class="page-current">{
    
    {
    
     page_obj.number }},{
    
    {
    
     page_obj.paginator.num_pages }}页。
            </span>
        </span>
    </div>
    {
    
    % endif %}
</body>
</html>

运行起来,仅需要简单的设置,就能在后台将数据提取出来交给模板进行展示:
在这里插入图片描述

4,详情视图DetailView

功能: 功能上较ListView更强。
源码:

class DetailView(SingleObjectTemplateResponseMixin, BaseDetailView):
    """
    Render a "detail" view of an object.
    By default this is a model instance looked up from `self.queryset`, but the view will support display of *any* object by overriding `self.get_object()`.
    """

class SingleObjectTemplateResponseMixin(TemplateResponseMixin):
    template_name_field = None	# 设置模板名
    template_name_suffix = '_detail'

    def get_template_names(self):
        """
        Return a list of template names to be used for the request. May not be
        called if render_to_response() is overridden. Return the following list:
        * the value of ``template_name`` on the view (if provided)
        * the contents of the ``template_name_field`` field on the
          object instance that the view is operating upon (if available)
        * ``<app_label>/<model_name><template_name_suffix>.html``
        """
        try:
            names = super().get_template_names()
        except ImproperlyConfigured:
            # If template_name isn't specified, it's not a problem --
            # we just start with an empty list.
            names = []
            # If self.template_name_field is set, grab the value of the field
            # of that name from the object; this is the most specific template
            # name, if given.
            if self.object and self.template_name_field:
                name = getattr(self.object, self.template_name_field, None)
                if name:
                    names.insert(0, name)
            # The least-specific option is the default <app>/<model>_detail.html;
            # only use this if the object in question is a model.
            if isinstance(self.object, models.Model):
                object_meta = self.object._meta
                names.append("%s/%s%s.html" % (
                    object_meta.app_label,
                    object_meta.model_name,
                    self.template_name_suffix
                ))
            elif getattr(self, 'model', None) is not None and issubclass(self.model, models.Model):
                names.append("%s/%s%s.html" % (
                    self.model._meta.app_label,
                    self.model._meta.model_name,
                    self.template_name_suffix
                ))
            # If we still haven't managed to find any template names, we should
            # re-raise the ImproperlyConfigured to alert the user.
            if not names:
                raise
        return names


class BaseDetailView(SingleObjectMixin, View):
    """
    A base view for displaying a single object.
	处理HTTP GET请求
	"""
    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        context = self.get_context_data(object=self.object)
        return self.render_to_response(context)


class SingleObjectMixin(ContextMixin):
    """
    Provide the ability to retrieve a single object for further manipulation.
    """
    model = None
    queryset = None
    slug_field = 'slug'			# 设置模型中某字段为查询对象,默认为slug
    context_object_name = None
    slug_url_kwarg = 'slug'		
    pk_url_kwarg = 'pk'			# 设置url的某个参数,默认为pk
    query_pk_and_slug = False	# True时,据slug_url_kwarg和pk_url_kwarg组合查询

    def get_object(self, queryset=None):
        """
        Return the object the view is displaying.
        Require `self.queryset` and a `pk` or `slug` argument in the URLconf.
        Subclasses can override this to return any object.
        单条数据查询
        """
        # Use a custom queryset if provided; this is required for subclasses
        # like DateDetailView
        if queryset is None:
            queryset = self.get_queryset()

        # Next, try looking up by primary key.
        pk = self.kwargs.get(self.pk_url_kwarg)
        slug = self.kwargs.get(self.slug_url_kwarg)
        if pk is not None:
            queryset = queryset.filter(pk=pk)

        # Next, try looking up by slug.
        if slug is not None and (pk is None or self.query_pk_and_slug):
            slug_field = self.get_slug_field()
            queryset = queryset.filter(**{
    
    slug_field: slug})

        # If none of those are defined, it's an error.
        if pk is None and slug is None:
            raise AttributeError(
                "Generic detail view %s must be called with either an object "
                "pk or a slug in the URLconf." % self.__class__.__name__
            )

        try:
            # Get the single item from the filtered queryset
            obj = queryset.get()
        except queryset.model.DoesNotExist:
            raise Http404(_("No %(verbose_name)s found matching the query") %
                          {
    
    'verbose_name': queryset.model._meta.verbose_name})
        return obj

    def get_queryset(self):
        """
        Return the `QuerySet` that will be used to look up the object.
        This method is called by the default implementation of get_object() and may not be called if get_object() is overridden.
        """
        if self.queryset is None:
            if self.model:
                return self.model._default_manager.all()
            else:
                raise ImproperlyConfigured(
                    "%(cls)s is missing a QuerySet. Define "
                    "%(cls)s.model, %(cls)s.queryset, or override "
                    "%(cls)s.get_queryset()." % {
    
    
                        'cls': self.__class__.__name__
                    }
                )
        return self.queryset.all()

    def get_slug_field(self):
        """
        Get the name of a slug field to be used to look up by slug.
        """
        return self.slug_field

    def get_context_object_name(self, obj):
        """Get the name to use for the object."""
        if self.context_object_name:
            return self.context_object_name
        elif isinstance(obj, models.Model):
            return obj._meta.model_name
        else:
            return None

    def get_context_data(self, **kwargs):
        """Insert the single object into the context dict."""
        context = {
    
    }
        if self.object:
            context['object'] = self.object
            context_object_name = self.get_context_object_name(self.object)
            if context_object_name:
                context[context_object_name] = self.object
        context.update(kwargs)
        return super().get_context_data(**context)


自己的例子:

models.py:
from django.db import models
# Create your models here.
class PersonInfo(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    age = models.IntegerField()


views.py:
from django.views.generic import DetailView
from .models import PersonInfo

class index(DetailView):
    # 设置模版文件
    template_name = 'index.html'
    # 设置模型外的数据
    extra_context = {
    
    'title': '人员信息表'}
    # 设置模型的查询字段
    slug_field = 'age'
    # 设置路由的变量名,与属性slug_field实现模型的查询操作
    slug_url_kwarg = 'age'
    pk_url_kwarg = 'pk'
    # 设置查询模型PersonInfo
    model = PersonInfo
    # 属性queryset可以做简单的查询操作
    # queryset = PersonInfo.objects.all()


index.html:
<!DOCTYPE html>
<html>
<head>
    <title>{
    
    {
    
     title }}</title>
<body>
    <h3>{
    
    {
    
     title }}</h3>
    <table border="1">
      <tr>
        <th>{
    
    {
    
     personinfo.name }}</th>
        <th>{
    
    {
    
     personinfo.age }}</th>
      </tr>
    </table>
    <br>
</body>
</html>

运行起来,相对ListView而言,DetailView除了拥有它的所有属性与方法之外,还能从请求中取出参数进行使用,查询更加细节:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/dangfulin/article/details/107890419