python工业互联网应用实战1—SQL与ORM
从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的更多相关文章
- python工业互联网应用实战2—从需求开始
前言:随着国家工业2025战略的推进,工业互联网发展将会提速,将迎来一个新的发展时期,越来越多的企业开始逐步的把产线自动化,去年年底投产的小米亦庄的智能工厂就是一个热议的新闻.小米/华为智能工厂只能说 ...
- python工业互联网应用实战3—模型层构建
本章开始我们正式进入到实战项目开发过程,如何从需求分析获得的实体数据转到模型设计中来,变成Django项目中得模型层.当然,第一步还是在VS2019 IDE环境重创建一个工程项目,本文我们把工程名称命 ...
- python工业互联网应用实战3—Django Admin列表
Django Admin笔者使用下来可以说是Django框架的开发利器,业务model构建完成后,我们就能快速的构建一个增删查改的后台管理框架.对于大量的企业管理业务开发来说,可以快速的构建一个可发布 ...
- python工业互联网应用实战7—业务层
本章我们演示代码是如何"进化"的,实战的企业日常开发过程中,系统功能总伴随着业务的不断增加,早期简单的代码慢慢的越来越复杂,敏捷编程中的"禅"--简单设计.快速 ...
- python工业互联网应用实战11—客户端UI
这个章节我们将演示用户端界面的开发,当前演示界面还是采用先实现基本功能再逐步完善的"敏捷"模式.首先聚焦在功能逻辑方面实现普通用户与系统的交互,普通用户通过url能查看到当前任务的 ...
- python工业互联网应用实战13—基于selenium的功能测试
本章节我们再来说说测试,单元测试和功能测试.单元测试我们在数据验证章节简单提过了,本章我们进一步如何用单元测试来测试view的功能代码:同时,也涉及一下基于selenium的功能测试做法.笔者过去的项 ...
- python工业互联网应用实战14——单元测试覆盖率
前面的章节我们完成了任务管理主要功能的开发及单元测试编写,可如何知道单元测试效果怎么样呢?测试充分吗?还有没有没有测到的地方呢? 本章节我们介绍一个统计测试代码覆盖率的利器Coverage,Cover ...
- python工业互联网应用实战15-前后端分离模式1
我们在13章节里通过监控界面讲了如何使用jquery的动态加载数据写法,通过简单案例来说明了如何实现动态的刷新监控界面的数据,本章我们将演示如何从Django模板加载数据逐步演化到前后端分离的异步数据 ...
- python工业互联网应用实战18—前后端分离模式之jquery vs vue
前面我们分三章来说明了使用django template与jquery的差别,通过jquery如何来实现前后端的分离,同时再9章节使用vue.js 我们浅尝辄止的介绍了JQuery到vue的切换,由于 ...
随机推荐
- 空间小姐姐生活照,我用python破解加密压缩包,无忧查看
事情的经过是这样的: 又是奶茶,行吧行吧. 快点开工,争取李大伟回来之前搞定. 李大伟说是6位数字密码 那么我们可以利用python生成全部的六位数字密码 #生成从000000到99999的密码表f ...
- SpringBoot系列(八)分分钟学会Springboot多种解决跨域方式
SpringBoot系列(八) 分分钟学会SpringBoot多种跨域解决方式 往期推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 s ...
- vue2.x学习笔记(二)
接着前面的内容:https://www.cnblogs.com/yanggb/p/12555836.html. 声明式渲染 vue的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进DOM的系统. ...
- Linux下nginx自启动配置
1.在linux系统的/etc/init.d/目录下创建nginx文件 vim /etc/init.d/nginx 在脚本中添加一下命令(内容主要参考官方文档) #!/bin/sh # # nginx ...
- Acid靶机渗透
Acid渗透靶机实战 攻击机:kali 192.168.41.147 靶机: acid 192.168.41.149 信息收集 ip发现 开启Acid靶机,通过nmap进行局域网存火主机扫描.函数 比如,你怎么把一个字符串转 ...
- Linux网络编程(2)
Preview 基于上一篇博客,本文将继续展开TCP面向连接的,客户端以及服务端各自需要进行的操作,我们按照真实TCP连接的顺序,分别阐述客户端socket(), connect()以及服务端sock ...