从sql到ORM应该说也是编程体系逐步演化的结果,通过类和对象更好的组织开个过程中遇到的各种业务问题,面向对象的解耦和内聚作为一套有效的方法论,对于复杂的企业应用而言确实能够解决实践过程中很多问题。

1.早期No ORM的做法

  这里先跟笔者回忆一下历史,在没有普及使用对象映射层之前,做企业业务系统开发通常是怎么做的呢?首先是不变的当然是需求分析,需求基本确定下来后,就是依据原始业务单据进行数据库表设计了,因为大量的企业信息化系统首先要干的第一件事情就是保存表单\保存表单\保存表单,笔者多年来干过的大量的事情就是保存表单 :( ,实现业务单据无纸化,单据数据保存到数据库表里,便于将来的查询、检索和统计分析。

1.1. 结构设计

  数据库表结构字段的设计和一些基础数据信息的设计,通常叫做数据字典。举例来说呢,比如系统要构建一个User的表,来存放用户基本信息,表设计如下图:

  我们通过数据管理工具Navicat连接前面demo创建的db.sqlite3文件数据库,运行创建User表的SQL我们就会看到表里面增加了一张User表,浏览表会看到还没有数据是一张空表。

CREATE TABLE "user" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"first_name" varchar(30),
"last_name" varchar(150),
"is_active" bool,
"remark" varchar(255)
);

  接下来为了便于演示,No ORM开发模式,执行下面的SQL表里插入一条记录。

INSERT INTO "main"."user"("id", "first_name", "last_name", "is_active", "remark") VALUES (1, 'ch', 'wu', '','a test user' );

  这里我们先演示通过SQL直接获取数据的方式来演示早期的编程模式,后面便于与ORM映射模式进行对比(没有对比就没有伤害)!Django同样也是可以通过SQL来load data的。

1.2. User View查看用户详情 

  首先,我们构建一个基于Django模板的UserView url来查看某个User Id 的数据详情,UserView.html代码如下:

<html>
<head>
<title>User Veiw</title>
</head>
<body>
<div>User Id: <strong>{{Id}}</strong></div>
<div>first Name : <strong>{{FirstName}}</strong></div>
<div>Last Name: <strong>{{LastName}}</strong></div>
<div>remark: <strong>{{Remark}}</strong></div>
</body>
</html>

  然后,在views 文件里添加函数userView返回UserView.html模板,userView代码如下:

from django.http import HttpRequest
def userView(request):
assert isinstance(request, HttpRequest)
return render(request,'Collector/UserView.html',\
{'Id':'','FirstName':'','LastName':'','Remark':'',})

  接着,项目urls发布userView,我们就可以再浏览器看到这个模板运行的效果,django web开发效率确实会快很多。

urlpatterns = [
# Uncomment the next line to enable the admin:
#path('admin/', admin.site.urls)
path('getTank4C9Data/', views.getTank4C9Data),
path('getCollectorData/', views.getCollectorData),
path('pushCollectorData/', views.pushCollectorData),
path('userView/', views.userView), ]

  浏览器运行效果:

2. SQL访问数据方式

  这一步,我们改进代码演示如何url如何传入UserId参数然后采用sql 从数据表读取这条记录,并通过django template系统渲染到UserView.html模板上,让页面变成一个动态加载的页面效果。 上代码:

from django.http import HttpRequest
import sqlite3
def userView(request):
assert isinstance(request, HttpRequest)
userId=request.GET.get('UserId') #获取UserId参数
if userId!=None:
#连接到数据库
db = sqlite3.connect('D:\my tfs\demo\source\CollectorSvr\db.sqlite3')
cursor = db.cursor() #创建一个游标
cursor.execute('select *from User where id={0}'.format(userId)) #执行SQL
rows =cursor.fetchall() #获取数据
row = rows[0]
db.close()
model={'Id':row[0] ,'FirstName':row[1],'LastName':row[2],'Remark':row[4] if row[4]!=None else '',}
else:
model={'Id':'','FirstName':'','LastName':'','Remark':'',}
return render(request,'Collector/UserView.html',model)

  代码解读:通过url请求的GET参数UserId 拼写本次要执行的SQL语句,然后通过数据游标返回执行SQL的结果,接着处理游标并封装到字典里,最后通过django模板渲染,最后运行效果如下http://127.0.0.1:8090/userView/?UserId=1

  userView运行效果实现了通过传入参数的方式,实现了从数据获取数据并显示再UI上的效果,但是过程中我们就的拼写SQL,如果是修改或者插入数据都需要编码拼写相应的SQL语句。编码过程中就有大量的编码工作是把UI提交的GET POST参数拼写成不同的SQL语句最后提交到数据库,由于不同的数据库有着不同的SQL语法,这导致了开发系统与数据库版本形成了强依赖关系,如果想把系统数据库从SQL SERVER迁移到Oracle就需要大量的测试和重新适配工作。

这样过了很多年,orm出现了...

3. Django Model 

  Django ORM对应的Django模型,Object Relational Mapping(对象关系映射),就是在面向对象模式编程中,把对象的模型跟数据库中表的对应起来。举例来说,一个业务对象类对应着一张表,类型属性对应表相应的字段。这个对象类的一个实例,对应着表中的一条记录,表里的一条条记录映射成对象后就是程序里一个个的对象。Django通过model来管理对象类和表之间的关系,并提供了一标准CRUD操作来满足数据操作的需求。

终于,可以哈哈一笑了

3.1. 数据库配置

  Django model我们可以使用强大的数据-模型语句,来描述我们的业务数据模型,下面我们开始来体验ORM的到底带来了什么。第一步首先是确认一下我们的demo project的数据库连接配置是否正确的指向了db.sqlite3数据库文件,查看project settings文件的配置是否如下代码:

# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}

  如果没有修改过应该时工程创建时的默认值。

  VS 2019 IDE环境中可以打开Open Django Shell命令窗口,执行下面的命令确认数据配置是否正确。

>>> from django.db import connection
>>> cursor = connection.cursor()
>>>

  如果没有显示什么错误信息,那么数据库配置是正确的。

  这里我们可以通过游标执行一下前面的SQL语句,看看再Django Shell的执行效果,先提一下Django Shell会给我们带来很多便利尤其再做一些探索性的编程和调试时,Django Shell也是笔者使用Python的最佳实践体会之一。

>>> from django.db import connection
>>> cursor = connection.cursor()
>>> cursor.execute('select *from User where id=1')
<django.db.backends.sqlite3.base.SQLiteCursorWrapper object at 0x03D5B240>
>>>
3.2. Model设计

  Django模型放在App的models文件里,现在我们在Collector/models定义模型吧,User模型的属性与数据表字段对照,为了更好的说明属性与表字段的对照关系,我们在模型里采用了column定义语法,User模型代码如下:

from django.db import models
# Create your models here. class User(models.Model):
Id=models.AutoField(primary_key=True,db_column='id')
FirstName = models.CharField(null=False,max_length=30,db_column='first_name')
LastName = models.CharField(null=False,max_length=150,db_column='last_name')
IsActive = models.NullBooleanField(null=True,db_column='is_active')
Remark = models.CharField(null=False,max_length=255,db_column='remark') class Meta:
db_table = 'user'

  接下来我们就可以在Django Shell里操作我们定义好的模型了,如下面的通过UserId=1获取一个User对象。

>>> from Collector.models import User
>>> model =User.objects.get(Id=1)
>>> print(model.LastName+model.FirstName)
wuch
>>>

  新增一个User对象

>>> user1=User()
>>> user1.FirstName ='xiaomin'
>>> user1.LastName='wang'
>>> user1.save()
>>>

  重新获取数据库表里Id=3对象

>>> user2=User.objects.get(Id=3)
>>> user2.FirstName
'xiaomin'

  更多丰富的查询接口...

>>> User.objects.all()
<QuerySet [<User: User object (1)>, <User: User object (3)>]>
>>> User.objects.get(LastName__startswith='Wu')
<User: User object (1)>
>>> User.objects.get(LastName__contains='wang')
<User: User object (3)>
3.3. 重构userView函数

  现在采用Django模型的方式来重构我们的UserView函数,从新的代码中你会看到返回值的赋值方式也从row[1] 改成了user.FirstName,对象属性的赋值方式大大的提高了代码的可读性和降低了赋值错误出错的概率。

from django.http import HttpRequest
from Collector.models import User
def userView(request):
assert isinstance(request, HttpRequest)
userId=request.GET.get('UserId') #获取UserId参数
if userId!=None:
user = User.objects.get(Id=userId)
model={'Id':user.Id ,'FirstName':user.FirstName,'LastName':user.LastName,'Remark':user.Remark if user.Remark!=None else '',}
else:
model={'Id':'','FirstName':'','LastName':'','Remark':'',}
return render(request,'Collector/UserView.html',model)

  现在调试运行效果一样了,没有SQL代码却简单很多,可读性也是

4. Model to Dict

  为了进一步的提高编程效率,直接把model转换成json返回格式的方式就进一步有效的降低代码量。这里采用model_to_dict来进行model到dict的转换,呵呵,你会觉得django怎么会这样简单啊,代码好少的说?代码越少可读性就越强,维护和扩展就越方便!

from django.http import HttpRequest
from Collector.models import User
from django.forms.models import model_to_dict
def userView(request):
assert isinstance(request, HttpRequest)
userId=request.GET.get('UserId') #获取UserId参数
if userId!=None:
user = User.objects.get(Id=userId)
else:
user=User()
model = model_to_dict(user)
return render(request,'Collector/UserView.html',model)

  最后我们再秀以下那个后台已经天翻地覆,UI端不变的显示界面。

5. 小节

  本章节是一个新的系列文章的开始,我们同样采用实战案例的方式和一些关键技术支出穿插的方式来介绍企业开发过程中常遇到的问题和实践经验总结。开篇第一章就介绍ORM和SQL获取数据的不同方式,主要是笔者近些年来使用Django的ORM实实在在的带来了开发效率的提升和业务变更的方便性,尤其企业开发过程中遇到的林林总总的“奇怪”需求面前,Python开发体系已经给笔者很多惊喜...。

python工业互联网应用实战1—SQL与ORM的更多相关文章

  1. python工业互联网应用实战2—从需求开始

    前言:随着国家工业2025战略的推进,工业互联网发展将会提速,将迎来一个新的发展时期,越来越多的企业开始逐步的把产线自动化,去年年底投产的小米亦庄的智能工厂就是一个热议的新闻.小米/华为智能工厂只能说 ...

  2. python工业互联网应用实战3—模型层构建

    本章开始我们正式进入到实战项目开发过程,如何从需求分析获得的实体数据转到模型设计中来,变成Django项目中得模型层.当然,第一步还是在VS2019 IDE环境重创建一个工程项目,本文我们把工程名称命 ...

  3. python工业互联网应用实战3—Django Admin列表

    Django Admin笔者使用下来可以说是Django框架的开发利器,业务model构建完成后,我们就能快速的构建一个增删查改的后台管理框架.对于大量的企业管理业务开发来说,可以快速的构建一个可发布 ...

  4. python工业互联网应用实战7—业务层

    本章我们演示代码是如何"进化"的,实战的企业日常开发过程中,系统功能总伴随着业务的不断增加,早期简单的代码慢慢的越来越复杂,敏捷编程中的"禅"--简单设计.快速 ...

  5. python工业互联网应用实战11—客户端UI

    这个章节我们将演示用户端界面的开发,当前演示界面还是采用先实现基本功能再逐步完善的"敏捷"模式.首先聚焦在功能逻辑方面实现普通用户与系统的交互,普通用户通过url能查看到当前任务的 ...

  6. python工业互联网应用实战13—基于selenium的功能测试

    本章节我们再来说说测试,单元测试和功能测试.单元测试我们在数据验证章节简单提过了,本章我们进一步如何用单元测试来测试view的功能代码:同时,也涉及一下基于selenium的功能测试做法.笔者过去的项 ...

  7. python工业互联网应用实战14——单元测试覆盖率

    前面的章节我们完成了任务管理主要功能的开发及单元测试编写,可如何知道单元测试效果怎么样呢?测试充分吗?还有没有没有测到的地方呢? 本章节我们介绍一个统计测试代码覆盖率的利器Coverage,Cover ...

  8. python工业互联网应用实战15-前后端分离模式1

    我们在13章节里通过监控界面讲了如何使用jquery的动态加载数据写法,通过简单案例来说明了如何实现动态的刷新监控界面的数据,本章我们将演示如何从Django模板加载数据逐步演化到前后端分离的异步数据 ...

  9. python工业互联网应用实战18—前后端分离模式之jquery vs vue

    前面我们分三章来说明了使用django template与jquery的差别,通过jquery如何来实现前后端的分离,同时再9章节使用vue.js 我们浅尝辄止的介绍了JQuery到vue的切换,由于 ...

随机推荐

  1. L8梯度消失、梯度爆炸

    houseprices数据下载: 链接:https://pan.baidu.com/s/1-szkkAALzzJJmCLlJ1aXGQ 提取码:9n9k 梯度消失.梯度爆炸以及Kaggle房价预测 代 ...

  2. python os模块获取指定目录下的文件列表

    bath_path = r"I:\ner_results\ner_results" dir_list1 = os.listdir(bath_path) for dir1 in di ...

  3. TensorFlow-keras 100分类

    import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' from tensorflow.python.keras.datasets import cifa ...

  4. Ubuntu创建WiFi:16.0.4

    点击编辑链接,点击桌面状态栏的网络图标 点击增加 类型选择WiFi 名称.SSID,均要填写,模式选择:热点 wifi安全性:选择一个安全模式,这里选的是, wpa 及 wpa2个人 必须说的是:选择 ...

  5. tp3.2的__construct和_initialize方法

    在tp3.2框架里面,有一个php自带的__construct()构造函数和tp3自带的构造函数_initialize()的实行顺序是先实行 php自带的__construct()构造函数 再实行 t ...

  6. Zabbix3.0安装部署最佳实践

    Zabbix介绍 1.1zabbix 简介 Zabbix 是一个高度集成的网络监控解决方案,可以提供企业级的开源分布式监控解决方案,由一个国外的团队持续维护更新,软件可以自由下载使用,运作团队靠提供收 ...

  7. OC的消息机制简单介绍

    在OC的消息机制中主要分为三个阶段,分别为: 1.消息发送阶段:从类以及父类的方法缓存列表和方法列表查找方法. 2.动态解析阶段:在消息发送阶段没有找到方法,则会进入这个阶段,负责动态添加方法实现. ...

  8. 【JAVA基础】05 Java语言基础:数组

    1. 数组概述和定义格式说明 为什么要有数组(容器) 为了存储同种数据类型的多个值 数组概念 数组是存储同一种数据类型多个元素的集合.也可以看成是一个容器. 数组既可以存储基本数据类型,也可以存储引用 ...

  9. 字符串translate方式实现

    在爬取百度图片的时候,发现百度图片做了反爬虫处理,在网上找到当前还能跑通的教程实例:python3多线程下载百度图片搜索结果. 在分析代码的过程中,发现作者对爬取的objURL的解码是通过字符串的tr ...

  10. 外媒解读Web安全核心PKI的四大致命问题

    Web安全的立足根基在于复杂的PKI部署体系,但实际生活中得到正确部署的比例却非常有限,而且这一切都将随着摩尔定律的滚滚洪流灰飞烟灭. 我个人算是PKI(即公共密钥基础设施)的忠实拥护者.我热爱数学与 ...