Django admin UserChangeForm с полем UUID в качестве первичного ключа - PullRequest
0 голосов
/ 05 ноября 2018

Я работаю над приложением Django, которое будет содержать конфиденциальные данные пользователя, поэтому я предпринимаю ряд шагов для анонимизации объектов пользователя и их данных.

Я создал пользовательский объект «Пользователь», который подклассирует модель AbstractBaseUser следующим образом:

class User(AbstractBaseUser, PermissionsMixin):
    (...)
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    (...)

Имеет следующий связанный ModelAdmin объект:

from django.contrib.auth.forms import UserChangeForm


@admin.register(User)
class UserAdmin(admin.ModelAdmin):
    form = UserChangeForm

Я использую поля UUID для первичных ключей, чтобы обеспечить максимальную анонимность, но я хотел бы иметь возможность сбрасывать пароли пользователей в Django Admin (как вы можете сделать с объектом User по умолчанию)

Однако, когда я открываю пользователя в админке и нажимаю ссылку для смены пароля, я получаю следующее сообщение об ошибке:

User with ID "21362aca-6918-47ea-9b29-275350a89c54/password" doesn't exist. Perhaps it was deleted?

Администратор URL все еще ожидает URL с целым числом в качестве значения pk.

Так что мне кажется, что мне нужно переопределить конфигурацию URL-адреса администратора в определении ModelAdmin, но мне было интересно, есть ли более простой способ достичь желаемого результата - так как я представляю, что замена User.pk на поле UUID довольно обычное явление, и я представляю, что многие разработчики столкнулись с этой проблемой. Я пытался найти какие-то настройки / переключатели для достижения этой цели, но безрезультатно, я что-то упустил?

1 Ответ

0 голосов
/ 07 ноября 2018

Ваш UserAdmin наследует от ModelAdmin, который предоставляет URL-адреса с помощью метода get_urls для представлений добавления, изменения, удаления и т. Д., Но также и URL-адрес "отката":

urlpatterns = [
    #...
    url(r'^(.+)/change/$', wrap(self.change_view), name='%s_%s_change' % info),
    # For backwards compatibility (was the change url before 1.9)
    path('<path:object_id>/', wrap(RedirectView.as_view(
        pattern_name='%s:%s_%s_change' % ((self.admin_site.name,) + info)
    ))),
]

URL, по которому вы переходите, выглядит как /user/<UUID>/password/, который соответствует регулярному выражению шаблона отката - который перенаправляет вас на страницу изменений таким образом, что он использует <UUID>/password в качестве object_id.

Попробуйте вместо этого унаследовать от django.contrib.auth.admin.UserAdmin, так как его метод get_urls предоставляет нужный шаблон URL.


Еще немного возни ...
Если вашим полем первичного ключа является AutoField, весь процесс вызовет ValueError('invalid literal for int') при попытке привести int('some_integer/password') в django.db.models.fields.AutoField.get_prep_value, чтобы подготовить значение для запроса. Понятный!

HOWEVER : UUIDField использует метод get_prep_value базового класса Field. Field.get_prep_value просто возвращает значение, даже не проверяя (в конце концов, проверка значения должна быть задачей UUIDField). Таким образом, вы получите запрос, который ищет фиктивного uuid '<uuid>/password', которого, очевидно, не существует.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...