Exemplo n.º 1
0
Arquivo: views.py Projeto: 3taps/geo
def search_by_name(request):
    """ Implement the "/name" API call.
    """
    # Extract our parameters.

    levels = []

    level_param = get_param(request, "level")
    if level_param != None:
        level = name_to_level(level_param)
        if level == None:
            return error_response(
                code=400, message="Unknown level: " + repr(level_param), callback=get_param(request, "callback")
            )
        levels.append(level)
    else:
        levels_param = get_param(request, "levels")
        if levels_param != None:
            for level_name in levels_param.split(","):
                level = name_to_level(level_name)
                if level == None:
                    return error_response(
                        code=400, message="Unknown level: " + repr(level_param), callback=get_param(request, "callback")
                    )
                levels.append(level)

    text = get_param(request, "text")

    if text == None:
        return error_response(code=400, message="Missing 'text' parameter.", callback=get_param(request, "callback"))
    if len(text) < 3:
        return error_response(code=400, message="'text' parameter too short.", callback=get_param(request, "callback"))

    type = get_param(request, "type")

    if type != None:
        type = type.lower()
        if not type in [
            "exact",
            "contains",
            "startswith",
            "endswith",
            "iexact",
            "icontains",
            "istartswith",
            "iendswith",
        ]:
            return error_response(
                code=400, message="Invalid 'type' parameter: " + repr(type), callback=get_param(request, "callback")
            )
    else:
        type = "istartswith"  # Default search type.

    # Perform the appropriate type of name-based search.

    args = {"name__" + str(type): text}
    if len(levels) > 0:
        args["level__in"] = levels

    query = Name.objects.filter(**args).order_by("level__level", "name")
    results = {}

    num_matches = query.count()
    results["numMatches"] = num_matches

    if num_matches <= 20:
        matches = []
        matched_locs = set()  # Used to only include each location once.

        for name in query:
            for loc_name in name.locationname_set.all():
                location = loc_name.location
                if location in matched_locs:
                    # Only include each location once.
                    continue

                matches.append(
                    {
                        "level": level_to_name(location.level),
                        "code": location.code,
                        "foundName": name.name,
                        "locationName": location.name,
                        "displayName": location.display_name,
                        "abbreviation": location.abbreviation,
                        "context": get_context(location),
                    }
                )

                matched_locs.add(location)

        results["locations"] = matches

    # Finally, return the results back to the caller.

    results = json.dumps(results)
    callback = get_param(request, "callback")
    if callback != None:
        results = callback + "(" + results + ")"  # Add JSONP callback.

    return HttpResponse(results, mimetype="application/json")
Exemplo n.º 2
0
Arquivo: views.py Projeto: 3taps/geo
def search_by_latlong(request):
    """ Implement the "latlong" API call.
    """
    # Process our CGI parameters.

    try:
        latitude = float(request.GET["lat"])
    except:
        return error_response(
            code=400, message="Missing or invalid 'lat' parameter.", callback=get_param(request, "callback")
        )

    try:
        longitude = float(request.GET["long"])
    except:
        return error_response(
            code=400, message="Missing or invalid 'long' parameter.", callback=get_param(request, "callback")
        )

    try:
        strategy = request.GET["strategy"]
    except KeyError:
        return error_response(
            code=400, message="Missing 'strategy' parameter.", callback=get_param(request, "callback")
        )

    if strategy == "all":
        pass
    elif strategy == "level":
        try:
            levels_param = request.GET["levels"]
        except KeyError:
            return error_response(
                code=400, message="Missing 'levels' parameter.", callback=get_param(request, "callback")
            )

        levels = []  # List of desired Level objects.
        for level_name in levels_param.split(","):
            level = name_to_level(level_name)
            if level != None:
                levels.append(level)
            else:
                return error_response(
                    code=400, message="Unknown level: " + repr(level_name), callback=get_param(request, "callback")
                )
    elif strategy == "parent":
        try:
            loc_code = request.GET["location"]
        except KeyError:
            return error_response(
                code=400, message="Missing 'location' parameter.", callback=get_param(request, "callback")
            )

        if loc_code == "WORLD":
            location = None
        else:
            try:
                location = Location.objects.get(code=loc_code)
            except Location.DoesNotExist:
                return error_response(
                    code=400, message="Unknown location " + repr(loc_code), callback=get_param(request, "callback")
                )
    else:
        return error_response(
            code=400, message="Invalid strategy " + repr(strategy), callback=get_param(request, "callback")
        )

    # Calculate the matching locations, using the specified strategy.

    pt = Point(longitude, latitude, srid=4326)

    locations = []

    if strategy == "all":
        for outline in Outline.objects.filter(outline__bbcontains=pt):
            if outline.outline.contains(pt):
                locations.append(outline.location.code)
    elif strategy == "level":
        for level in levels:
            for outline in Outline.objects.filter(location__level=level, outline__bbcontains=pt):
                if outline.outline.contains(pt):
                    locations.append(outline.location.code)
    elif strategy == "parent":
        # Check the starting location's children.
        outlineIDs = []
        if location != None:
            for child in location.children.all():
                outline = get_outline(child)
                if outline != None:
                    outlineIDs.append(outline.id)
        else:
            # We're at the top level -> check the countries.
            for child in Location.objects.filter(level__level=1):
                outline = get_outline(child)
                if outline != None:
                    outlineIDs.append(outline.id)

        for outline in Outline.objects.filter(id__in=outlineIDs, outline__bbcontains=pt):
            if outline.outline.contains(pt):
                locations.append(outline.location.code)
                break

        if len(locations) == 0:
            # We didn't find a child location -> search for locations starting
            # at the same level as the parent, going up to the country level.
            if location != None:
                for level in range(location.level.level, 0, -1):
                    query = Outline.objects.filter(outline__bbcontains=pt, location__level__level=level)
                    for outline in query:
                        if outline.outline.contains(pt):
                            locations.append(outline.location.code)
                            break
                    if len(locations) > 0:
                        break  # Only find the first matching location.

    # Finally, return the found locations back to the caller.

    results = json.dumps({"locations": locations})

    callback = get_param(request, "callback")
    if callback != None:
        results = callback + "(" + results + ")"  # Add JSONP callback.

    return HttpResponse(results, mimetype="application/json")
Exemplo n.º 3
0
Arquivo: views.py Projeto: 3taps/geo
def search_by_bbox(request):
    """ Implement the "bbox" API call.
    """
    # Extract our parameters.

    levels = []  # List of desired Level objects.

    levels_param = get_param(request, "levels")
    if levels_param != None:
        for level_name in levels_param.split(","):
            level = name_to_level(level_name)
            if level == None:
                return error_response(
                    code=400, message="Unknown level: " + repr(level_name), callback=get_param(request, "callback")
                )
            else:
                levels.append(level)

    minlat = get_param(request, "minlat")
    maxlat = get_param(request, "maxlat")
    minlong = get_param(request, "minlong")
    maxlong = get_param(request, "maxlong")

    try:
        minlat = float(minlat)
    except:
        return error_response(
            code=400, message="Invalid minlat: " + repr(minlat), callback=get_param(request, "callback")
        )

    try:
        maxlat = float(maxlat)
    except:
        return error_response(
            code=400, message="Invalid maxlat: " + repr(maxlat), callback=get_param(request, "callback")
        )

    try:
        minlong = float(minlong)
    except:
        return error_response(
            code=400, message="Invalid minlong: " + repr(minlong), callback=get_param(request, "callback")
        )

    try:
        maxlong = float(maxlong)
    except:
        return error_response(
            code=400, message="Invalid maxlong: " + repr(maxlong), callback=get_param(request, "callback")
        )

    # Create a Polygon geometry that encompasses the specified bounding box.

    bounds = Polygon.from_bbox((minlong, minlat, maxlong, maxlat))

    # Perform a spatial query to return all objects that *might* be in our
    # bounding box.  Note that, because of limitations in MySQL, we have to
    # then check each object individually.

    locations = []  # List of all location codes within our desired bounds.

    for outline in Outline.objects.filter(location__level__in=levels, outline__intersects=bounds):
        mpoly = outline.outline
        if mpoly.intersects(bounds):
            locations.append(outline.location.code)

    # Finally, return the results back to the caller.

    results = json.dumps({"locations": locations})

    callback = get_param(request, "callback")
    if callback != None:
        results = callback + "(" + results + ")"  # Add JSONP callback.

    return HttpResponse(results, mimetype="application/json")