Overriding Server Logic¶
There are a few places where the server logic can be extended:
There are a few places that allow to customize the WFS logic:
View Layer¶
The following methods of the WFSView
can be overwritten:
get_feature_types()
to dynamically generate all exposed features.get_service_description()
to dynamically generate the description.dispatch()
to implement basic auth.
Feature Layer¶
Overriding FeatureType
allows to change how particular features and fields are exposed.
It can also override the internal XML Schema Definition (XSD) that all output and query filters read.
This can also adjust the
- Overriding
check_permissions()
allows to perform a permission check before the feature can be read (e.g. a login role check). - Overriding
get_queryset()
allows to define the queryset per request. - Overriding
xsd_type
constructs the internal XSD definition of this feature. - Overriding
xsd_type_class
defines which class constructs the XSD.
The field()
function returns a FeatureField
.
Instances of this class can be passed directly to the FeatureType(fields=...)
parameter,
and override these attributes:
xsd_element
constructs the internal XSD that filters and output formats use.xsd_element_class
defines which class defines the attribute.
XSD Layer¶
The feature fields generate an internal XML Schema Definition (XSD) that defines how
properties are read, and where the underlying ORM field/relation can be found.
These types can be overwritten for custom behavior, and then be returned by
custom FeatureType
and FeatureField
objects.
XsdComplexType
defines a complete class with elements and attributes.XsdElement
defines a property that becomes a normal element.XsdAttribute
defines the attributes (onlygml:id
is currently rendered).
The elements and attributes have the following fields:
orm_path
- returns where to find the ORM relation.orm_field
- returns the first part of the ORM relation.orm_relation
- returns the ORM relation as path and final field name.get_value()
- how to read the attribute value.format_value()
- format raw-retrieved values from the database (e.g.values()
query).to_python()
- how to cast input data.validate_comparison()
- checks a field supports a certain data type.build_lhs_part()
- how to generate the ORM left-hand-side.build_rhs_part()
- how to generate the ORM right-hand-side.
Custom Filter Functions¶
Warning
While the machinery to hook new functions is in place, this part is still in development.
As part of the WFS Filter Encoding, a client can execute a function against a server.
These are executed with ?REQUEST=GetFeature&FILTER...
An expression such as: table_count == Add(“previous_table_count”, 100) would be encoded in the following way using the Filter Encoding Specification (FES):
<fes:Filter xmlns:fes="http://www.opengis.net/fes/2.0">
<fes:PropertyIsEqualTo>
<fes:ValueReference>table_count</fes:ValueReference>
<fes:Function name="Add">
<fes:ValueReference>previous_table_count</fes:ValueReference>
<fes:Literal>100</fes:Literal>
</fes:Function>
</fes:PropertyIsEqualTo>
</fes:Filter>
These FES functions can be defined in the project, by generating a corresponding database function.
Use gisserver.parsers.fes_function_registry
to register new functions:
from django.db.models import functions
from gisserver.parsers import fes_function_registry
from gisserver.types import XsdTypes
# Either link an exising Django ORM function:
function_registry.register(
"atan",
functions.ATan,
arguments={"value": XsdTypes.double},
returns=XsdTypes.double,
)
# Or link a parsing logic that generates an ORM function/object:
@function_registry.register(
name="Add",
arguments=dict(value1=XsdTypes.double, value2=XsdTypes.double),
returns=XsdTypes.double,
)
def fes_add(value1, value2):
return F(value1) + value2
Each FES function should return a Django ORM Func
or Combinable
object.
Custom Stored Procedures¶
Warning
While the machinery to add new stored procedures is in place, this part is still in development.
Aside from filters, a WFS server can also expose “stored procedures”.
These are executed with ?REQUEST=GetFeature&STOREDQUERY_ID=...
By default, only GetFeatureById
is built-in.
These stored procedures can be defined like this:
from gisserver.queries import StoredQuery, stored_query_registry
from gisserver.types import XsdTypes
@stored_query_registry.register(
id="GetRecentChanges",
title="Get all recent changed features",
abstract="All recent changes...",
parameters={"date": XsdTypes.date},
)
class GetRecentChanges(StoredQuery):
...
For a simple implementation, the following methods need to be overwritten:
get_type_names()
defines which feature types this query applies to.compile_query()
defines how to filter the queryset.
For full control, these methods can also be overwritten instead:
get_queryset()
to define the full results.get_hits()
to return the collection forRESULTTYPE=hits
.get_results()
to return the collection forRESULTTYPE=results
.