Django商城的数据业务处理


目录:

商城的数据业务处理

​ 视图(Views)是Django的MTV架构模式的V部分,主要负责处理用户请求和生成相应的响应内容,然后在页面或其他类型文档中显示。也可以理解为视图是MVC架构里面的C部分(控制器),主要处理功能和业务上的逻辑。我们习惯使用视图函数处理HTTP请求,即在视图里定义def函数,这种方式称为FBV(Function Base Views)。

​ Web开发是一项无聊而且单调的工作,特别是在视图功能编写方面更为显著。为了减少这种痛苦,Django植入了视图类这一功能,该功能封装了视图开发常用的代码,无须编写大量代码即可快速完成数据视图的开发,这种以类的形式实现响应与请求处理称为CBV(Class Base Views)。

首页的视图函数

​ 由于项目应用index的urls.py的路由index设置视图函数名为indexView,因此在项目应用index的views.py定义视图函数indexView,定义过程如下:

image-20220208090928296

上述代码中,视图函数indexView一共定义了7个变量,每个变量的作用说明如下:

​ (1)变量title是设置网页标签内容,即HTML的title标签文本内容,该变量将会在模板中使用。

(2)变量classContent是控制网页导航栏的样式,比如当前网页为首页,导航栏的“首页”应设置样式为class="active",如图5-1所示。以此类推,如果网页为购物车页面,导航栏的“购物车”的样式设为class="active"。

image-20220208091039373

(3)变量commodityInfos是查询模型CommodityInfos销量最高的前8条数据,这些数据将显示在首页的“今日必抢”栏目中。

(4)变量types是查询模型Types的所有数据,用于变量cl、fl和gl的数据筛选。

(5)变量cl是在变量types的基础上,对变量types的数据进行筛选,获取字段firsts等于“儿童服饰”的所有数据,并以列表格式表示。(6)变量clothes是将变量cl作为模型CommodityInfos的查询条件,符合条件的数据按销量排序并获取前5条数据,这些数据将显示在首页的“宝宝服饰”栏目。

(7)变量fl是在变量types的基础上,对变量types的数据进行筛选,获取字段firsts等于“奶粉辅食”的所有数据,并以列表格式表示。(8)变量food是将变量fl作为模型CommodityInfos的查询条件,符合条件的数据按销量排序并获取前5条数据,这些数据将显示在首页的“奶粉辅食”栏目。

(9)变量gl是在变量types的基础上,对变量types的数据进行筛选,获取字段firsts等于“儿童用品”的所有数据,并以列表格式表示。(10)变量goods是将变量gl作为模型CommodityInfos的查询条件,符合条件的数据按销量排序并获取前5条数据,这些数据将显示在首页的“宝宝用品”栏目。

最后视图函数indexView使用return设置函数的返回值,只要是Django的视图函数,它必须要设置返回值,其作用是将函数中定义的变量传递给模板,然后由模板引擎对这些变量进行解析并渲染到网页上。

视图的请求对象

请求方式

image-20220208091256513

  • GET请求的请求参数是在路由地址后添加“?”和参数内容,参数内容以key=value形式表示,等号前面的是参数名,后面的是参数值,如果涉及多个参数,每个参数之间就使用“&”隔开,如127.0.0.1:8000/?user=xy&pw=123。

  • POST请求的请求参数一般以表单的形式传递,常见的表单使用HTML的form标签,并且form标签的method属性设为POST。

Request对象

对于Django来说,当它接收到HTTP请求之后,会根据HTTP请求携带的请求参数以及请求信息来创建一个WSGIRequest对象,并且作为视图函数的首个参数,这个参数通常写成request。(django\core\handlers\wsgi.py)

下面对一些常用的属性进行说明。

  • COOKIE:获取客户端(浏览器)的Cookie信息,以字典形式表示,并且键值对都是字符串类型。
  • FILES:django.http.request.QueryDict对象,包含所有的文件上传信息。
  • GET:获取GET请求的请求参数,它是django.http.request.QueryDict对象,操作起来类似于字典。
  • POST:获取POST请求的请求参数,它是django.http.request.QueryDict对象,操作起来类似于字典。META:获取客户端(浏览器)的请求头信息,以字典形式存储。
  • method:获取当前请求的请求方式(GET请求或POST请求)。
  • path:获取当前请求的路由地址。
  • session:一个类似于字典的对象,用来操作服务器的会话信息,可临时存放用户信息。
  • user:当Django启用AuthenticationMiddleware中间件时才可用。它的值是内置数据模型User的对象,表示当前登录的用户。如果用户当前没有登录,那么user将设为django.contrib.auth.models.AnonymousUser的一个实例。

由于类WSGIRequest继承并重写类HttpRequest,因此类HttpRequest里定义的类方法同样适用于类WSGIRequest。类HttpRequest一共定义了31个类方法,我们选择一些常用的方法进行讲述。

  • is_secure():是否采用HTTPS协议。
  • is_ajax():是否采用Ajax发送HTTP请求。判断原理是请求头中是否存在X-Requested-With:XMLHttpRequest。
  • get_host():获取服务器的域名。如果在访问的时候设有端口,就会加上端口号,如127.0.0.1:8000。
  • get_full_path():返回路由地址。如果该请求为GET请求并且设有请求参数,返回路由地址就会将请求参数返回,如/?user=xy&pw=123。
  • get_raw_uri():获取完整的网址信息,将服务器的域名、端口和路由地址一并返回,如http://127.0.0.1:8000/?user=xy&pw=123。

image-20220208094703932

视图的响应方式

响应类

image-20220208094827490image-20220208094856889

​ 视图函数index使用响应类HttpResponse实现响应过程。从HttpResponse的参数可知,第一个参数是响应内容,一般是网页内容或JSON数据,网页内容是以HTML语言为主的,JSON数据用于生成API接口数据。第二个参数用于设置HTTP状态码,它支持HTTP所有的状态码。

​ 从HttpResponse的使用过程可知,如果要生成网页内容,就需要将HTML语言以字符串的形式表示,如果网页内容过大,就会增加视图函数的代码量,同时也没有体现模板的作用。因此,Django在此基础上进行了封装处理,定义了函数render、render_to_response和redirect。

​ render的参数request和template_name是必需参数,其余的参数是可选参数。各个参数说明如下:

  • request:浏览器向服务器发送的请求对象,包含用户信息、请求内容和请求方式等。

  • template_name:设置模板文件名,用于生成网页内容。

  • context:对模板上下文(模板变量)赋值,以字典格式表示,默认情况下是一个空字典。

  • content_type:响应内容的数据格式,一般情况下使用默认值即可。

  • status:HTTP状态码,默认为200。using:设置模板引擎,用于解析模板文件,生成网页内容。

    从render的参数看到,参数context是将视图函数的变量传递给模板引擎,再由模板引擎解析这些变量并展示在网页上。在实际开发过程中,如果视图传递的变量过多,在设置参数context时就显得非常冗余,而且不利于日后的维护和更新。因此,可以使用Python内置语法locals()取代参数context,比如5.1节定义的视图函数indexView,该函数是使用locals()取代参数context。

image-20220208095138644

函数render的返回值调用响应类HttpResponse来生成具体的响应内容,这说明响应类HttpResponse是Django在响应过程中核心的功能类。结合render源码进一步阐述render读取模板文件的运行过程:(1)使用loader.render_to_string方法读取模板文件内容。

(2)由于模板文件设有模板上下文,因此模板文件解析网页内容的过程需要由模板引擎using实现。

(3)解析模板文件的过程中,loader.render_to_string的参数context给模板语法的变量提供具体的数据内容,若模板上下文在该参数里不存在,则对应的网页内容为空。

(4)调用响应类HttpResponse,并将变量content(模板文件的解析结果)、变量content_type(响应内容的数据格式)和变量status(HTTP状态码)以参数形式传入HttpResponse,从而完成响应过程。

​ 综上所述,我们介绍了Django的响应类,比如HttpResponse、HttpResponseRedirect和HttpResponseNotFound等,其中最为核心的响应类是HttpResponse,它是所有响应类的基础。在此基础上,Django还进一步封装了响应函数render,该函数能直接读取模板文件,并且能设置多种响应方式(设置不同的HTTP状态码)。

认识视图类

​ 视图类是通过定义和声明类的形式实现的,根据用途划分3部分:数据显示视图、数据操作视图和日期筛选视图。

​ 数据显示视图是将后台的数据展示在网页上,数据主要来自模型,一共定义了4个视图类,分别是RedirectView、TemplateView、ListView和DetailView,说明如下:

  • RedirectView用于实现HTTP重定向,默认情况下只定义GET请求的处理方法。

  • TemplateView是视图类的基础视图,可将数据传递给HTML模板,默认情况下只定义GET请求的处理方法。

  • ListView是在TemplateView的基础上将数据以列表显示,通常将某个数据表的数据以列表表示。

  • DetailView是在TemplateView的基础上将数据详细显示,通常获取数据表的单条数据。

数据操作视图是对模型进行操作,如增、删、改,从而实现Django与数据库的数据交互。数据操作视图有4个视图类,分别是FormView、CreateView、UpdateView和DeleteView,说明如下:

  • FormView视图类使用内置的表单功能,通过表单实现数据验证、响应输出等功能,用于显示表单数据。
  • CreateView实现模型的数据新增功能,通过内置的表单功能实现数据新增。
  • UpdateView实现模型的数据修改功能,通过内置的表单功能实现数据修改。
  • DeleteView实现模型的数据删除功能,通过内置的表单功能实现数据删除。

日期筛选视图是根据模型里的某个日期字段进行数据筛选的,然后将符合结果的数据以一定的形式显示在网页上。简单来说,在列表视图ListView或详细视图DetailView的基础上增加日期筛选所实现的视图类。它一共定义了7个日期视图类,说明如下:

  • ArchiveIndexView是将数据表所有的数据以某个日期字段的降序方式进行排序显示的。
  • YearArchiveView是在数据表筛选某个日期字段某年的所有的数据,默认以升序的方式排序显示,年份的筛选范围由路由变量提供。
  • MonthArchiveView是在数据表筛选某个日期字段某年某月的所有的数据,默认以升序的方式排序显示,年份和月份的筛选范围都由路由变量提供。
  • WeekArchiveView是在数据表筛选某个日期字段某年某周的所有的数据,总周数是将一年的总天数除以7所得的,数据默认以升序的方式排序显示,年份和周数的筛选范围都是由路由变量提供的。
  • DayArchiveView是对数据表的某个日期字段精准筛选到某年某月某天,将符合条件的数据以升序的方式排序显示,年份、月份和天数都是由路由变量提供的。
  • TodayArchiveView是在视图类DayArchiveView的基础上进行封装处理的,它将数据表某个日期字段的筛选条件设为当天时间,符合条件的数据以升序的方式排序显示。

从日期筛选视图类的继承关系得知,它们的继承关系都有一定的相似之处,说明它们的属性和方法在使用上不会存在太大的差异。因此,我们选择最有代表性的视图类MonthArchiveView和WeekArchiveView进行讲述,在日常开发中,这两个日期视图类通常用于开发报表功能(月报表和周报表)。

使用视图类实现商城首页

​ 虽然视图类分为数据显示视图、数据操作视图和日期筛选视图,每种类型的视图类适合特定的使用场景,比如用户的注册登录功能则适合使用数据操作视图,财务报表则适合使用日期筛选视图,商品展示则适用使用数据显示视图。

​ 我们在项目babys的项目应用index的views.py定义了视图函数indexView,该视图函数主要是查询模型Types和CommodityInfos的数据信息,将这些数据信息传递给模板引擎并展示在网页上,因此,我们还可以使用数据显示视图的TemplateView类实现商城首页的业务逻辑处理。

​ 由于商城首页的数据展示没有实现分页展示,并且数据无须详细展示出来,因此该网页不适合使用视图类ListView和DetailView。视图类TemplateView是所有视图类里最基础的应用视图类,开发者可以直接调用应用视图类,它继承多个父类: TemplateResponseMixin、ContextMixin和View。在PyCharm里查看视图类TemplateView的源码,如图5-10所示。

image-20220208100536741

​ 从视图类TemplateView的源码看到,它只定义了类方法get(),该方法分别调用函数方法get_context_data()和render_to_response(),从而完成HTTP请求的响应过程。类方法get()所调用的函数方法主要来自父类TemplateResponseMixin和ContextMixin,为了准确地描述函数方法的调用过程,我们以流程图的形式加以说明,如图5-11所示。

​ 视图类TemplateView的get()所调用的函数说明如下:

​ 视图类ContextMixin的get_context_data()方法用于获取模板上下文内容,模板上下文是将视图里的数据传递到模板文件,再由模板引擎将数据转换成HTML网页数据。视图类TemplateResponseMixin的render_to_response()用于实现响应处理,由响应类TemplateResponse完成。

image-20220208100718974

​ 我们可以在视图类TemplateView的源码文件里找到视图类TemplateResponseMixin的定义过程,该类设置了4个属性和两个类方法,这些属性和类方法说明如下:

  • template_name:设置模板文件的文件名。

  • template_engine:设置解析模板文件的模板引擎。

  • response_class:设置HTTP请求的响应类,默认值为响应类TemplateResponse。

  • content_type:设置响应内容的数据格式,一般情况下使用默认值即可。

  • render_to_response():实现响应处理,由响应类TemplateResponse完成。

  • get_template_names():获取属性template_name的值。

    从源码角度分析了视图类TemplateView的定义过程,接下来使用视图类TemplateView实现商城首页的业务逻辑,在项目应用index的urls.py重新定义路由index,代码如下:

image-20220208100816403

我们将路由index改为视图类indexClassView,如果路由的视图为视图类,视图类必须由调用函数方法as_view(),这是对视图类进行实例化处理。下一步在项目应用index的views.py定义视图类indexClassView,定义过程如下:

image-20220208101121324

视图类indexClassView重新定义了4个类属性和3个类方法,每个属性和方法的说明如下:

​ (1)属性template_name设置模板文件名,网页内容由模板文件index.html生成。

​ (2)属性template_engine设置解析模板文件的模板引擎,属性值为None则默认使用配置文件settings.py的TEMPLATES的BACKEND所设置的模板引擎。

​ (3)属性content_type设置响应内容的数据格式,属性值为None则使用text/html作为响应内容的数据格式。

​ (4)属性extra_context来自视图类ContextMixin,这是为模板文件设置额外变量。在模板文件中可能会使用多个不同的变量,而这些变量是在视图中定义生成的,我们只需将这些变量以字典格式表示并赋值给属性extra_context即可。一般情况下,如果变量的值比较固定或具有规律性,笔者建议写入属性extra_context。

​ (5)方法get_context_data()是获取属性extra_context的值,如果某些变量具有动态变化或者需要复杂的处理逻辑,可以在此方法里面动态添加这些变量,比如查询模型数据、数据的算法处理等。

​ (6)方法get()定义HTTP的GET请求处理方法,参数request代表HTTP请求信息,可以从该参数中获取用户的请求信息;该方法调用方法get_context_data(),获取整个视图所有变量并赋值给context,然后将context传递给render_to_response()方法,从而完成整个GET请求和响应过程。

​ (7)方法post()与方法get()的业务逻辑相似,该方法是处理POST请求和响应过程。综合上述,视图类是通过类继承以及属性方法的重写来实现业务逻辑处理,Django内置视图类都是继承类TemplateResponseMixin、ContextMixin和View,某些视图在继承过程中可能继承多个父类,比如视图类ListView,它的继承过程如图5-12所示。

image-20220208103230950

​ 我们在学习Django内置视图类的时候,必须梳理视图类的继承过程,并归纳类属性和类方法的定义和重写过程,这样才能掌握每个内置视图类的使用方法。