Django Admin:根据父模型字段值动态显示对应子模型Inline
动态显示Django Admin Inline:根据Geometry类型匹配对应子模型
我是Python和Django新手,正在开发存储空间位置信息的Web应用。父模型Location关联Geometry模型(包含Point、Linestring、Polygon三种几何类型),对应三个子模型Point、Linestring、Polygon分别存储不同类型空间数据。
希望在Django Admin中创建Location实例时,根据所选geom_type字段值动态显示对应子模型Inline。当前代码会显示全部三个Inline,尝试通过get_inlines实现条件逻辑时,始终仅显示else分支结果,推测是字段引用方式错误,求正确实现方法。
模型代码
from django.contrib.gis.db import models class Geometry(models.Model): TYPE = ( ('Point', 'Point'), ('Linestring', 'Linestring'), ('Polygon', 'Polygon'), ) geom_type = models.CharField('Geometry Type', choices = TYPE, max_length = 30) class Meta: verbose_name = 'Geometry' verbose_name_plural = 'Geometries' def __str__(self): return self.geom_type class Location(models.Model): name = models.CharField('Location Name', max_length = 50) geom_type = models.ForeignKey(Geometry, on_delete=models.CASCADE) def __str__(self): return self.name class Point(models.Model): name = models.OneToOneField(Location, on_delete=models.CASCADE) geometry = models.PointField() def __str__(self): return self.name.name class Linestring(models.Model): name = models.OneToOneField(Location, on_delete=models.CASCADE) geometry = models.LineStringField() def __str__(self): return self.name.name class Polygon(models.Model): name = models.OneToOneField(Location, on_delete=models.CASCADE) geometry = models.PolygonField() def __str__(self): return self.name.name
Admin代码
from django.contrib.gis import admin from leaflet.admin import LeafletGeoAdmin, LeafletGeoAdminMixin from .models import Geometry, Location, Point, Linestring, Polygon class GeometryAdmin(admin.ModelAdmin): list_display = ('id', 'geom_type') admin.site.register(Geometry, GeometryAdmin) class PointInline(LeafletGeoAdminMixin, admin.StackedInline): model = Point class LinestringInline(LeafletGeoAdminMixin, admin.StackedInline): model = Linestring class PolygonInline(LeafletGeoAdminMixin, admin.StackedInline): model = Polygon class LocationAdmin(admin.ModelAdmin): model = Location list_display = ('id', 'name', 'geom_type') inlines = [ PointInline, LinestringInline, PolygonInline ] admin.site.register(Location, LocationAdmin)
失败的尝试代码
def get_inlines(self, request, obj: Location): if obj.geom_type == 'Point': return [PointInline] elif obj.geom_type == 'Location': return [LinestringInline] elif obj.geom_type == 'Polygon': return [PolygonInline] else: return []
解决方法
你失败的核心问题有两个:
obj.geom_type是Geometry模型的实例,不是字符串,直接和字符串比较永远不成立,会走到else分支;- elif分支里把
Linestring误写成了Location。
修改后的LocationAdmin代码如下:
class LocationAdmin(admin.ModelAdmin): model = Location list_display = ('id', 'name', 'geom_type') def get_inlines(self, request, obj=None): # 创建新实例时,obj为None,先不显示任何Inline if not obj: return [] # 获取关联Geometry实例的geom_type字符串值 selected_type = obj.geom_type.geom_type if selected_type == 'Point': return [PointInline] elif selected_type == 'Linestring': return [LinestringInline] elif selected_type == 'Polygon': return [PolygonInline] else: return []
补充说明
- 上述代码在编辑已有Location实例时可以正常动态显示对应Inline;
- 如果希望在创建新Location时,选择geom_type后实时显示对应Inline,需要借助JavaScript实现动态刷新(因为创建时obj还未保存,服务器端无法获取选择值)。新手可以先实现编辑场景的功能,再逐步优化创建流程。
内容的提问来源于stack exchange,提问作者fishdata
相关产品推荐
相关产品推荐

