2009-03-26 7 views
12

Ho provato vari metodi per raggiungere questo obiettivo.Django - Overriding get_form per personalizzare i moduli di amministrazione in base alla richiesta

Ho deciso di non sovrascrivere formfield_for_dbfield in quanto non ottiene una copia dell'oggetto richiesta e speravo di evitare l'hack thread_locals.

ho optato per l'override get_form nella mia classe ModelAdmin e provato quanto segue:

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) 

Quando stampo fieldsets o declared_fieldsets dall'interno get_form ricevo Nessuno (o qualsiasi altra cosa ho impostato come valore iniziale in PageOptions).

Perché questo non funziona e c'è un modo migliore per farlo?

+1

Hai provato a dichiarare un fieldset da qualche parte nella classe PageOptions solo per vedere se funziona? –

+0

Sì, lo spettacolo è attivo, non importa cosa c'è in get_form –

risposta

8

Non ho idea del perché la stampa la proprietà non dà volete appena assegnato (immagino può essere che dipende da dove si stampa, appunto), ma prova sovrascrivendo get_fieldsets invece. L'implementazione di base è simile al seguente:

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()})] 

Vale a dire dovresti essere in grado di restituire le tue tuple.

MODIFICA da andybak. 4 anni dopo e ho trovato di nuovo la mia domanda quando cercavo di fare qualcosa di simile su un altro progetto. Questa volta sono andato con questo approccio, anche se leggermente modificato per evitare di dover ripetere fieldsets definizione:

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

Ho un codice di esempio da un mio recente progetto che credo possa aiutarti. In questo esempio, i super user possono modificare ogni campo, mentre tutti gli altri hanno il campo "description" escluso.

Nota che penso che ci si aspetta che tu restituisca una classe Form da get_form, che potrebbe essere il motivo per cui il tuo non funzionava correttamente.

Ecco l'esempio:

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

Sembra davvero utile. Sono nel bel mezzo di una scadenza in questo momento, ma ci proverò la prossima settimana. PS La mia super chiamata non restituisce un modulo? Sto solo modificando i parametri e restituendo ciò che get_form avrebbe restituito da solo. –

+0

E che ne pensi di usare i set di campi con questa soluzione? Se usiamo get_forms sembriamo perdere la configurazione per i set di campi e anche il widget javascript DateTimeField. Grazie. – vmassuchetto

+1

https://docs.djangoproject.com/en/1.4/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_form sembra essere la soluzione migliore. @ ryan-duffield – Saurabh

6

Questa è la mia soluzione:

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 speranza può aiutare

+1

Piuttosto che rimuovere il campo, potresti voler renderlo di sola lettura (Django 1.2 e versioni successive) - usa solo self.readonly_fields invece di self.exclude. – jturnbull

+0

Questo non è thread-safe. Oppure è thread-safe solo perché hai un'altra condizione. Prova a modificare kwargs ["exclude"] invece di self.exclude. – pista329

3

non si modifica il valore di di auto attributi perché non è thread-safe. È necessario utilizzare qualunque hook per sovrascrivere tali valori.

6

Per creare moduli di amministrazione personalizzati abbiamo definito una nuova classe che può essere utilizzata come mixin.L'approccio è abbastanza flessibile:

  • ModelAdmin: definire un fieldset contenente tutti campi

  • ModelForm: restringono i campi essendo mostrati

  • FlexibleModelAdmin: override get_fieldsets-metodo di ModelAdmin; restituisce un fieldset ridotta che contiene solo i campi definiti nella forma di amministrazione


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) 

Nel modello di amministrazione si definisce fieldsets_proposed che serve da modello e contiene tutti i campi.

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) 

nel modello costituisce ora è possibile definire i campi che devono essere esclusi/inclusi. get_fieldset() della classe mixin si assicura che vengano restituiti solo i campi definiti nel modulo.

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

Si potrebbe fare fieldsets e form proprietà e li emettono segnali per ottenere i desiderati forme/fieldsets.

Problemi correlati