#33049: TabularInline doesn't render properly MultiPolygonField in Django Admin
-------------------------------------+-------------------------------------
               Reporter:  Vladyslav  |          Owner:  nobody
  Krylasov                           |
                   Type:             |         Status:  new
  Uncategorized                      |
              Component:  GIS        |        Version:  2.2
               Severity:  Normal     |       Keywords:  gis, admin,
           Triage Stage:             |  MultiPolygonField, TabularInline
  Unreviewed                         |      Has patch:  0
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  1          |
-------------------------------------+-------------------------------------
 I have a Django model that contains `MultiPolygonField`, so wanted to
 render it through the admin dashboard as an inline field.
 {{{
 #!div style="font-size: 80%"
 models.py
   {{{#!python
   class Geometry(models.Model):
     zone = models.ForeignKey(to=Zone, on_delete=models.CASCADE)
     mpoly = models.MultiPolygonField(null=True, blank=True)
   }}}
 admin.py
   {{{#!python
   class GeometryInline(admin.TabularInline):
     model = Geometry
     max_num = 1

   class ZoneAdmin(admin.GeoModelAdmin):
     model = Zone
     ...
     inlines = (GeometryInline,)

   }}}
 }}}
 This renders such result:
 [[Image(https://i.ibb.co/njML4CP/Screenshot-
 from-2021-08-20-13-27-32.png)]]

 But when I make `django.contrib.gis.admin.GeoModelAdmin` as a mixin it
 works just fine.
 {{{
 #!div style="font-size: 80%"
 admin.py
   {{{#!python
 from django.contrib.gis import admin
 from django.contrib.gis.admin.widgets import OpenLayersWidget
 from django.contrib.gis.db import models
 from django.contrib.gis.gdal import OGRGeomType
 from django.forms import Media


 class GeoAdminMixin:
     """
     Copied over from django.contrib.gis.admin.GeoModelAdmin

     The administration options class for Geographic models. Map settings
     may be overloaded from their defaults to create custom maps.
     """

     # The default map settings that may be overloaded -- still subject
     # to API changes.
     default_lon = 0
     default_lat = 0
     default_zoom = 4
     display_wkt = False
     display_srid = False
     extra_js = []
     num_zoom = 18
     max_zoom = False
     min_zoom = False
     units = False
     max_resolution = False
     max_extent = False
     modifiable = True
     mouse_position = True
     scale_text = True
     layerswitcher = True
     scrollable = True
     map_width = 600
     map_height = 400
     map_srid = 4326
     map_template = 'gis/admin/openlayers.html'
     openlayers_url =
 'https://cdnjs.cloudflare.com/ajax/libs/openlayers/2.13.1/OpenLayers.js'
     point_zoom = num_zoom - 6
     wms_url = 'http://vmap0.tiles.osgeo.org/wms/vmap0'
     wms_layer = 'basic'
     wms_name = 'OpenLayers WMS'
     wms_options = {'format': 'image/jpeg'}
     debug = False
     widget = OpenLayersWidget

     @property
     def media(self):
         "Injects OpenLayers JavaScript into the admin."
         return super().media + Media(js=[self.openlayers_url] +
 self.extra_js)

     def formfield_for_dbfield(self, db_field, request, **kwargs):
         """
         Overloaded from ModelAdmin so that an OpenLayersWidget is used
         for viewing/editing 2D GeometryFields (OpenLayers 2 does not
 support
         3D editing).
         """
         if isinstance(db_field, models.GeometryField) and db_field.dim <
 3:
             # Setting the widget with the newly defined widget.
             kwargs['widget'] = self.get_map_widget(db_field)
             return db_field.formfield(**kwargs)
         else:
             return super().formfield_for_dbfield(db_field, request,
 **kwargs)

     def get_map_widget(self, db_field):
         """
         Return a subclass of the OpenLayersWidget (or whatever was
 specified
         in the `widget` attribute) using the settings from the attributes
 set
         in this class.
         """
         is_collection = db_field.geom_type in (
             'MULTIPOINT',
             'MULTILINESTRING',
             'MULTIPOLYGON',
             'GEOMETRYCOLLECTION',
         )
         if is_collection:
             if db_field.geom_type == 'GEOMETRYCOLLECTION':
                 collection_type = 'Any'
             else:
                 collection_type =
 OGRGeomType(db_field.geom_type.replace('MULTI', ''))
         else:
             collection_type = 'None'

         class OLMap(self.widget):
             template_name = self.map_template
             geom_type = db_field.geom_type

             wms_options = ''
             if self.wms_options:
                 wms_options = ["%s: '%s'" % pair for pair in
 self.wms_options.items()]
                 wms_options = ', %s' % ', '.join(wms_options)

             params = {
                 'default_lon': self.default_lon,
                 'default_lat': self.default_lat,
                 'default_zoom': self.default_zoom,
                 'display_wkt': self.debug or self.display_wkt,
                 'geom_type': OGRGeomType(db_field.geom_type),
                 'field_name': db_field.name,
                 'is_collection': is_collection,
                 'scrollable': self.scrollable,
                 'layerswitcher': self.layerswitcher,
                 'collection_type': collection_type,
                 'is_generic': db_field.geom_type == 'GEOMETRY',
                 'is_linestring': db_field.geom_type in ('LINESTRING',
 'MULTILINESTRING'),
                 'is_polygon': db_field.geom_type in ('POLYGON',
 'MULTIPOLYGON'),
                 'is_point': db_field.geom_type in ('POINT', 'MULTIPOINT'),
                 'num_zoom': self.num_zoom,
                 'max_zoom': self.max_zoom,
                 'min_zoom': self.min_zoom,
                 'units': self.units,  # likely should get from object
                 'max_resolution': self.max_resolution,
                 'max_extent': self.max_extent,
                 'modifiable': self.modifiable,
                 'mouse_position': self.mouse_position,
                 'scale_text': self.scale_text,
                 'map_width': self.map_width,
                 'map_height': self.map_height,
                 'point_zoom': self.point_zoom,
                 'srid': self.map_srid,
                 'display_srid': self.display_srid,
                 'wms_url': self.wms_url,
                 'wms_layer': self.wms_layer,
                 'wms_name': self.wms_name,
                 'wms_options': wms_options,
                 'debug': self.debug,
             }

         return OLMap



   class GeometryInline(GeoAdminMixin, admin.TabularInline):
     model = Geometry
     max_num = 1
   }}}
 }}}

 Result:
 [[Image(https://i.ibb.co/PQftkKt/Screenshot-
 from-2021-08-24-15-11-11.png)]]

 Am I missing something or Django needs a mixin for this situation?

-- 
Ticket URL: <https://code.djangoproject.com/ticket/33049>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/055.e74fa4f7a7cc2cb4b839efa54ba80ed3%40djangoproject.com.

Reply via email to