diff --git a/django/contrib/gis/db/models/sql/query.py b/django/contrib/gis/db/models/sql/query.py index 0376e266e1b33..13b724ec9e6e8 100644 --- a/django/contrib/gis/db/models/sql/query.py +++ b/django/contrib/gis/db/models/sql/query.py @@ -30,6 +30,13 @@ def __init__(self, model, conn): self.transformed_srid = None self.extra_select_fields = {} + if SpatialBackend.oracle: + # Have to override this so that GeoQuery, instead of OracleQuery, + # is returned when unpickling. + def __reduce__(self): + callable, args, data = super(GeoQuery, self).__reduce__() + return (unpickle_geoquery, (), data) + def clone(self, *args, **kwargs): obj = super(GeoQuery, self).clone(*args, **kwargs) # Customized selection dictionary and transformed srid flag have @@ -324,6 +331,15 @@ def _geo_field(self, field_name=None): # a lookup to a _related_ geographic field. return self._check_geo_field(self.model, field_name) +if SpatialBackend.oracle: + def unpickle_geoquery(): + """ + Utility function, called by Python's unpickling machinery, that handles + unpickling of GeoQuery subclasses of OracleQuery. + """ + return GeoQuery.__new__(GeoQuery) + unpickle_geoquery.__safe_for_unpickling__ = True + ### Field Classes for `convert_values` #### class BaseField(object): def get_internal_type(self): diff --git a/django/contrib/gis/tests/relatedapp/tests.py b/django/contrib/gis/tests/relatedapp/tests.py index a35836773a712..3096914a9d45b 100644 --- a/django/contrib/gis/tests/relatedapp/tests.py +++ b/django/contrib/gis/tests/relatedapp/tests.py @@ -137,6 +137,15 @@ def test09_pk_relations(self): self.assertEqual(val_dict['id'], c_id) self.assertEqual(val_dict['location__id'], l_id) + def test11_geoquery_pickle(self): + "Ensuring GeoQuery objects are unpickled correctly. See #10839." + import pickle + from django.contrib.gis.db.models.sql import GeoQuery + qs = City.objects.all() + q_str = pickle.dumps(qs.query) + q = pickle.loads(q_str) + self.assertEqual(GeoQuery, q.__class__) + # TODO: Related tests for KML, GML, and distance lookups. def suite():