dso_api.dynamic_api.views package
All views for the dynamically generated API, split by protocol type.
REST API
The REST API views are based on Django-Rest-Framework.
The viewsets handle the main API logic of the server. The relevant subclasses are dynamically generated from Amsterdam Schema files, just like the rest of the objects (such as serializers, filtersets and models).
To maintain readable code for the dynamic viewsets, all logic can be found in a normal Python
class (namely the DynamicApiViewSet
base class).
The viewset_factory()
function then generates a subclass
for the specific model/endpoint. The same two-step logic can be found in the serializer
and model layer of this application.
- class dso_api.dynamic_api.views.DynamicApiViewSet(**kwargs)
Viewset for an API, that is DSO-compatible and dynamically generated. Each dynamically generated model in this server will receive a viewset.
Most of the DSO logic is implemented in the base class;
DSOViewMixin
.- dataset_id = None
The dataset ID is filled in by the factory
- get_object() DynamicModel
An improved version of GenericAPIView.get_object() that supports temporal objects.
- get_queryset() QuerySet
Get the list of items for this view. This must be an iterable, and may be a queryset. Defaults to using self.queryset.
This method should always be used rather than accessing self.queryset directly, as self.queryset gets evaluated only once, and those results are cached for all subsequent requests.
You may want to override this if you need to provide different querysets depending on the incoming request.
(Eg. return a list of items that is specific to the user)
- initial(request, *args, **kwargs)
Runs anything that needs to occur prior to calling the method handler.
- property lookup_field
Overwritten from GenericAPIView to filter on temporal identifier instead.
- model: type[schematools.contrib.django.models.DynamicModel] = None
The model is filled in by the factory
- property paginator
The paginator is disabled when a output format supports unlimited sizes.
- table_id = None
The table ID is filled in by the factory
- dso_api.dynamic_api.views.viewset_factory(model: type[schematools.contrib.django.models.DynamicModel]) type[dso_api.dynamic_api.views.api.DynamicApiViewSet]
Generate the viewset for a dynamic model.
This generates a class in-memory, as if the following code was written:
class CustomViewSet(DynamicApiViewSet): dataset_id = ... table_id = ... model = ... queryset = model.objects.all() serializer_class = serializer_factory(model) filterset_class = filterset_factory(model) authorization_grantor = "OIS" ordering_fields = ...
Internally, the
serializer_factory()
, function is called to generate those classes.
WFS API
The WFS views expose all geographic datasets as WFS endpoints and feature types.
The main logic of the WFS server can be found in the django-gisserver
package. By overriding it’s WFSView
class,
our dynamic models can be introduced into the django-gisserver logic.
Specifically, the following happens:
The
FeatureType
class is overwritten to implement permission checks.The
WFSView.get_feature_types()
dynamically returns the feature types based on the datasets.The query parameters
?expand
and?embed
extend the server logic to provide object-embedding at the feature type level.
The WFS server itself doesn’t have any awareness of Amsterdam Schema, or the
fact that model definitions are dynamically generated. It’s output and filter
logic is purely based on the provided FeatureType
definition. Hence, the
server can act differently based on authorization logic - as we provide a
different FeatureType
definition in such case.
By making the dataset name part of the view kwargs
,
each individual dataset becomes a separate WFS server endpoint.
The models of that dataset become WFS feature types.
- class dso_api.dynamic_api.views.DatasetWFSIndexView(**kwargs)
Bases:
APIIndexView
An overview of the available WFS endpoints. This makes sure a request to
/wfs/
renders a reasonable index page.
- class dso_api.dynamic_api.views.DatasetWFSView(**kwargs)
Bases:
CheckPermissionsMixin
,WFSView
A WFS view for a single dataset.
This extends the logic of django-gisserver to expose the dynamically generated as WFS
FeatureType
objects. When the?extend=..
/?expand=..
parameters are given, a different set of feature types is generated so the WFS response contains complex nested objects.Permission checks happen in 2 levels. First, only the accessible fields are exposed in the feature types. Second, the
AuthenticatedFeatureType
class extends the feature type logic to add permission-checking for table-level access.This view is not constructed with factory-logic as we don’t need named-integration in the URLConf. Instead, we can resolve the ‘dataset’ via the URL kwargs.
- get_embedded_fields(relation_name, model, pk_attr=None) list[Union[str, gisserver.features.FeatureField]]
Define which fields to embed as flattened fields.
- get_expanded_fields(model) list[Union[str, gisserver.features.FeatureField]]
Define which fields to include in an expanded relation. This is a shorter list, as including a geometry has no use here. Relations are also avoided as these won’t be expanded anyway.
- get_feature_fields(model, main_geometry_field_name) list[Union[str, gisserver.features.FeatureField]]
Define which fields should be exposed with the model.
Instead of opting for the “__all__” value of django-gisserver, provide an explicit list of fields so unauthorized fields are excluded.
- get_feature_types() list[gisserver.features.FeatureType]
Generate map feature layers for all models that have geometry data.
- get_index_context_data(**kwargs)
Context data for the HTML root page
- get_service_description(service: str) ServiceDescription
Provide the (dynamically generated) service description.
- index_template_name = 'dso_api/dynamic_api/wfs_dataset.html'
Template to render a HTML welcome page for non-OGC requests.
- setup(request, *args, **kwargs)
Initial setup logic before request handling:
Resolve the current model or return a 404 instead.
- xml_namespace = 'https://api.data.amsterdam.nl/v1/wfs/'
Define the namespace to use in the XML
- class dso_api.dynamic_api.views.wfs.AuthenticatedFeatureType(queryset, *, wfs_view: DatasetWFSView, **kwargs)
Bases:
FeatureType
Extended WFS feature type definition that also performs authentication.
- __init__(queryset, *, wfs_view: DatasetWFSView, **kwargs)
- Parameters
queryset – The queryset to retrieve the data.
fields – Define which fields to show in the WFS data. This can be a list of field names, or
FeatureField
objects.display_field_name – Name of the field that’s used as general string representation.
geometry_field – Name of the geometry field to expose (default = auto detect).
name – Name, also used as XML tag name.
title – Used in WFS metadata.
abstract – Used in WFS metadata.
keywords – Used in WFS metadata.
crs – Used in WFS metadata.
other_crs – Used in WFS metadata.
metadata_url – Used in WFS metadata.
show_name_field – Whether to show the
gml:name
or the GeoJSONgeometry_name
field. Default is to show a field whenname_field
is given.xml_prefix – The XML namespace prefix to use.
- check_permissions(request)
Perform the access check for a particular request. This retrieves the accessed models, and relays further processing in the view.
When a related object returns a queryset, this hook allows extra filtering.