Django admin inline, обусловленный значениями полей модели
Я пытаюсь показать один из трех различных инлайнов дочерней модели для родительской модели, основываясь на значении выбранного поля в родительской модели. Я перепробовал все решения, которые всплывают в различных поисковых запросах Google, но, похоже, ничего не работает.
Сначала немного предыстории, я новичок в python и django, но пока что я чувствую, что быстро учусь. Я пытаюсь создать веб-приложение для размещения информации, связанной с различными пространственными местоположениями. Тип геометрии (geom_type) для каждого местоположения может быть разным (т.е. возможны точки, линии и полигоны). Для сбора этой информации я планирую создать родительскую модель (Location) для хранения имени и геом_типа (и, возможно, других метаданных). Пространственные данные, относящиеся к каждому местоположению, будут храниться в трех отдельных дочерних моделях, по одной для каждого геом_типа. При вводе данных я хотел бы создать новое местоположение и выбрать тип геома, который затем подтянет нужные данные в строку.
Теперь о деталях:
Модели
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)
Все три инлайна правильно отображаются в приведенном выше коде, как и ожидалось. Однако, когда я пытаюсь включить условную логику с различными вариациями get_inlines
или get_inline_instances
, всегда отображается только строка, связанная с последним утверждением "else".
Моя неудачная попытка
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 []
Я полагаю, что проблема возникает из-за того, что условные операторы неправильно ссылаются на поле модели. Но я никак не могу найти правильный способ достижения ожидаемого результата.
Используйте related_name
в модели, как показано ниже:
next_question = models.ForeignKey(Question, on_delete=models.CASCADE, null = True, blank = True, related_name='next_question', limit_choices_to={'is_active': True})
и затем fk_name
Как в примере ниже: Затем попробуйте. Надеюсь, вы сможете найти решение самостоятельно.
class Labels(admin.TabularInline):
model = Label
extra = 0
fk_name = "next_question"
Используйте admin.StackedInline
для OneToOne и admin.TabularInline
для ForeignKey.
class ProfileInline(admin.StackedInline):
model = Profile
can_delete = False
Создайте отдельную админку для 'Geometry' и 'Location', если вы их складываете.