django-gisserver 2.0__py3-none-any.whl → 2.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {django_gisserver-2.0.dist-info → django_gisserver-2.1.1.dist-info}/METADATA +27 -10
- django_gisserver-2.1.1.dist-info/RECORD +68 -0
- {django_gisserver-2.0.dist-info → django_gisserver-2.1.1.dist-info}/WHEEL +1 -1
- gisserver/__init__.py +1 -1
- gisserver/conf.py +23 -1
- gisserver/crs.py +452 -0
- gisserver/db.py +78 -6
- gisserver/exceptions.py +106 -2
- gisserver/extensions/functions.py +122 -28
- gisserver/extensions/queries.py +15 -10
- gisserver/features.py +46 -33
- gisserver/geometries.py +64 -306
- gisserver/management/commands/loadgeojson.py +41 -21
- gisserver/operations/base.py +11 -7
- gisserver/operations/wfs20.py +31 -93
- gisserver/output/__init__.py +6 -2
- gisserver/output/base.py +28 -13
- gisserver/output/csv.py +18 -6
- gisserver/output/geojson.py +7 -6
- gisserver/output/gml32.py +86 -27
- gisserver/output/results.py +25 -39
- gisserver/output/utils.py +9 -2
- gisserver/parsers/ast.py +177 -68
- gisserver/parsers/fes20/__init__.py +76 -4
- gisserver/parsers/fes20/expressions.py +97 -27
- gisserver/parsers/fes20/filters.py +9 -6
- gisserver/parsers/fes20/identifiers.py +27 -7
- gisserver/parsers/fes20/lookups.py +8 -6
- gisserver/parsers/fes20/operators.py +101 -49
- gisserver/parsers/fes20/sorting.py +14 -6
- gisserver/parsers/gml/__init__.py +10 -19
- gisserver/parsers/gml/base.py +32 -14
- gisserver/parsers/gml/geometries.py +54 -21
- gisserver/parsers/ows/kvp.py +10 -2
- gisserver/parsers/ows/requests.py +6 -4
- gisserver/parsers/query.py +6 -2
- gisserver/parsers/values.py +61 -4
- gisserver/parsers/wfs20/__init__.py +2 -0
- gisserver/parsers/wfs20/adhoc.py +28 -18
- gisserver/parsers/wfs20/base.py +12 -7
- gisserver/parsers/wfs20/projection.py +3 -3
- gisserver/parsers/wfs20/requests.py +1 -0
- gisserver/parsers/wfs20/stored.py +3 -2
- gisserver/parsers/xml.py +12 -0
- gisserver/projection.py +17 -7
- gisserver/static/gisserver/index.css +27 -6
- gisserver/templates/gisserver/base.html +15 -0
- gisserver/templates/gisserver/index.html +10 -16
- gisserver/templates/gisserver/service_description.html +12 -6
- gisserver/templates/gisserver/wfs/feature_field.html +1 -1
- gisserver/templates/gisserver/wfs/feature_type.html +44 -13
- gisserver/types.py +152 -82
- gisserver/views.py +47 -24
- django_gisserver-2.0.dist-info/RECORD +0 -66
- {django_gisserver-2.0.dist-info → django_gisserver-2.1.1.dist-info/licenses}/LICENSE +0 -0
- {django_gisserver-2.0.dist-info → django_gisserver-2.1.1.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
"""These classes map to the FES 2.0 specification for expressions.
|
|
2
2
|
The class names are identical to those in the FES spec.
|
|
3
|
+
|
|
4
|
+
Inheritance structure:
|
|
5
|
+
|
|
6
|
+
* :class:`Expression`
|
|
7
|
+
|
|
8
|
+
* :class:`Function` for ``<fes:Function>``.
|
|
9
|
+
* :class:`Literal` for ``<fes:Literal>``.
|
|
10
|
+
* :class:`ValueReference` for ``<fes:ValueReference>``.
|
|
11
|
+
* :class:`BinaryOperator` for FES 1.0 compatibility.
|
|
12
|
+
|
|
13
|
+
The :class:`BinaryOperator` is included as expression
|
|
14
|
+
to handle FES 1.0 :class:`BinaryOperatorType` arithmetic tags:
|
|
15
|
+
``<fes:Add>``, ``<fes:Sub>``, ``<fes:Mul>``, ``<fes:Div>``.
|
|
3
16
|
"""
|
|
4
17
|
|
|
5
18
|
from __future__ import annotations
|
|
@@ -13,6 +26,7 @@ from typing import Union
|
|
|
13
26
|
|
|
14
27
|
from django.contrib.gis import geos
|
|
15
28
|
from django.contrib.gis.db import models as gis_models
|
|
29
|
+
from django.core.exceptions import ValidationError
|
|
16
30
|
from django.db import models
|
|
17
31
|
from django.db.models import Q, Value
|
|
18
32
|
from django.db.models.expressions import Combinable
|
|
@@ -20,7 +34,7 @@ from django.db.models.expressions import Combinable
|
|
|
20
34
|
from gisserver.exceptions import ExternalParsingError
|
|
21
35
|
from gisserver.extensions.functions import function_registry
|
|
22
36
|
from gisserver.parsers.ast import (
|
|
23
|
-
|
|
37
|
+
AstNode,
|
|
24
38
|
TagNameEnum,
|
|
25
39
|
expect_no_children,
|
|
26
40
|
expect_tag,
|
|
@@ -36,7 +50,7 @@ from gisserver.parsers.gml import (
|
|
|
36
50
|
from gisserver.parsers.query import RhsTypes
|
|
37
51
|
from gisserver.parsers.values import auto_cast
|
|
38
52
|
from gisserver.parsers.xml import NSElement, parse_qname, xmlns
|
|
39
|
-
from gisserver.types import
|
|
53
|
+
from gisserver.types import XPathMatch, XsdTypes
|
|
40
54
|
|
|
41
55
|
NoneType = type(None)
|
|
42
56
|
ParsedValue = Union[int, str, date, D, datetime, GM_Object, GM_Envelope, TM_Object, NoneType]
|
|
@@ -74,10 +88,11 @@ class BinaryOperatorType(TagNameEnum):
|
|
|
74
88
|
Div = operator.truediv
|
|
75
89
|
|
|
76
90
|
|
|
77
|
-
class Expression(
|
|
91
|
+
class Expression(AstNode):
|
|
78
92
|
"""Abstract base class, as defined by FES spec.
|
|
79
93
|
|
|
80
94
|
The FES spec defines the following subclasses:
|
|
95
|
+
|
|
81
96
|
* :class:`ValueReference` (pointing to a field name)
|
|
82
97
|
* :class:`Literal` (a scalar value)
|
|
83
98
|
* :class:`Function` (a transformation for a value/field)
|
|
@@ -110,13 +125,13 @@ class Expression(BaseNode):
|
|
|
110
125
|
@dataclass(repr=False)
|
|
111
126
|
@tag_registry.register("Literal")
|
|
112
127
|
class Literal(Expression):
|
|
113
|
-
"""The
|
|
128
|
+
"""The ``<fes:Literal>`` element that holds a literal value.
|
|
114
129
|
|
|
115
130
|
This can be a string value, possibly annotated with a type::
|
|
116
131
|
|
|
117
132
|
<fes:Literal type="xs:boolean">true</fes:Literal>
|
|
118
133
|
|
|
119
|
-
Following the spec, the value may also contain a complete geometry
|
|
134
|
+
Following the spec, the value may also contain a complete geometry::
|
|
120
135
|
|
|
121
136
|
<fes:Literal>
|
|
122
137
|
<gml:Envelope xmlns:gml="http://www.opengis.net/gml/3.2" srsName="urn:ogc:def:crs:EPSG::4326">
|
|
@@ -138,7 +153,9 @@ class Literal(Expression):
|
|
|
138
153
|
|
|
139
154
|
@cached_property
|
|
140
155
|
def value(self) -> ParsedValue: # officially <xsd:any>
|
|
141
|
-
"""Access the value of the element, cast to the appropriate data type.
|
|
156
|
+
"""Access the value of the element, cast to the appropriate data type.
|
|
157
|
+
:raises ExternalParsingError: When the value can't be converted to the proper type.
|
|
158
|
+
"""
|
|
142
159
|
if not isinstance(self.raw_value, str):
|
|
143
160
|
return self.raw_value # GML element or None
|
|
144
161
|
elif self.type:
|
|
@@ -208,14 +225,22 @@ class Literal(Expression):
|
|
|
208
225
|
@tag_registry.register("ValueReference")
|
|
209
226
|
@tag_registry.register("PropertyName", hidden=True) # FES 1.0 name that old clients still use.
|
|
210
227
|
class ValueReference(Expression):
|
|
211
|
-
"""The
|
|
228
|
+
"""The ``<fes:ValueReference>`` element that holds an XPath string.
|
|
212
229
|
In the fes XSD, this is declared as a subclass of xsd:string.
|
|
213
230
|
|
|
231
|
+
This parses the syntax like::
|
|
232
|
+
|
|
233
|
+
<fes:ValueReference>field-name</fes:ValueReference>
|
|
234
|
+
<fes:ValueReference>path/to/field-name</fes:ValueReference>
|
|
235
|
+
<fes:ValueReference>collection[@attr=value]/field-name</fes:ValueReference>
|
|
236
|
+
|
|
214
237
|
The old WFS1/FES1 "PropertyName" is allowed as an alias.
|
|
215
238
|
Various clients still send this, and mapserver/geoserver support this.
|
|
216
239
|
"""
|
|
217
240
|
|
|
241
|
+
#: The XPath value
|
|
218
242
|
xpath: str
|
|
243
|
+
#: The known namespaces aliases at this point in the XML tree
|
|
219
244
|
xpath_ns_aliases: dict[str, str] | None = field(compare=False, default=None)
|
|
220
245
|
|
|
221
246
|
def __str__(self):
|
|
@@ -231,35 +256,37 @@ class ValueReference(Expression):
|
|
|
231
256
|
return cls(xpath=element.text, xpath_ns_aliases=element.ns_aliases)
|
|
232
257
|
|
|
233
258
|
def build_lhs(self, compiler) -> str:
|
|
234
|
-
"""
|
|
259
|
+
"""Use the field name in a left-hand-side expression."""
|
|
260
|
+
# Optimized from base class: fields don't need an alias lookup through annotations.
|
|
235
261
|
match = self.parse_xpath(compiler.feature_types)
|
|
236
262
|
return match.build_lhs(compiler)
|
|
237
263
|
|
|
238
264
|
def build_rhs(self, compiler) -> RhsTypes:
|
|
239
|
-
"""
|
|
265
|
+
"""Use the field name in a right-hand expression.
|
|
266
|
+
This generates an F-expression for the ORM."""
|
|
240
267
|
match = self.parse_xpath(compiler.feature_types)
|
|
241
268
|
return match.build_rhs(compiler)
|
|
242
269
|
|
|
243
|
-
def parse_xpath(self, feature_types: list) ->
|
|
270
|
+
def parse_xpath(self, feature_types: list) -> XPathMatch:
|
|
244
271
|
"""Convert the XPath into the required ORM query elements."""
|
|
245
|
-
|
|
246
|
-
# Can resolve against XSD paths, find the correct DB field name
|
|
247
|
-
return feature_types[0].resolve_element(self.xpath, self.xpath_ns_aliases)
|
|
248
|
-
else:
|
|
249
|
-
# Only used by unit testing (when feature_type is not given).
|
|
250
|
-
parts = [word.strip() for word in self.xpath.split("/")]
|
|
251
|
-
return ORMPath(orm_path="__".join(parts), orm_filters=None)
|
|
252
|
-
|
|
253
|
-
@cached_property
|
|
254
|
-
def element_name(self):
|
|
255
|
-
"""Tell which element this reference points to."""
|
|
256
|
-
return self.xpath.rpartition("/")[2]
|
|
272
|
+
return feature_types[0].resolve_element(self.xpath, self.xpath_ns_aliases)
|
|
257
273
|
|
|
258
274
|
|
|
259
275
|
@dataclass
|
|
260
276
|
@tag_registry.register("Function")
|
|
261
277
|
class Function(Expression):
|
|
262
|
-
"""The
|
|
278
|
+
"""The ``<fes:Function name="...">`` element.
|
|
279
|
+
|
|
280
|
+
This parses the syntax such as::
|
|
281
|
+
|
|
282
|
+
<fes:Function name="Add">
|
|
283
|
+
<fes:ValueReference>field-name</fes:ValueReference>
|
|
284
|
+
<fes:Literal>2</fes:Literal>
|
|
285
|
+
</fes:Function>
|
|
286
|
+
|
|
287
|
+
Each argument of the function can be another :class:`Expression`,
|
|
288
|
+
such as a :class:`Function`, :class:`ValueReference` or :class:`Literal`.
|
|
289
|
+
"""
|
|
263
290
|
|
|
264
291
|
name: str # scoped name
|
|
265
292
|
arguments: list[Expression] # xsd:element ref="fes20:expression"
|
|
@@ -284,8 +311,17 @@ class Function(Expression):
|
|
|
284
311
|
class BinaryOperator(Expression):
|
|
285
312
|
"""Support for FES 1.0 arithmetic operators.
|
|
286
313
|
|
|
314
|
+
This parses a syntax like::
|
|
315
|
+
|
|
316
|
+
<fes:Add>
|
|
317
|
+
<fes:ValueReference>field-name</fes:ValueReference>
|
|
318
|
+
<fes:Literal>2</fes:Literal>
|
|
319
|
+
</fes:Add>
|
|
320
|
+
|
|
321
|
+
The operator can be a ``<fes:Add>``, ``<fes:Sub>``, ``<fes:Mul>``, ``<fes:Div>``.
|
|
322
|
+
|
|
287
323
|
These are no longer part of the FES 2.0 spec, but clients (like QGis)
|
|
288
|
-
still assume the server
|
|
324
|
+
still assume the server use these. Hence, these need to be included.
|
|
289
325
|
"""
|
|
290
326
|
|
|
291
327
|
_operatorType: BinaryOperatorType
|
|
@@ -302,9 +338,43 @@ class BinaryOperator(Expression):
|
|
|
302
338
|
)
|
|
303
339
|
|
|
304
340
|
def build_rhs(self, compiler) -> RhsTypes:
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
341
|
+
self.validate_arithmetic(compiler, self.expression[0], self.expression[1])
|
|
342
|
+
value1 = self.expression[0].build_rhs(compiler)
|
|
343
|
+
value2 = self.expression[1].build_rhs(compiler)
|
|
344
|
+
|
|
345
|
+
# Func() + 2 or 2 + Func() are automatically handled,
|
|
346
|
+
# but Q(..) + 2 or 2 + Q(..) aren't.
|
|
347
|
+
# When both are values, a direct calculation takes place in Python.
|
|
348
|
+
if isinstance(value1, Q):
|
|
349
|
+
value2 = _make_combinable(value2)
|
|
350
|
+
if isinstance(value2, Q):
|
|
351
|
+
value1 = _make_combinable(value1)
|
|
352
|
+
|
|
353
|
+
try:
|
|
354
|
+
# This calls somthing like: operator.add(F("field"), 2) or operator.add(1, 2)
|
|
355
|
+
return self._operatorType.value(value1, value2)
|
|
356
|
+
except (TypeError, ValueError, ArithmeticError) as e:
|
|
357
|
+
raise ValidationError(
|
|
358
|
+
f"Invalid data for the 'fes:{self._operatorType.name}' element: {value1} {value2}"
|
|
359
|
+
) from e
|
|
360
|
+
|
|
361
|
+
def validate_arithmetic(self, compiler, lhs: Expression, rhs: Expression):
|
|
362
|
+
"""Check whether values support arithmetic operators."""
|
|
363
|
+
if isinstance(lhs, Literal) and isinstance(rhs, ValueReference):
|
|
364
|
+
lhs, rhs = rhs, lhs
|
|
365
|
+
|
|
366
|
+
if isinstance(lhs, ValueReference):
|
|
367
|
+
xsd_element = lhs.parse_xpath(compiler.feature_types).child
|
|
368
|
+
if isinstance(rhs, Literal):
|
|
369
|
+
# Since the element is resolved, inform the Literal how to parse the value.
|
|
370
|
+
# This avoids various validation errors along the path.
|
|
371
|
+
rhs.bind_type(xsd_element.type)
|
|
372
|
+
|
|
373
|
+
# Validate the expressions against each other
|
|
374
|
+
# This raises an ValidationError when values can't be converted
|
|
375
|
+
xsd_element.to_python(rhs.raw_value)
|
|
376
|
+
|
|
377
|
+
return None
|
|
308
378
|
|
|
309
379
|
|
|
310
380
|
def _make_combinable(value) -> Combinable | Q:
|
|
@@ -6,7 +6,7 @@ from typing import AnyStr, ClassVar, Union
|
|
|
6
6
|
from django.db.models import Q
|
|
7
7
|
|
|
8
8
|
from gisserver.exceptions import InvalidParameterValue
|
|
9
|
-
from gisserver.parsers.ast import
|
|
9
|
+
from gisserver.parsers.ast import AstNode, expect_tag, tag_registry
|
|
10
10
|
from gisserver.parsers.gml import GEOSGMLGeometry
|
|
11
11
|
from gisserver.parsers.ows import KVPRequest
|
|
12
12
|
from gisserver.parsers.query import CompiledQuery
|
|
@@ -14,6 +14,7 @@ from gisserver.parsers.xml import NSElement, parse_xml_from_string, xmlns
|
|
|
14
14
|
|
|
15
15
|
from . import expressions, identifiers, operators
|
|
16
16
|
|
|
17
|
+
#: The FES element group that can be used as body for the :class:`Filter` element.
|
|
17
18
|
FilterPredicates = Union[expressions.Function, operators.Operator]
|
|
18
19
|
|
|
19
20
|
# Fully qualified tag names
|
|
@@ -22,8 +23,8 @@ FES_RESOURCE_ID = xmlns.fes20.qname("ResourceId")
|
|
|
22
23
|
|
|
23
24
|
@dataclass
|
|
24
25
|
@tag_registry.register("Filter", xmlns.fes20)
|
|
25
|
-
class Filter(
|
|
26
|
-
"""The
|
|
26
|
+
class Filter(AstNode):
|
|
27
|
+
"""The ``<fes:Filter>`` element.
|
|
27
28
|
|
|
28
29
|
This parses and handles the syntax::
|
|
29
30
|
|
|
@@ -41,7 +42,9 @@ class Filter(BaseNode):
|
|
|
41
42
|
|
|
42
43
|
query_language: ClassVar[str] = "urn:ogc:def:queryLanguage:OGC-FES:Filter"
|
|
43
44
|
|
|
45
|
+
#: The filter predicate (body)
|
|
44
46
|
predicate: FilterPredicates
|
|
47
|
+
|
|
45
48
|
source: AnyStr | None = field(default=None, compare=False)
|
|
46
49
|
|
|
47
50
|
@classmethod
|
|
@@ -106,7 +109,7 @@ class Filter(BaseNode):
|
|
|
106
109
|
|
|
107
110
|
@classmethod
|
|
108
111
|
def from_string(cls, text: AnyStr, ns_aliases: dict[str, str] | None = None) -> Filter:
|
|
109
|
-
"""Parse an XML
|
|
112
|
+
"""Parse an XML ``<fes:Filter>`` string.
|
|
110
113
|
|
|
111
114
|
This uses defusedxml by default, to avoid various XML injection attacks.
|
|
112
115
|
|
|
@@ -156,8 +159,8 @@ class Filter(BaseNode):
|
|
|
156
159
|
return self.predicate.build_query(compiler)
|
|
157
160
|
|
|
158
161
|
def get_resource_id_types(self) -> list[str] | None:
|
|
159
|
-
"""When the filter
|
|
160
|
-
This can return an empty list in case a ResourceId object doesn't define a type.
|
|
162
|
+
"""When the filter predicate consists of ``<fes:ResourceId>`` elements, return those.
|
|
163
|
+
This can return an empty list in case a ``<fes:ResourceId>`` object doesn't define a type.
|
|
161
164
|
"""
|
|
162
165
|
if isinstance(self.predicate, operators.IdOperator):
|
|
163
166
|
return self.predicate.get_type_names()
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
"""These classes map to the FES 2.0 specification for identifiers.
|
|
2
2
|
The class names are identical to those in the FES spec.
|
|
3
|
+
|
|
4
|
+
Inheritance structure:
|
|
5
|
+
|
|
6
|
+
* :class:`Id`
|
|
7
|
+
|
|
8
|
+
* :class:`ResourceId`
|
|
3
9
|
"""
|
|
4
10
|
|
|
5
11
|
from __future__ import annotations
|
|
@@ -12,7 +18,7 @@ from django.db.models import Q
|
|
|
12
18
|
|
|
13
19
|
from gisserver import conf
|
|
14
20
|
from gisserver.exceptions import ExternalValueError, InvalidParameterValue
|
|
15
|
-
from gisserver.parsers.ast import
|
|
21
|
+
from gisserver.parsers.ast import AstNode, expect_no_children, expect_tag, tag_registry
|
|
16
22
|
from gisserver.parsers.values import auto_cast, parse_iso_datetime
|
|
17
23
|
from gisserver.parsers.xml import parse_qname, xmlns
|
|
18
24
|
|
|
@@ -20,7 +26,7 @@ NoneType = type(None)
|
|
|
20
26
|
|
|
21
27
|
|
|
22
28
|
class VersionActionTokens(Enum):
|
|
23
|
-
"""Values for the 'version' attribute of the ResourceId node."""
|
|
29
|
+
"""Values for the 'version' attribute of the :class:`ResourceId` node."""
|
|
24
30
|
|
|
25
31
|
FIRST = "FIRST"
|
|
26
32
|
LAST = "LAST"
|
|
@@ -29,8 +35,11 @@ class VersionActionTokens(Enum):
|
|
|
29
35
|
PREVIOUS = "PREVIOUS"
|
|
30
36
|
|
|
31
37
|
|
|
32
|
-
class Id(
|
|
33
|
-
"""Abstract base class, as defined by FES spec.
|
|
38
|
+
class Id(AstNode):
|
|
39
|
+
"""Abstract base class, as defined by FES spec.
|
|
40
|
+
Any custom identifier-element needs to extend from this node.
|
|
41
|
+
By default, the :class:`ResourceId` element is supported.
|
|
42
|
+
"""
|
|
34
43
|
|
|
35
44
|
xml_ns = xmlns.fes20
|
|
36
45
|
|
|
@@ -44,19 +53,30 @@ class Id(BaseNode):
|
|
|
44
53
|
@dataclass
|
|
45
54
|
@tag_registry.register("ResourceId")
|
|
46
55
|
class ResourceId(Id):
|
|
47
|
-
"""The
|
|
56
|
+
"""The ``<fes:ResourceId>`` element.
|
|
48
57
|
This element allow queries to retrieve a resource by their identifier.
|
|
58
|
+
|
|
59
|
+
This parses the syntax::
|
|
60
|
+
|
|
61
|
+
<fes:ResourceId rid="typename.123" />
|
|
62
|
+
|
|
63
|
+
This element is placed inside a :class:`~gisserver.parsers.fes20.filters.Filter`.
|
|
49
64
|
"""
|
|
50
65
|
|
|
51
|
-
|
|
52
|
-
|
|
66
|
+
#: A raw "resource identifier". It typically includes the object name,
|
|
67
|
+
#: which is completely unrelated to XML namespacing.
|
|
53
68
|
rid: str
|
|
69
|
+
|
|
70
|
+
#: Internal extra attribute, referencing the inferred typename from the :attr:`rid`.
|
|
54
71
|
type_name: str | None
|
|
72
|
+
|
|
73
|
+
#: Unused, this is part of additional conformance classes.
|
|
55
74
|
version: int | datetime | VersionActionTokens | NoneType = None
|
|
56
75
|
startTime: datetime | None = None
|
|
57
76
|
endTime: datetime | None = None
|
|
58
77
|
|
|
59
78
|
def get_type_name(self):
|
|
79
|
+
"""Implemented/override to expose the inferred type name."""
|
|
60
80
|
return self.type_name
|
|
61
81
|
|
|
62
82
|
def __post_init__(self):
|
|
@@ -14,7 +14,7 @@ from gisserver.compat import ArrayField
|
|
|
14
14
|
@models.TextField.register_lookup
|
|
15
15
|
@models.ForeignObject.register_lookup
|
|
16
16
|
class FesLike(lookups.Lookup):
|
|
17
|
-
"""Allow fieldname__fes_like
|
|
17
|
+
"""Allow ``fieldname__fes_like=...`` lookups in querysets."""
|
|
18
18
|
|
|
19
19
|
lookup_name = "fes_like"
|
|
20
20
|
|
|
@@ -36,7 +36,7 @@ class FesLike(lookups.Lookup):
|
|
|
36
36
|
@models.Field.register_lookup
|
|
37
37
|
@models.ForeignObject.register_lookup
|
|
38
38
|
class FesNotEqual(lookups.Lookup):
|
|
39
|
-
"""Allow fieldname__fes_notequal
|
|
39
|
+
"""Allow ``fieldname__fes_notequal=...`` lookups in querysets."""
|
|
40
40
|
|
|
41
41
|
lookup_name = "fes_notequal"
|
|
42
42
|
|
|
@@ -49,10 +49,12 @@ class FesNotEqual(lookups.Lookup):
|
|
|
49
49
|
|
|
50
50
|
@BaseSpatialField.register_lookup
|
|
51
51
|
class FesBeyondLookup(DWithinLookup):
|
|
52
|
-
"""
|
|
52
|
+
"""Allow ``fieldname__fes_beyond=...`` lookups in querysets.
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
Based on the FES 2.0.3 corrigendum:
|
|
55
|
+
|
|
56
|
+
* ``DWithin(A,B,d) = Distance(A,B) < d``
|
|
57
|
+
* ``Beyond(A,B,d) = Distance(A,B) > d``
|
|
56
58
|
|
|
57
59
|
See: https://docs.opengeospatial.org/is/09-026r2/09-026r2.html#61
|
|
58
60
|
"""
|
|
@@ -130,7 +132,7 @@ else:
|
|
|
130
132
|
|
|
131
133
|
@ArrayField.register_lookup
|
|
132
134
|
class FesArrayLike(FesLike):
|
|
133
|
-
"""Allow
|
|
135
|
+
"""Allow like lookups for array fields."""
|
|
134
136
|
|
|
135
137
|
lookup_name = "fes_anylike"
|
|
136
138
|
|