前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >高质量代码-智慧城市GIS平台后端代码

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

原创
作者头像
MiaoGIS
修改2019-03-08 14:33:56
1.3K0
修改2019-03-08 14:33:56
举报
文章被收录于专栏:Python in AI-IOTPython in AI-IOT

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

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

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

代码语言:python
复制
# -*- 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)
代码语言:python
复制
#选择Station表所有记录
result=Station.Select()
#打印结果记录数量
print result.count()
#打印结果
for i in result:
    print i.name,i.x,i.y
#将结果直接以json格式打印出来
print list(r.dicts())

代码语言:python
复制
#关联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()

代码语言:python
复制
#根据名字模糊搜索Station表
Station.select().where(Station.name.contains("厂"))

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

代码语言:python
复制
#查询所有流量监测站监测到的最新的电压数据,并关联地理站点表方便地图展示。
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

代码语言:python
复制
转为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框架中对应的调用

代码语言:python
复制
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如下:

代码语言:python
复制
{"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,才使得这些如此容易。

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档