• Django通用视图执行过程


    使用通用视图后,Django请求处理过程(以ListView为例):
    在我们自定义的视图中:

    class IndexView(ListView):
        template_name = 'blog/index.html'
        context_object_name = 'article_list'
    
        def get_context_data(self, **kwargs):
            kwargs['category_list'] = Category.objects.all()
            return super(IndexView, self).get_context_data()
    
        def get_queryset(self):
            return Article.objects.filter(status=1)
    

    ListView的定义:

    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.
        """
    

    View中as_view方法:

    class View(object):
        @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.request = request
                self.args = args
                self.kwargs = kwargs
                return self.dispatch(request, *args, **kwargs)
    

     dispatch方法:

    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)
    

     dispatch方法中根据http请求的method得到handler的值(get,post...),接着调用handler方法,如果是get请求,则调用的是get方法。get方法定义在BaseListView中:

    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 = len(self.object_list) == 0
                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)
    

     get_queryset、get_context_data在父类中的定义:

    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.
            """
            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, six.string_types):
                    ordering = (ordering,)
                queryset = queryset.order_by(*ordering)
    
            return queryset
            
            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, **kwargs):
                """
                Get the context for this view.
                """
                queryset = kwargs.pop('object_list', 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(MultipleObjectMixin, self).get_context_data(**context)
    

     当我们自定义的视图函数IndexView中重写get_context_data时,可将需传递到template的数据赋值给kwargs变量,最终数据会加入到context上下文中:

    if context_object_name is not None:
            context[context_object_name] = queryset
            context.update(kwargs)
    

     最后回到BaseListView类的get方法,调用了self.render_to_response(context)进行响应输出。

  • 相关阅读:
    【python】requests库
    pycharm新建项目时选择virtualenv的说明
    cookie、session、token
    读写锁--DEMO
    锁降级--防止线程安全问题
    mysql-left join
    index-document-shard
    ES-常见搜索方式
    SpringBoot在自定义类中调用service层等Spring其他层
    mongodb crud
  • 原文地址:https://www.cnblogs.com/liubiao/p/5594501.html
Copyright © 2020-2023  润新知