This commit is contained in:
Schuyler Erle 2011-08-31 11:17:36 +02:00
commit c5501c7ff6
2 changed files with 40 additions and 17 deletions

View File

@ -24,16 +24,23 @@ class FeatureSearchManager(models.GeoManager):
cursor = connection.cursor()
cursor.execute("""SELECT set_limit(%f)""" % threshold)
def overlaps(self, (minx, miny, maxx, maxy), text=None, srid=4326):
bbox = Polygon(((minx,miny),(minx,maxy),(maxx,maxy),(maxx,miny),(minx,miny)),srid=srid)
if srid != 4326: bbox.transform(4326) # convert to lon/lat
qset = models.GeoManager.get_query_set(self).filter(geometry__bboverlaps=bbox)
def find(self, bbox=None, text=None, adm1=None, adm2=None srid=4326):
qset = self.get_query_set()
if bbox:
(minx, miny, maxx, maxy) = bbox
bbox = Polygon(((minx,miny),(minx,maxy),(maxx,maxy),(maxx,miny),(minx,miny)),srid=srid)
if srid != 4326: bbox.transform(4326) # convert to lon/lat
qset = qset.filter(geometry__bboverlaps=bbox)
if text:
text = text.replace("'", "''") # escape the '
# use the pg_trgm index
qset = qset.extra(select={"similarity":"similarity(preferred_name, '%s')" % text},
where=["preferred_name %%%% '%s'" % text],
qset = qset.extra(select={"similarity":"similarity(preferred_name, '%s')"},
select_params=[text],
where=["preferred_name %% '%s'"],
params=[text],
order_by=["-similarity"])
if adm1: qset = qset.filter(admin1__exact=adm1)
if adm2: qset = qset.filter(admin2__exact=adm2)
return qset
class Feature(models.Model):
@ -41,8 +48,8 @@ class Feature(models.Model):
url = models.CharField(max_length=512, unique=True, verbose_name="URI")
preferred_name = models.CharField(max_length=512)
feature_type = models.ForeignKey("FeatureType", null=True, blank=True)
admin1 = models.CharField(max_length=2, blank=True, verbose_name="State")
admin2 = models.CharField(max_length=255, blank=True, verbose_name="County")
admin1 = models.CharField(max_length=2, blank=True, verbose_name="State", db_index=True)
admin2 = models.CharField(max_length=255, blank=True, verbose_name="County", db_index=True)
geometry = models.GeometryField()
is_primary = models.BooleanField(default=True)
time_frame = models.ForeignKey("TimeFrame", null=True, blank=True)
@ -60,8 +67,8 @@ class Feature(models.Model):
return self.feature_type.name.title()
feature_type_name.short_description = "Feature Type"
def get_geojson(self):
geom = json.loads(self.geometry.transform(3785, True).geojson)
def get_geojson(self, srid=4326):
geom = json.loads(self.geometry.transform(srid, True).geojson)
if self.feature_type is None:
feature_type = ''

View File

@ -10,15 +10,31 @@ def search(request):
def search_json(request):
search_term = request.GET.get("search", "")
threshold = request.GET.get("threshold", None)
bbox = request.GET.get("bbox", False)
if not bbox:
return render_to_json_response({'error': 'no bbox parameter'})
bs = bbox.split(",")
bs_param = (float(bs[0]), float(bs[1]), float(bs[2]), float(bs[3]),)
country = request.GET.get("adm0", "US") # right now, unused
adm1 = request.GET.get("adm1", "")
adm2 = request.GET.get("adm2", "")
srid = int(request.GET.get("srid", 4326))
features_qset = Feature.search.overlaps(bs_param, text=search_term, srid=3785)[0:20]
features = [f.get_geojson() for f in features_qset]
if threshold:
try:
threshold = float(threshold)
except ValueError:
return render_to_json_response({'error': 'threshold must be a float'})
if bbox:
try:
bbox = map(float, bbox.split(","))
except ValueError:
bbox = None
return render_to_json_response({'error': 'bbox must be in the form: minx,miny,maxx,maxy'})
if not bbox and not search_term:
return render_to_json_response({'error': 'must supply either a valid `bbox` or a `search` parameter'})
features_qset = Feature.search.find(bbox=bbox, text=search_term, threshold=threshold, adm1=adm1, adm2=adm2, srid=srid)[0:20]
features = [f.get_geojson(srid) for f in features_qset]
d = {
'type': 'FeatureCollection',
'features': features