with template register loginview create and django permissions django-admin django-users

template - ¿Cómo evito la escalada de permisos en el administrador de Django cuando se concede el permiso de "cambio de usuario"?



django user model (5)

obtienen la capacidad de establecer la marca is_superuser en cualquier cuenta, incluida la propia. (!!!)

No solo esto, también obtienen la capacidad de otorgarse permisos uno por uno, el mismo efecto ...

Estoy seguro de que implica subclasificar django.contrib.auth.forms.UserChangeForm

Bueno, no necesariamente. El formulario que se ve en la página de cambios del administrador de django es creado dinámicamente por la aplicación de administración y se basa en UserChangeForm , pero esta clase apenas agrega validación de UserChangeForm regulares al campo de username .

y conectándolo a mi objeto UserAdmin ya personalizado ...

Un UserAdmin personalizado es el camino a seguir aquí. Básicamente, quieres cambiar la propiedad de los fieldsets a algo así:

class MyUserAdmin(UserAdmin): fieldsets = ( (None, {''fields'': (''username'', ''password'')}), (_(''Personal info''), {''fields'': (''first_name'', ''last_name'', ''email'')}), # Removing the permission part # (_(''Permissions''), {''fields'': (''is_staff'', ''is_active'', ''is_superuser'', ''user_permissions'')}), (_(''Important dates''), {''fields'': (''last_login'', ''date_joined'')}), # Keeping the group parts? Ok, but they shouldn''t be able to define # their own groups, up to you... (_(''Groups''), {''fields'': (''groups'',)}), )

Pero el problema aquí es que esta restricción se aplicará a todos los usuarios. Si esto no es lo que desea, podría, por ejemplo, anular change_view para comportarse de manera diferente dependiendo del permiso de los usuarios. Fragmento de código :

class MyUserAdmin(UserAdmin): staff_fieldsets = ( (None, {''fields'': (''username'', ''password'')}), (_(''Personal info''), {''fields'': (''first_name'', ''last_name'', ''email'')}), # No permissions (_(''Important dates''), {''fields'': (''last_login'', ''date_joined'')}), (_(''Groups''), {''fields'': (''groups'',)}), ) def change_view(self, request, *args, **kwargs): # for non-superuser if not request.user.is_superuser: try: self.fieldsets = self.staff_fieldsets response = super(MyUserAdmin, self).change_view(request, *args, **kwargs) finally: # Reset fieldsets to its original value self.fieldsets = UserAdmin.fieldsets return response else: return super(MyUserAdmin, self).change_view(request, *args, **kwargs)

Tengo un sitio de django con una gran base de clientes. Me gustaría dar a nuestro departamento de servicio al cliente la capacidad de alterar las cuentas de usuario normales, hacer cosas como cambiar contraseñas, direcciones de correo electrónico, etc. Sin embargo, si otorgo a alguien la auth | user | Can change user incorporada auth | user | Can change user auth | user | Can change user auth | user | Can change user permiso del auth | user | Can change user y pueden establecer la is_superuser en cualquier cuenta, incluida la propia. (!!!)

¿Cuál es la mejor manera de eliminar esta opción para el personal que no es superusuario? Estoy seguro de que implica subclasificar django.contrib.auth.forms.UserChangeForm y conectarlo a mi objeto UserAdmin ya personalizado ... de alguna manera. Pero no puedo encontrar ninguna documentación sobre cómo hacer esto, y todavía no entiendo lo interno lo suficientemente bien.


Código completo para django 1.1 (limitado a la información básica del usuario para el personal (no superusuarios))

from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ class MyUserAdmin(UserAdmin): my_fieldsets = ( (None, {''fields'': (''username'', ''password'')}), (_(''Personal info''), {''fields'': (''first_name'', ''last_name'', ''email'')}), ) def change_view(self, request, object_id, extra_context=None): # for non-superuser print ''test'' if not request.user.is_superuser: self.fieldsets = self.my_fieldsets response = UserAdmin.change_view(self, request, object_id, extra_context=None) return response else: return UserAdmin.change_view(self, request, object_id, extra_context=None) admin.site.unregister(User) admin.site.register(User, MyUserAdmin)


Este enfoque fue elaborado a partir de varios consejos útiles en la web. En este caso, estamos modificando UserAdmin para que, para el personal sin superusuario con permiso de agregar / cambiar usuario, los únicos permisos y grupos que pueden otorgar a otro usuario sean los que el miembro del personal ya tiene.

(para Django 1.11)

from django.contrib.auth.admin import UserAdmin, User from django.contrib import admin class RestrictedUserAdmin(UserAdmin): model = User def formfield_for_dbfield(self, db_field, **kwargs): field = super(RestrictedUserAdmin, self).formfield_for_dbfield(db_field, **kwargs) user = kwargs[''request''].user if not user.is_superuser: if db_field.name == ''groups'': field.queryset = field.queryset.filter(id__in=[i.id for i in user.groups.all()]) if db_field.name == ''user_permissions'': field.queryset = field.queryset.filter(id__in=[i.id for i in user.user_permissions.all()]) if db_field.name == ''is_superuser'': field.widget.attrs[''disabled''] = True return field admin.site.unregister(User) admin.site.register(User, RestrictedUserAdmin)

Esto también debe hacerse para GroupAdmin si un usuario tiene permiso para cambiar de grupo.


La siguiente parte de la respuesta aceptada tiene una condición de carrera en la que si dos usuarios del personal intentan acceder al formulario de administración al mismo tiempo, uno de ellos puede obtener el formulario de superusuario.

try: self.readonly_fields = self.staff_self_readonly_fields response = super(MyUserAdmin, self).change_view(request, object_id, form_url, extra_context, *args, **kwargs) finally: # Reset fieldsets to its original value self.fieldsets = UserAdmin.fieldsets

Para evitar esta condición de carrera (y en mi opinión, mejorar la calidad general de la solución), podemos anular los get_fieldsets() y get_readonly_fields() directamente:

class UserAdmin(BaseUserAdmin): staff_fieldsets = ( (None, {''fields'': (''username'')}), (''Personal info'', {''fields'': (''first_name'', ''last_name'', ''email'')}), # No permissions (''Important dates'', {''fields'': (''last_login'', ''date_joined'')}), ) staff_readonly_fields = (''username'', ''first_name'', ''last_name'', ''email'', ''last_login'', ''date_joined'') def get_fieldsets(self, request, obj=None): if not request.user.is_superuser: return self.staff_fieldsets else: return super(UserAdmin, self).get_fieldsets(request, obj) def get_readonly_fields(self, request, obj=None): if not request.user.is_superuser: return self.staff_readonly_fields else: return super(UserAdmin, self).get_readonly_fields(request, obj)


Muchas gracias a Clément. Lo que se me ocurrió al hacer lo mismo para mi sitio es que, además, necesitaba que todos los campos fueran de solo lectura para los usuarios que no sean yo. Así que basándome en la respuesta de Clément, escribí campos de solo lectura y campos de contraseñas que se ocultan cuando no se ve a uno mismo.

class MyUserAdmin(UserAdmin): model = User staff_self_fieldsets = ( (None, {''fields'': (''username'', ''password'')}), (_(''Personal info''), {''fields'': (''first_name'', ''last_name'', ''email'')}), # No permissions (_(''Important dates''), {''fields'': (''last_login'', ''date_joined'')}), ) staff_other_fieldsets = ( (None, {''fields'': (''username'', )}), (_(''Personal info''), {''fields'': (''first_name'', ''last_name'', ''email'')}), # No permissions (_(''Important dates''), {''fields'': (''last_login'', ''date_joined'')}), ) staff_self_readonly_fields = (''last_login'', ''date_joined'') def change_view(self, request, object_id, form_url='''', extra_context=None, *args, **kwargs): # for non-superuser if not request.user.is_superuser: try: if int(object_id) != request.user.id: self.readonly_fields = User._meta.get_all_field_names() self.fieldsets = self.staff_other_fieldsets else: self.readonly_fields = self.staff_self_readonly_fields self.fieldsets = self.staff_self_fieldsets response = super(MyUserAdmin, self).change_view(request, object_id, form_url, extra_context, *args, **kwargs) except: logger.error(''Admin change view error. Returned all readonly fields'') self.fieldsets = self.staff_other_fieldsets self.readonly_fields = (''first_name'', ''last_name'', ''email'', ''username'', ''password'', ''last_login'', ''date_joined'') response = super(MyUserAdmin, self).change_view(request, object_id, form_url, extra_context, *args, **kwargs) finally: # Reset fieldsets to its original value self.fieldsets = UserAdmin.fieldsets self.readonly_fields = UserAdmin.readonly_fields return response else: return super(MyUserAdmin, self).change_view(request, object_id, form_url, extra_context, *args, **kwargs)