2009-03-26 22 views
12

He intentado varios métodos para lograr esto.Django - Sobreescribiendo get_form para personalizar formularios de administrador según solicitud

Decidí no anular formfield_for_dbfield ya que no obtiene una copia del objeto de solicitud y esperaba evitar el hack thread_locals.

que se establecieron en anulando get_form en mi clase ModelAdmin y trató lo siguiente:

class PageOptions(admin.ModelAdmin): 
    def get_form(self, request, obj=None, **kwargs): 
     if request.user.is_superuser: 
      self.fieldsets = ((None, {'fields': ('title','name',),}),) 
     else: 
      self.fieldsets = ((None, {'fields': ('title',),}),) 
     return super(PageOptions,self).get_form(request, obj=None, **kwargs) 

Al imprimir fieldsets o declared_fieldsets desde dentro get_form consigo Ninguno (o lo que sea me puse como un valor inicial en PageOptions).

¿Por qué esto no funciona y hay una mejor manera de hacerlo?

+1

¿Ha intentado declarar un fieldset en algún lugar de la clase PageOptions solo para ver si funciona? –

+0

Sí, ese programa no importa lo que se encuentre en get_form –

Respuesta

8

no tengo ni idea de por qué la impresión de la propiedad no da usted quiere que acaba de asignar (supongo que puede ser que depende de donde se imprime, exactamente), pero trata anulando get_fieldsets en su lugar. La implementación base es el siguiente:

def get_fieldsets(self, request, obj=None): 
    if self.declared_fieldsets: 
     return self.declared_fieldsets 
    form = self.get_formset(request).form 
    return [(None, {'fields': form.base_fields.keys()})] 

es decir, Deberías poder devolver tus tuplas.

EDITAR por andybak. 4 años después y encontré mi propia pregunta nuevamente cuando intentaba hacer algo similar en otro proyecto. Esta vez fui con este enfoque, aunque ligeramente modificado para no tener que repetir fieldsets definición:

def get_fieldsets(self, request, obj=None): 
    # Add 'item_type' on add forms and remove it on changeforms. 
    fieldsets = super(ItemAdmin, self).get_fieldsets(request, obj) 
    if not obj: # this is an add form 
     if 'item_type' not in fieldsets[0][1]['fields']: 
      fieldsets[0][1]['fields'] += ('item_type',) 
    else: # this is a change form 
     fieldsets[0][1]['fields'] = tuple(x for x in fieldsets[0][1]['fields'] if x!='item_type') 
    return fieldsets 
21

Tengo un código de muestra de un proyecto mío reciente que creo que puede ser de ayuda. En este ejemplo, los superusuarios pueden editar cada campo, mientras que todos los demás tienen el campo "descripción" excluido.

Tenga en cuenta que creo que se espera que devuelva una clase Form de get_form, que podría ser por qué la suya no estaba funcionando del todo bien.

Aquí está el ejemplo:

class EventForm(forms.ModelForm): 
    class Meta: 
     model = models.Event 
     exclude = ['description',] 

class EventAdminForm(forms.ModelForm): 
    class Meta: 
     model = models.Event 

class EventAdmin(admin.ModelAdmin): 

    def get_form(self, request, obj=None, **kwargs): 
     if request.user.is_superuser: 
      return EventAdminForm 
     else: 
      return EventForm 

admin.site.register(models.Event, EventAdmin) 
+0

Eso se ve realmente útil. Estoy en el medio de una fecha límite en este momento, pero lo probaré la próxima semana. PS ¿No resulta mi supercompañera un Formulario que se devuelve? Solo estoy modificando los parámetros y devolviendo lo que get_form hubiera devuelto por sí mismo. –

+0

¿Y qué pasa con el uso de conjuntos de campos con esta solución? Si usamos get_forms, parece que perdemos la configuración de los conjuntos de campo y también del widget de DateTimeField javascript. Gracias. – vmassuchetto

+1

https://docs.djangoproject.com/en/1.4/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_form parece ser una solución mucho mejor. @ ryan-duffield – Saurabh

6

Ésta es mi solución:

class MyModelAdmin(admin.ModelAdmin): 

    def get_form(self, request, obj=None, **kwargs): 
     if request.user.is_superuser: 
      self.exclude =() 
     else: 
      self.exclude = ('field_to_exclude',) 
     return super(MyModelAdmin, self).get_form(request, obj=None, **kwargs) 

La esperanza puede ayudar a

+1

En lugar de eliminar el campo, puede querer que sea de solo lectura (Django 1.2 y superior) - simplemente use self.readonly_fields en lugar de self.exclude. – jturnbull

+0

Esto no es seguro para subprocesos. O es seguro para subprocesos solo porque tienes otra condición. Intente modificar kwargs ["exclude"] en lugar de self.exclude. – pista329

3

No cambie el valor de atributos propios porque no es seguro para subprocesos. Debe usar los ganchos para anular esos valores.

6

Para crear formularios de administración personalizados, hemos definido una nueva clase que se puede usar como mixin.El enfoque es bastante flexible:

  • ModelAdmin: definir un conjunto de campos que contiene todos campos

  • ModelForm: Filtrar los campos que se muestran

  • FlexibleModelAdmin: imperiosas get_fieldsets-método de ModelAdmin; devuelve un conjunto de campos reducida que sólo contiene los campos definidos en el formulario de administración


class FlexibleModelAdmin(object): 
    ''' 
    adds the possibility to use a fieldset as template for the generated form 
    this class should be used as mix-in 
    ''' 

    def _filterFieldset(self, proposed, form): 
     ''' 
     remove fields from a fieldset that do not 
     occur in form itself. 
     ''' 

     allnewfields = [] 
     fields = form.base_fields.keys() 
     fieldset = [] 
     for fsname, fdict in proposed: 
      newfields = [] 
      for field in fdict.get('fields'): 
       if field in fields: 
        newfields.append(field) 
       allnewfields.extend(newfields) 
      if newfields: 
       newentry = {'fields': newfields} 
       fieldset.append([fsname, newentry]) 

     # nice solution but sets are not ordered ;) 
     # don't forget fields that are in a form but were forgotten 
     # in fieldset template 
     lostfields = list(set(fields).difference(allnewfields)) 
     if len(lostfields): 
      fieldset.append(['lost in space', {'fields': lostfields}]) 

     return fieldset 

    def get_fieldsets(self, request, obj=None): 
     ''' 
     Hook for specifying fieldsets for the add form. 
     ''' 

     if hasattr(self, 'fieldsets_proposed'): 
      form = self.get_form(request, obj) 
      return self._filterFieldset(self.fieldsets_proposed, form) 
     else: 
      return super(FlexibleModelAdmin, self).get_fieldsets(request, obj) 

En el modelo de administración defines fieldsets_proposed que sirve como plantilla y contiene todos los campos.

class ReservationAdmin(FlexibleModelAdmin, admin.ModelAdmin): 

    list_display = ['id', 'displayFullName'] 
    list_display_links = ['id', 'displayFullName'] 
    date_hierarchy = 'reservation_start' 
    ordering = ['-reservation_start', 'vehicle'] 
    exclude = ['last_modified_by'] 

    # considered by FlexibleModelAdmin as template 
    fieldsets_proposed = (
     (_('General'), { 
      'fields': ('vehicle', 'reservation_start', 'reservation_end', 'purpose') # 'added_by' 
     }), 
     (_('Report'), { 
      'fields': ('mileage') 
     }), 
     (_('Status'), { 
      'fields': ('active', 'editable') 
     }), 
     (_('Notes'), { 
      'fields': ('note') 
     }), 
    ) 
    ....   

    def get_form(self, request, obj=None, **kwargs): 
     ''' 
     set the form depending on the role of the user for the particular group 
     ''' 

     if request.user.is_superuser: 
      self.form = ReservationAdminForm 
     else: 
      self.form = ReservationUserForm 

     return super(ReservationAdmin, self).get_form(request, obj, **kwargs) 

admin.site.register(Reservation, ReservationAdmin) 

En los formularios de su modelo, ahora puede definir los campos que se excluirán/incluirán. get_fieldset() de mixin-class se asegura de que solo se devuelvan los campos definidos en el formulario.

class ReservationAdminForm(ModelForm): 
    class Meta: 
     model = Reservation 
     exclude = ('added_by', 'last_modified_by') 

class ReservationUserForm(BaseReservationForm): 
    class Meta: 
     model = Reservation 
     fields = ('vehicle', 'reservation_start', 'reservation_end', 'purpose', 'note') 
0

Se podría hacer fieldsets y form propiedades y hacer que se emiten señales para obtener los formularios/fieldsets deseados.

Cuestiones relacionadas