• Django有3种视图与说明


    Django有3种视图:
    函数视图 FBV
    类视图 CBV
    通用视图 CBGV
    函数视图 FBV
    通过条件分支来处理不同http请求

    # 函数视图  FBV
    def my_view(request):
        if request.method == 'GET':
            return HttpResponse("xxx")
        elif request.method == 'POST':
            return HttpResponse("xxx")
        elif request.method == 'DELETE':
            return HttpResponse("xxx")
    1
    2
    3
    4
    5
    6
    7
    8
    # urls
    from . import views
    urlpatterns = [
        path('', views.my_view, name='index')
    ]
    1
    2
    3
    4
    5
    缺点:函数式编程-面向过程,代码复用率低

    类视图 CBV
    继承自View类,通过不同实例方法来响应http请求

    # 面向对象编程
    from django.views.generic import View

    class MyView(View):
        def get(self,request,*args,**kwargs):
            pass
        def post(self,request,*args,**kwargs):
            pass
    1
    2
    3
    4
    5
    6
    7
    8
    # urls
    from . import views

    # 使用as_view()方法,为基于类的视图提供一个类似函数的入口
    urlpatterns = [
        path('', views.MyView.as_view(), name='index')
    ]
    1
    2
    3
    4
    5
    6
    7
    通用视图 CBGV
    在类视图上更进一步,把增删改查操作的具体方法抽象出来,使用更少的代码实现功能

    以通用显示视图 DetailView 为例:
    该视图从以下视图继承方法和属性,MRO顺序:
    想了解MRO的具体原理移步我的另一篇博文: https://blog.csdn.net/weixin_44955304/article/details/105175789

    DetailView(自身)
    django.views.generic.detail.SingleObjectTemplateResponseMixin
    django.views.generic.base.TemplateResponseMixin
    django.views.generic.detail.BaseDetailView
    django.views.generic.detail.SingleObjectMixin
    django.views.generic.base.ContextMixin
    django.views.generic.base.View

    方法流程图

    具有(可重写-自定义)的类属性

    属性    Defined in
    content_type = None    TemplateResponseMixin
    context_object_name = None    SingleObjectMixin
    extra_context = None    ContextMixin
    http_method_names = [‘get’, ‘post’, ‘put’, ‘patch’, ‘delete’, ‘head’, ‘options’, ‘trace’]    View
    model = None    SingleObjectMixin
    pk_url_kwarg = ‘pk’    SingleObjectMixin
    query_pk_and_slug = False    SingleObjectMixin
    queryset = None    SingleObjectMixin
    response_class =     TemplateResponseMixin
    slug_field = ‘slug’    SingleObjectMixin
    slug_url_kwarg = ‘slug’    SingleObjectMixin
    template_engine = None    TemplateResponseMixin
    template_name = None    TemplateResponseMixin
    template_name_field = None    SingleObjectTemplateResponseMixin
    template_name_suffix = ‘_detail’    SingleObjectTemplateResponseMixin
    按照Django官方文档所述流程看,通用类视图代码
    setup

    def setup(self, request, *args, **kwargs):
    """Initialize attributes shared by all view methods."""
        self.request = request
        self.args = args
        self.kwargs = kwargs
    1
    2
    3
    4
    5
    dispatch()

    def dispatch(self, request, *args, **kwargs):
        # 当request 请求参数在自定义类属性self.http_method_names中
        if request.method.lower() in self.http_method_names:
            # 处理器 = 获取当前类的request.method.lower()值,默认获取值为self.http_method_not_allowed
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        # 或者请求参数不存在
        else:
            handler = self.http_method_not_allowed
        # handler = get/post/delete... 与上文类视图 处理请求类似
        return handler(request, *args, **kwargs)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    http_method_not_allowed()

    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 http.HttpResponseNotAllowed(self._allowed_methods())
    1
    2
    3
    4
    5
    6
    7
    8
    def _allowed_methods(self):
        return [m.upper() for m in self.http_method_names if hasattr(self, m)]
    1
    2
    get_template_names()
    有两个类(SingleObjectTemplateResponseMixin/TemplateResponseMixin )定义了该函数,按照MRO算法,此处使用的是SingleObjectTemplateResponseMixin中定义的get_template_names()

    ps: SingleObjectTemplateResponseMixin类继承自TemplateResponseMixin类

    def get_template_names(self):
    try:
        # 调用父类TemplateResponseMixin中的get_template_names()方法
        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 = []
        # 如果设置了self.template_name_字段,则获取该字段的值
        if self.object and self.template_name_field:
            name = getattr(self.object, self.template_name_field, None)
            if name:
                names.insert(0, name)
        # 仅当所讨论的对象是模型时才使用此选项
        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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    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())
    1
    2
    3
    4
    5
    6
    get_slug_field()

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

    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.
    """
    # 如果self.queryset属性 没有自定义
    if self.queryset is None:
        # 如果定义了 self.model 属性
        if self.model:
            # 返回模型类的所有查询集(_default_manager代表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()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    get_object()

    def get_object(self, queryset=None):
        """
        返回视图显示的对象。
        在url参数中要求 `self.queryset` and a `pk` or `slug` .
        S子类可以重写此项以返回任何对象。
        """
        # 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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    get_context_object_name()

    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
    1
    2
    3
    4
    5
    6
    7
    8
    get_context_data()

    同样有两个类(SingleObjectMixin/ContextMixin)实现了改方法 ,按照MRO,该方法属于SingleObjectMixin

    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)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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)
    1
    2
    3
    4
    render_to_response()

    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)
        # response_class =
        return self.response_class(
            request=self.request,
            template=self.get_template_names(),
            context=context,
            using=self.template_engine,
            **response_kwargs
        )
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    TemplateResponse: 标准的HttpResponse对象是静态构造的,TemplateResponse对象则是惰性构造的,它保持自己的所有上下文、模板用以构造真正的response,但只有在最后需要的时候才真正进行渲染。Django之通用类视图DetailView_Miles_sudo的博客-CSDN博客

  • 相关阅读:
    [附源码]计算机毕业设计人事系统Springboot程序
    都有哪些大厂有自己的Web组件库?
    C++面向对象——类与对象
    上传文件-读取excel文件数据
    rust学习(tokio协程分析一)
    【Android】获取手机上所有电话卡的运营商和信号强度
    新建vue-element项目
    VideoPipe可视化视频结构化框架开源了!
    关于OpenFeign 接口参数定义的问题
    【k8s集群搭建(二):基于虚拟机的linux的k8s集群搭建_超详细_可视化界面Dashboard安装_记录全过程踩坑记录及解决方法】
  • 原文地址:https://blog.csdn.net/qq_41048831/article/details/126546871