将自定义 UserCreationForm 与 GeoDjango 管理员 (OSMGeoAdmin) 结合使用

Use custom UserCreationForm with GeoDjango admin (OSMGeoAdmin)

Django==2.2.1
GDAL==2.3.2
django-username-email==2.2.4

我有一个简单的 Django 应用程序,带有基于 django-username-emailAbstractCUser 的自定义用户模型,它从用户模型中删除了 username,改用电子邮件地址.在用户模型上,我定义了一个 PointField 字段来存储用户的当前位置。

models.py

from django.contrib.gis.db import models as gis_models
from cuser.models import AbstractCUser

class User(AbstractCUser):
    """Custom user model that extends AbstractCUser."""

    current_location = gis_models.PointField(null=True, blank=True,)

我想在 Django 管理中注册这个模型,这样我就可以注册新用户并 view/set 他们使用地图小部件的位置。如果我将基于 admin.OSMGeoAdmin 的自定义用户管理员与自定义用户更改表单结合使用,则这种方法有效:

admin.py

from django.contrib.gis import admin
from django.contrib.auth import get_user_model
from .forms import CustomUserCreationForm, CustomUserChangeForm

class CustomUserAdmin(admin.OSMGeoAdmin):
    model = get_user_model()
    add_form = CustomUserCreationForm    # <- there seems to be a problem here
    form = CustomUserChangeForm

    list_display = ['email', 'last_name', 'first_name']
    readonly_fields = ['last_login', 'date_joined']


admin.site.register(get_user_model(), CustomUserAdmin)

forms.py

from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm, UserChangeForm    

class CustomUserCreationForm(UserCreationForm):

    class Meta(UserCreationForm.Meta):
        model = get_user_model()
        exclude = ('username',)


class CustomUserChangeForm(UserChangeForm):

    class Meta(UserChangeForm.Meta):
        model = get_user_model()
        fields = (
            'email',
            'first_name',
            'last_name',
            'current_location',
            # ...
        )

当我在 Django 管理中打开现有用户记录时,必填字段按预期显示,当前位置显示在地图上。然而,相同的表单似乎也用于用户创建(即 add_form 无效),这使得无法通过管理员添加新用户,因为密码设置功能未正确嵌入(见屏幕射击)。

问题似乎是 OSMGeoAdmininherits from ModelAdmin,与标准 UserAdmin 相比,它没有 add_form 属性。

在这种情况下是否有任何方法可以指定自定义用户创建表单(最好是 django-username-email 提供的 UserCreationForm 同时保持在用户更改表单上的地图上显示点字段的能力?

您需要像 django.contrib.auth.admin.UserAdmin 那样覆盖 get_form

def get_form(self, request, obj=None, **kwargs):
    """
    Use special form during user creation
    """
    defaults = {}
    if obj is None:
        defaults['form'] = self.add_form
    defaults.update(kwargs)
    return super().get_form(request, obj, **defaults)

根据 schillingt 的建议,这是我最终使用的代码:

from django.contrib.gis import admin
from django.contrib.auth import get_user_model
from cuser.forms import UserCreationForm
from .forms import CustomUserChangeForm


class CustomUserAdmin(admin.OSMGeoAdmin):
    model = get_user_model()
    add_form = UserCreationForm
    form = CustomUserChangeForm

    list_display = ['email', 'last_name', 'first_name']
    readonly_fields = ['last_login', 'date_joined']

    def get_form(self, request, obj=None, **kwargs):
        """
        Use special form during user creation.

        Override get_form method in the same manner as django.contrib.auth.admin.UserAdmin does.
        """
        defaults = {}
        if obj is None:
            defaults['form'] = self.add_form
        defaults.update(kwargs)
        return super().get_form(request, obj, **defaults)


admin.site.register(get_user_model(), CustomUserAdmin)