En admin me gustaría deshabilitar un campo cuando se modifica un objeto, pero que sea necesario cuando la adición de nuevos objetos.

¿Cuál es el django manera de ir sobre esto?

InformationsquelleAutor frnhr | 2010-12-03

7 Comentarios

  1. 154

    Puede invalidar la administración del get_readonly_fields método:

    class MyModelAdmin(admin.ModelAdmin):
    
        def get_readonly_fields(self, request, obj=None):
            if obj: # editing an existing object
                return self.readonly_fields + ('field1', 'field2')
            return self.readonly_fields
    • Menor/mayor advertencia: Esto no funciona para los elementos incorporados. La dinámica de «añadir otro X» botón de muestra el campo readonly como «(Ninguno)», no un campo de formulario como era de esperar.
  2. 10

    Si quieres conjunto de todos los campos como de sólo lectura justo en el cambio de punto de vista, invalidar la administración del get_readonly_fields:

    def get_readonly_fields(self, request, obj=None):
        if obj: # editing an existing object
            # All model fields as read_only
            return self.readonly_fields + tuple([item.name for item in obj._meta.fields])
        return self.readonly_fields

    Y si desea ocultar los botones guardar en cambiar de vista:

    1. Cambiar la vista

      def change_view(self, request, object_id, form_url='', extra_context=None):
          ''' customize edit form '''
          extra_context = extra_context or {}
          extra_context['show_save_and_continue'] = False
          extra_context['show_save'] = False
          extra_context['show_save_and_add_another'] = False # this not works if has_add_permision is True
          return super(TransferAdmin, self).change_view(request, object_id, extra_context=extra_context)
    2. Cambiar los permisos de si el usuario está tratando de edición:

      def has_add_permission(self, request, obj=None):
         # Not too much elegant but works to hide show_save_and_add_another button
          if '/change/' in str(request):
              return False
          return True

      Esta solución ha sido probado con el Django 1.11

    • Perfecto. Esto es exactamente lo que yo necesitaba!
  3. 3

    FYI: en caso de que alguien más se ejecuta en la misma de los dos problemas que me encontré:

    1. Aún debe declarar cualquier permanentemente readonly_fields en el cuerpo de la clase, como el readonly_fields atributo de clase se tendrá acceso desde la validación (ver django.contrib.admin.validación: validate_base(), línea de.213 appx)

    2. Esto no funciona con elementos incorporados como el obj pasa a get_readonly_fields() es el padre obj (tengo dos más chapucero y baja de soluciones de seguridad mediante el uso de css o js)

    • 2. punto – que es debido a un error en el admin: #15602 Parece que no se fijo que pronto (última actividad 2 años atrás), así que parece que estamos a la izquierda hasta CSS/JS soluciones.
  4. 2

    Una variación sobre la base del anterior excelente sugerencia de Bernhard Vallant, que también se conserva cualquier posible la personalización proporcionado por la clase base (si alguno):

    class MyModelAdmin(BaseModelAdmin):
    
        def get_readonly_fields(self, request, obj=None):
            readonly_fields = super(MyModelAdmin, self).get_readonly_fields(request, obj)
            if obj: # editing an existing object
                return readonly_fields + ['field1', ..]
            return readonly_fields
  5. 0

    Usted puede hacer esto mediante la invalidación de la formfield_for_foreignkey método de la ModelAdmin:

    from django import forms
    from django.contrib import admin
    
    from yourproject.yourapp.models import YourModel
    
    class YourModelAdmin(admin.ModelAdmin):
    
        class Meta:
            model = YourModel
    
        def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
            # Name of your field here
            if db_field.name == 'add_only':
                if request:
                    add_opts = (self._meta.app_label, self._meta.module_name)
                    add = u'/admin/%s/%s/add/' % add_opts
                    if request.META['PATH_INFO'] == add:
                        field = db_field.formfield(**kwargs)
                    else:
                        kwargs['widget'] = forms.HiddenInput()
                        field = db_field.formfield(**kwargs)
                return field
            return admin.ModelAdmin(self, db_field, request, **kwargs)
  6. 0

    Tengo un problema similar. He resuelto con «add_fieldsets» y «restricted_fieldsets» en el ModelAdmin.

    from django.contrib import admin  
    class MyAdmin(admin.ModelAdmin):
     declared_fieldsets = None
     restricted_fieldsets = (
        (None, {'fields': ('mod_obj1', 'mod_obj2')}),
        ( 'Text', {'fields': ('mod_obj3', 'mod_obj4',)}),
     )
    
     add_fieldsets = (
                (None, {
                 'classes': ('wide',),
                 'fields': ('add_obj1', 'add_obj2', )}),
                 )

    Por favor, véase por ejemplo: http://code.djangoproject.com/svn/django/trunk/django/contrib/auth/admin.py

    Pero esto no proteger su modelo de posteriores cambios de «add_objX».
    Si desea que este demasiado, creo que tienes que ir por el camino sobre el Modelo de la clase de función «guardar» y comprobar los cambios.

    Ver: http://www.djangoproject.com/documentation/models/save_delete_hooks/

    Greez, Nick

  7. 0

    La situación con de formularios en línea, aún no se soluciona por Django 2.2.x, pero el solución de John en realidad es bastante inteligente.

    Código ligeramente atentos a mi situación:

    class NoteListInline(admin.TabularInline):
    """ Notes list, readonly """
        model = Note
        verbose_name = _('Note')
        verbose_name_plural = _('Notes')
        extra = 0
        fields = ('note', 'created_at')
        readonly_fields = ('note', 'created_at')
    
        def has_add_permission(self, request, obj=None):
        """ Only add notes through AddInline """
        return False
    
    class NoteAddInline(admin.StackedInline):
        """ Notes edit field """
        model = Note
        verbose_name = _('Note')
        verbose_name_plural = _('Notes')
        extra = 1
        fields = ('note',)
        can_delete = False
    
        def get_queryset(self, request):
            queryset = super().get_queryset(request)
            return queryset.none()  # no existing records will appear
    
    @admin.register(MyModel)
    class MyModelAdmin(admin.ModelAdmin):
        # ...
        inlines = (NoteListInline, NoteAddInline)
        # ...

Dejar respuesta

Please enter your comment!
Please enter your name here