Code generated by the framework is part of the application, so, you, as the application developer, can customize it at will.
Web services generated with the paster mf-layer command implement the HTTP interfaces described in the Protocol page. You may need to augment these interfaces and add your own, custom filtering parameters.
The generated controller class for the users layer looks like this:
class UsersController(BaseController):
readonly = True # if set to True, only GET is supported
def __init__(self):
self.protocol = Protocol(Session, User, self.readonly)
def index(self, format='json'):
return self.protocol.read(request)
(The comments and the other actions have been intentionally omited.)
Note that no filter is passed to the protocol (the filter positional argument to the read method is not set). When the protocol isn’t passed a filter it creates a default one, the MapFish default filter, which corresponds to what’s defined in the MapFish Protocol.
We’re now going to see how you can change the behavior of the users web service.
Let’s assume you want that only employees are returned by the users web service. For this you will create a comparison filter and combine it with the MapFish default filter:
from sqlalchemy.sql import and_
class UsersController(BaseController):
readonly = True # if set to True, only GET is supported
def __init__(self):
self.protocol = Protocol(Session, User, self.readonly)
def index(self, format='json'):
default_filter = create_default_filter(request, User)
filter = and_(default_filter, User.type == "employee")
return self.protocol.read(request, filter=filter)
The new filter is combined with the default filter in a boolean filter. The default filter is created with the create_default_filter(). The boolean filter is created with the and_ SQLAlchemy function, see the SQLAlchemy documentation for further detail.
Let’s now assume that you want the web service to return either managers or developers or both based on the type parameter in the query string. Let’s also assume that you still want your web service to support all the geographic filtering capability of the MapFish protocol:
from sqlalchemy.sql import and_
class UsersController(BaseController):
readonly = True # if set to True, only GET is supported
def __init__(self):
self.protocol = Protocol(Session, User, self.readonly)
def index(self, format='json'):
filter = create_geom_filter(request, User)
if "type" in request.params:
filter = and_(filter, User.type == request.params["type"])
return self.protocol.read(request, filter=filter)
The create_geom_filter() function is called to get the default geographic filter. And, if the query string includes the type parameter, the geographic filter is combined with a specific filter in a boolean filter. See the documentation of the create_geom_filter() function.
We assume in this scenario that you want to support the type parameter in the query string (as in Scenario #2) and that you only want to support bbox for the geographic filtering:
class UsersController(BaseController):
readonly = True # if set to True, only GET is supported
def __init__(self):
self.protocol = Protocol(Session, User, self.readonly)
def index(self, format='json'):
filters = []
if "type" in request.params:
filters.append(User.type == request.params["type"])
if "bbox" in request.params:
FIXME FIXME the following will have to change
filters.append(
spatial.Spatial(
spatial.Spatial.BOX,
User.geometry_column(),
box=request.params["bbox"].split(",")
).to_sql_expr()
return self.protocol.read(request, filter=and_(*filters))
In this scenario the web service doesn’t rely on the MapFish default filter.
This scenario will demonstrate how to use GeoAlchemy’s geometry functions in a custom filter. Let’s say you want to query lakes whose area is greater or equal than the value of a area parameter in the query string:
class LakesController(BaseController):
readonly = True # if set to True, only GET is supported
def __init__(self):
self.protocol = Protocol(Session, Lake, self.readonly)
def index(self, format='json'):
filter = create_geom_filter(request, Lake)
if "area" in request.params:
filter = and_(filter, Lake.geom.area == request.params["area"])
return self.protocol.index(request, filter=filter)
If the parameter area is set in the request, a filter is created and combined with the geographic filter. This filter calls the function area() on the geometry column and compares it with the value of parameter area.