专栏首页Python in AI-IOT高质量代码-智慧城市GIS平台后端代码
原创

高质量代码-智慧城市GIS平台后端代码

高质量代码-智慧城市GIS平台数据表设计》一文介绍了项目中的数据库表设计。此文介绍优良合理的表设计给后端接口开发带来的便利性。

整个后端使用Python语言开发,tornado作为web框架peewee作为ORM和数据库打交道。下面展示利用peewee操作数据库(读取)是多么的简单。

使用peewee定义表,注意ForeignKeyFieldbackref的用法

# -*- coding:utf-8 -*-
from peewee import *

from datetime import date,datetime
import itertools

db=SqliteDatabase('gis.db')
class BaseModel(Model):
    class Meta:
        database=db
class Station(BaseModel):
    name=CharField(null = False)
    address=CharField(null = True)
    latitude=DoubleField(null = True)
    longitude=DoubleField(null = True)
    x=DoubleField(null = True)
    y=DoubleField(null = True)
    
class Meter(BaseModel):
    name=CharField(null=True)
    unit=CharField(null=True)
class Species(BaseModel):
    name=CharField(null=True)


class Monitor(BaseModel):
    station=ForeignKeyField(Station,backref='monitors')
    species=ForeignKeyField(Species,backref='monitors')   
class MonitorMeter(BaseModel):
    monitor=ForeignKeyField(Monitor,backref='meters')
    meter=ForeignKeyField(Meter,backref='monitors')    
 
class Data(BaseModel):
    monitor=ForeignKeyField(Monitor,backref='data')
    meter=ForeignKeyField(Meter,backref='data')
    value=DoubleField(null=True)
    timestamp=DateTimeField(null=True)

class WaterSupplyPipe(BaseModel):
    ShpID=BigIntegerField(null=True)
    Diameter=DoubleField(null=True)
    Depth=DoubleField(null=True)
    Material=CharField(null=True)
#选择Station表所有记录
result=Station.Select()
#打印结果记录数量
print result.count()
#打印结果
for i in result:
    print i.name,i.x,i.y
#将结果直接以json格式打印出来
print list(r.dicts())

#关联Monitor和Station和Species,注意select,switch,join,alias的用法
result=Monitor.select(Station.name.alias('stationName'),Species.name.alias('speciesName'))\
.join(Station).switch(Monitor).join(Species)
#打印peewee生成的sql语句
print result.sql()

#根据名字模糊搜索Station表
Station.select().where(Station.name.contains("厂"))

下面再演示稍微复杂的查询语句,注意group_by,order_by,以及fn.MAX,fn.MIN聚合函数使用。

#查询所有流量监测站监测到的最新的电压数据,并关联地理站点表方便地图展示。
result=Monitor.select(Station.name.alias('stationName'),Station.x.alias('stationX'),
Station.y.alias('stationY'),fn.MAX(Data.timestamp).alias('dataTimestamp'),Data.value.alias('dataValue'))
.join(Station).switch(Monitor).join(Data).join(Meter).where(Meter.name=='Pressure')
.switch(Monitor).join(Species).where(Species.name=='flowStations').group_by(Monitor.id)
#将日期数据格式化
result=map(lambda x:convertDate(x),result.dicts())

def convertDate(x):
    x['dataTimestamp']=datetime.strftime(x['dataTimestamp'],'%Y-%m-%d %H:%M:%S')
    return x

下面定义一个函数,函数参数是由web请求的参数传递过来的,然后以标准的geoJson格式将最终结果返回,注意为了防止一个语句太长不方便阅读和条件判断,我们将sql语句的每个过程分开写,但是还是生成一句sql语句在获取数据结果时执行。耐心看每个过程的使用,为了将数据转化为geojson中的feature,而且要将表中最终Data表数据转化为feature["properties"],即[{'meterName':'Pressure','dataValue':500},{'meterName':'Voltage','value':500}]转为

{'properties':{'Pressure':500,'Voltage':500} },所以我们使用了辅助函数convertFeatures和convertFeature

转为def getMonitorDataBySpecies(species,search,limit,offset):
    #print search,limit,offset
    
    result=Monitor.select(Species.name.alias('speciesName'),Monitor.id.alias('monitorId'),
    Station.name.alias('stationName'),Meter.name.alias('meterName'),Station.x.alias('stationX'),
    Station.y.alias('stationY'),fn.MAX(Data.timestamp).alias('dataTimestamp'),
    Data.value.alias('dataValue')).join(Station)
    print result.count()
    if search!='':
        result=result.where(Station.name.contains(search))
        print result.count()
    result=result.switch(Monitor).join(Data).join(Meter).switch(Monitor).join(Species)
    print result.count()
    if species!='ALL':
        result=result.where(Species.name==species)
        print result.count()
    result=result.group_by(Monitor.id,Meter.id)
    print result.count()
   
    result=map(lambda x:convertDate(x),result.dicts())
    print len(result)
    #这里使用自定义的分页,而不是sql语句的分页
    result=convertFeatures(result)[offset:limit+offset]
    print len(result)
    result=renderGeoJson('GeoJsonTemplate.txt',result)
    
    return result

def convertFeatures(data):
    data=sorted(data,key=lambda x:x['monitorId'])
    gpData=itertools.groupby(data,lambda x:x['monitorId'])
    groups=[]
    for k,g in gpData:
        
        groups.append(convertFeature(list(g)))
    return groups

def convertFeature(data):
    if(len(data)<0):
        return {}
    item=data[0].copy()
    fields=['meterName','dataValue']
    item['x']=item['stationX']
    item['y']=item['stationY']
    
    for field in fields:
        if item.has_key(field):
            item.pop(field)
    
    properties=dict(map(lambda x:[x[fields[0]],x[fields[1]]],data))
    
    item.update(properties)
    
    return item

tornado web框架中对应的调用

class getRecentMonitorGeoJsonHandler(cross_originAllowed_Handler):
    def get(self,species):
        self.write('success')

    def post(self,species):
        search=self.get_argument('search','')
        limit=self.get_argument('limit',10)
        offset=self.get_argument('offset',0) 
        #print search
        result=dbTools.getMonitorDataBySpecies(species,search.strip(),int(limit),int(offset))
        self.write(result)

这里使用模板来生成geoJson,模板txt如下:

{"type":"FeatureCollection",
"features":[
{% for i in range(len(data)) %}
	{"type":"Feature",
	"geometry":{
		"type":"Point",
		"coordinates":[{{data[i]['x']}},{{data[i]['y']}}]
		},
	"properties":	{% raw json.dumps(data[i]) %}
	} {% if i<len(data)-1 %} ,{% else %} {% end %}
{% end %}
]}

生成的geoJson数据如下结构:

感谢Python,才使得这些如此容易。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python开发---试用OCR文字识别API

    AI如今发展迅速,各云厂商对通用的人脸识别,文字识别,语音识别和语音合成提供了接口。在日常中有些小场景还是可以用到这些通用AI接口使平台或软件锦上添花的。

    MiaoGIS
  • 高质量编码--使用Pandas查询日期文件名中的数据

    代码如下,其中subDirTimeFormat,fileTimeFormat,requestTimeFormat分别来指定文件夹解析格式,文件解析格式,以及查询...

    MiaoGIS
  • Python开发---使用subprocess从命令行程序获取数据

    发现一个简单的解决不同语言开发的程序之间调用对方函数获取数据的方法,就是使用命令行作为数据流的接口。

    MiaoGIS
  • Python2运行时查看线程信息

    kongxx
  • python+shell 备份 csdn 博客文章

    前面,我们将所有的博客文章全部备份下来了。但是,博客当中的那些图片,还是散落在各处。有的在第三方的网站上,有的在 CSDN 的服务器上,有的直接引用的其他地方的...

    FungLeo
  • 彻底搞懂 python 中文乱码问题(深入分析)

    前言 曾几何时 Python 中文乱码的问题困扰了我很多很多年,每次出现中文乱码都要去网上搜索答案,虽然解决了当时遇到的问题但下次出现乱码的时候又会懵逼,究其...

    砸漏
  • CDA第八届认证考试数据报告发布!

    CDA数据分析师认证考试在每年的6月与12月最后一个周末进行,一年两次。第八届(2018年6月)CDA考试现已结束,本次考试在全国21所考试中心顺利进行,共完成...

    CDA数据分析师
  • Struts2框架的基本使用(二)

         上一篇 Struts2框架的基本使用 我们限于篇幅,最后简单介绍了Action的配置问题,本篇接着介绍有关框架的一些其他基本用法,主要内容如下: Ac...

    Single
  • 基于Opendaylight的packet-in flooding攻击的检测与防护

    作者简介:智智方,西安电子科技大学硕士研究生,主要研究方向为SDN与网络安全,邮箱:675520574@qq.com

    SDNLAB
  • Web 后端--PHP 与数据库的交互

             用 PHP  操作 MySQL ,实现数据的交换,还要多练练....

    书童小二

扫码关注云+社区

领取腾讯云代金券