Ticket #17018: django-17018.diff

File django-17018.diff, 5.5 KB (added by grobertson, 3 years ago)

updated patch with tests

  • django/contrib/gis/utils/layermapping.py

     
    295295            elif isinstance(model_field, models.base.ModelBase):
    296296                # The related _model_, not a field was passed in -- indicating
    297297                # another mapping for the related Model.
    298                 val = self.verify_fk(feat, model_field, ogr_name)
     298                fk_field = self.model._meta.get_field(field_name)
     299                val = self.verify_fk(feat, model_field, fk_field, ogr_name)
    299300            else:
    300301                # Otherwise, verify OGR Field type.
    301302                val = self.verify_ogr_field(feat[ogr_name], model_field)
     
    373374            val = ogr_field.value
    374375        return val
    375376
    376     def verify_fk(self, feat, rel_model, rel_mapping):
     377    def verify_fk(self, feat, rel_model, fk_field, rel_mapping):
    377378        """
    378379        Given an OGR Feature, the related model and its dictionary mapping,
    379380        this routine will retrieve the related model for the ForeignKey
     
    385386
    386387        # Constructing and verifying the related model keyword arguments.
    387388        fk_kwargs = {}
     389        ogr_values_null = True
    388390        for field_name, ogr_name in rel_mapping.items():
     391            ogr_values_null = ogr_values_null and feat[ogr_name].value == ''
    389392            fk_kwargs[field_name] = self.verify_ogr_field(feat[ogr_name], rel_model._meta.get_field(field_name))
    390393
     394        # If the all of the ogr values representing the foreign key are None
     395        # and the foreign key field's configuration allows null foreign key values,
     396        # then set the foreign key value to None
     397        if fk_field.null and ogr_values_null:
     398            return None
     399
    391400        # Attempting to retrieve and return the related model.
    392401        try:
    393402            return rel_model.objects.using(self.using).get(**fk_kwargs)
  • django/contrib/gis/tests/layermap/tests.py

     
    1111from django.contrib.gis.utils.layermapping import LayerMapping, LayerMapError, InvalidDecimal, MissingForeignKey
    1212
    1313from .models import (
    14     City, County, CountyFeat, Interstate, ICity1, ICity2, Invalid, State,
     14    City, County, CountyNullState, CountyFeat, Interstate, ICity1, ICity2, Invalid, State,
    1515    city_mapping, co_mapping, cofeat_mapping, inter_mapping)
    1616
    1717
    1818shp_path = os.path.realpath(os.path.join(os.path.dirname(__file__), os.pardir, 'data'))
    1919city_shp = os.path.join(shp_path, 'cities', 'cities.shp')
    2020co_shp = os.path.join(shp_path, 'counties', 'counties.shp')
     21co_shp_null_state = os.path.join(shp_path, 'counties', 'counties_null_state.shp')
    2122inter_shp = os.path.join(shp_path, 'interstates', 'interstates.shp')
    2223invalid_shp = os.path.join(shp_path, 'invalid', 'emptypoints.shp')
    2324
     
    2627NUMS   = [1, 2, 1, 19, 1] # Number of polygons for each.
    2728STATES = ['Texas', 'Texas', 'Texas', 'Hawaii', 'Colorado']
    2829
     30
    2931class LayerMapTest(TestCase):
    3032
    3133    def test01_init(self):
     
    278280        lm = LayerMapping(Invalid, invalid_shp, invalid_mapping,
    279281                          source_srs=4326)
    280282        lm.save(silent=True)
     283
     284    def test08_null_foreign_key(self):
     285        "Tests LayerMapping for models with nullable foreign keys.  See #17018."
     286        # Check that a record is successfully added with a null foreign key value when
     287        # the model foreign key field allows a null value and mapping value is null
     288        lm = LayerMapping(CountyNullState, co_shp_null_state, co_mapping, transform=False, unique='name')
     289        lm.save()
     290        self.assertEqual(1, CountyNullState.objects.all().count())
     291        county = CountyNullState.objects.all()[0]
     292        self.assertEqual('Pueblo', county.name)
     293        self.assertEqual(None, county.state)
     294        CountyNullState.objects.all().delete()
     295
     296        # Check that MissingForeignKey is raised when
     297        # the model foreign key field does not allow a null value and mapping value is null
     298        lm = LayerMapping(County, co_shp_null_state, co_mapping, transform=False, unique='name')
     299        self.assertRaises(MissingForeignKey, lm.save, silent=True, strict=True)
     300
     301        # Check that MissingForeignKey is raised when
     302        # the model foreign key field allows a null value and there is no foreign record
     303        # There are no states populated in this case
     304        lm = LayerMapping(CountyNullState, co_shp, co_mapping, transform=False, unique='name')
     305        self.assertRaises(MissingForeignKey, lm.save, silent=True, strict=True)
  • django/contrib/gis/tests/layermap/models.py

     
    1010    mpoly = models.MultiPolygonField(srid=4269) # Multipolygon in NAD83
    1111    objects = models.GeoManager()
    1212
     13class CountyNullState(models.Model):
     14    name = models.CharField(max_length=25)
     15    state = models.ForeignKey(State, null=True)
     16    mpoly = models.MultiPolygonField(srid=4269) # Multipolygon in NAD83
     17    objects = models.GeoManager()
     18
    1319class CountyFeat(models.Model):
    1420    name = models.CharField(max_length=25)
    1521    poly = models.PolygonField(srid=4269)
Back to Top