-
Notifications
You must be signed in to change notification settings - Fork 72
/
Copy pathdemo_geoalchemy.py
executable file
·101 lines (76 loc) · 2.89 KB
/
demo_geoalchemy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#
# Implementation using geoalchemy column types
# Documentation:
# https://github.com/thomaxxl/safrs/wiki/Postgis-Geoalchemy2
#
import json
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import func
from geoalchemy2 import Geometry
from flask_sqlalchemy import SQLAlchemy
from safrs import SAFRSBase, SafrsApi
from safrs.json_encoder import SAFRSJSONEncoder
from geoalchemy2.shape import from_shape, to_shape
from shapely.geometry import shape
from shapely import geometry
from geoalchemy2.elements import _SpatialElement
app = Flask(__name__)
db = SQLAlchemy()
class GeoJSONEncoder(SAFRSJSONEncoder):
"""
json encode geometry shapes
"""
def default(self, obj, **kwargs):
if isinstance(obj, _SpatialElement):
result = geometry.mapping(to_shape(obj))
return result
return super().default(obj, **kwargs)
class GeometryColumn(db.Column):
"""
The class attributes are used for the swagger
"""
description = "Geo column description"
swagger_type = "json"
swagger_format = "json"
sample = {"coordinates": [-122.43129, 37.773972], "type": "Point"}
class City(SAFRSBase, db.Model):
"""
A city, including its geospatial data
"""
__tablename__ = "cities"
point_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
location = db.Column(db.String(30), default="Gotham City")
geo = GeometryColumn(Geometry(geometry_type="POINT", srid=25833, dimension=2))
def ___init__(self, *args, **kwargs):
# convert the json to geometry database type
# (this can be implemented in the GeometryColumn type.python_type too)
geo = kwargs.get("geo")
kwargs["geo"] = str(to_shape(from_shape(geometry.shape(geo))))
super().__init__(*args, **kwargs)
def __repr__(self):
return f"<City {self.location}"
__str__ = __repr__
def get_cities_within_radius(self, radius):
"""Return all cities within a given radius (in meters) of this city."""
return City.query.filter(func.ST_Distance_Sphere(City.geo, self.geo) < radius).all()
def connect_to_db(app):
"""Connect the database to Flask app."""
app.config["SQLALCHEMY_DATABASE_URI"] = "postgres:///testgis"
app.config["SQLALCHEMY_ECHO"] = False
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db.app = app
db.init_app(app)
def create_api(app, HOST="localhost", PORT=5000, API_PREFIX=""):
api = SafrsApi(app, host=HOST, port=PORT, prefix=API_PREFIX, json_encoder=GeoJSONEncoder)
api.expose_object(City)
print(f"Starting API: http://{HOST}:{PORT}/{API_PREFIX}")
if __name__ == "__main__":
connect_to_db(app)
db.create_all()
host = "192.168.235.136"
with app.app_context():
create_api(app, host, 5555)
for city in City.query.all():
pass # print(city, city.location)
app.run(host=host, port=5555)