GeoDjango:我可以在用户管理的内联中使用 OSMGeoAdmin 吗?

GeoDjango: Can I use OSMGeoAdmin in an Inline in the User Admin?

Profile 包含一个 PointField。我在 ProfileAdmin 中使用了 OSMGeoAdmin,这里:

class ProfileAdmin(admin.OSMGeoAdmin):
    model = Profile

但无法弄清楚如何在 UserAdmin 中显示的内联中使用它。我目前的设置如下:

# User Admin, with Profile attached
class ProfileInline(admin.StackedInline):
    model = Profile
    can_delete = False
    verbose_name_plural = 'Profile'  # As only one is displayed in this view

class UserAdmin(UserAdmin):
    inlines = (
        ProfileInline,
    )

admin.site.unregister(User)
admin.site.register(User, UserAdmin)

在这种情况下可以使用 class OSMGeoAdmin 吗?

我想这是一个很好的请求功能。

作为变通方法,您可以利用 InlineModelAdminModelAdmin 非常相似这一事实。两者都扩展 BaseModelAdmin.

StackedInlineModelAdmin 继承应该不会有太多冲突。

唯一的问题是两个 __init__() 方法都采用 2 个位置参数并调用 super().__init__() 时不带参数。所以无论继承顺序如何,它都会失败 TypeError: __init__() missing 2 required positional arguments: 'parent_model' and 'admin_site'

幸运的是,我们感兴趣的 InlineModelAdmin.__init__() 方法既不冗长也不复杂(没有太多 super().__init__() 级联调用)。

这是它的样子 in Django 1.9:

def __init__(self, parent_model, admin_site):
    self.admin_site = admin_site
    self.parent_model = parent_model
    self.opts = self.model._meta
    self.has_registered_model = admin_site.is_registered(self.model)
    super(InlineModelAdmin, self).__init__()
    if self.verbose_name is None:
        self.verbose_name = self.model._meta.verbose_name
    if self.verbose_name_plural is None:
        self.verbose_name_plural = self.model._meta.verbose_name_plural

这是它的父级 (BaseModelAdmin) 的样子 in Django 1.9

def __init__(self):
    overrides = FORMFIELD_FOR_DBFIELD_DEFAULTS.copy()
    overrides.update(self.formfield_overrides)
    self.formfield_overrides = overrides

现在让我们把它们放在一起:

from django.contrib.admin.options import FORMFIELD_FOR_DBFIELD_DEFAULTS

# User Admin, with Profile attached
class ProfileInline(OSMGeoAdmin, admin.StackedInline):
    model = Profile
    can_delete = False
    verbose_name_plural = 'Profile'  # As only one is displayed in this view

    def __init__(self, parent_model, admin_site):
        self.admin_site = admin_site
        self.parent_model = parent_model
        self.opts = self.model._meta
        self.has_registered_model = admin_site.is_registered(self.model)
        overrides = FORMFIELD_FOR_DBFIELD_DEFAULTS.copy()
        overrides.update(self.formfield_overrides)
        self.formfield_overrides = overrides
        if self.verbose_name is None:
            self.verbose_name = self.model._meta.verbose_name
        if self.verbose_name_plural is None:
            self.verbose_name_plural = self.model._meta.verbose_name_plural

class UserAdmin(UserAdmin):
    inlines = (
        ProfileInline,
    )

admin.site.unregister(User)
admin.site.register(User, UserAdmin)

这并不是一个真正令人满意的解决方案,因为它需要 copy/paste 来自 django 的一些代码,这些代码在您使用的 Django 版本中可能有所不同,并且在升级 Django 时可能很难维护。但是它应该可以工作,直到它作为混入或作为 InlineModelAdmin.

包含在 Django 中

注意:以上代码片段取自Django 1.9,您应该浏览github标签找到与您的版本对应的片段。

由于 Django 管理字段使用小部件,您可以使用 formfield_overrides. In this case, you can override all PointField instances to use the OSMWidget class 覆盖为 PointField 自动设置的小部件,如下所示:

from django.contrib.gis.forms.widgets import OSMWidget 

class ProfileInline(admin.StackedInline):
    model = Profile
    can_delete = False
    verbose_name_plural = 'Profile'  # As only one is displayed in this view
    formfield_overrides = {
        PointField: {"widget": OSMWidget},
    }