2009-03-26 4 views
12

J'ai essayé différentes méthodes pour y parvenir.Django - Remplacer get_form pour personnaliser les formulaires d'administration en fonction de la demande

J'ai décidé de ne pas modifier formfield_for_dbfield car il n'obtient pas une copie de l'objet request et j'espérais éviter le hack thread_locals.

je me suis installé sur le remplacement get_form dans ma classe ModelAdmin et essayé les éléments suivants:

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) 

Lorsque j'imprime fieldsets ou declared_fieldsets à l'intérieur get_form je reçois Aucun (ou tout ce que je mets comme valeur initiale dans PageOptions). Pourquoi cela ne fonctionne-t-il pas et existe-t-il un meilleur moyen de le faire?

+1

Avez-vous essayé de déclarer un fieldset quelque part dans la classe PageOptions juste pour voir si cela fonctionne? –

+0

Oui, ça se passe quoi que ce soit dans get_form –

Répondre

8

Je ne sais pas pourquoi l'impression de la propriété ne vous voulez que vous venez d'affecter donne pas (je pense que peut-être cela dépend de l'endroit où l'impression, exactement), mais essayez primordial get_fieldsets à la place. La mise en œuvre de base ressemble à ceci:

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

à savoir Vous devriez pouvoir retourner vos tuples.

EDIT par andybak. 4 ans plus tard et j'ai retrouvé ma propre question en essayant de faire quelque chose de similaire sur un autre projet. Cette fois, je suis allé avec cette approche, bien que légèrement modifié pour éviter d'avoir à répéter la définition de fieldsets:

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

J'ai un exemple de code d'un de mes projets récents qui, je crois, peut vous aider. Dans cet exemple, les super-utilisateurs peuvent modifier chaque champ, tandis que tout le monde a le champ "description" exclu.

Notez que je pense qu'il est prévu que vous renvoyiez une classe Form de get_form, ce qui pourrait expliquer pourquoi la vôtre ne fonctionnait pas correctement.

Voici l'exemple:

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

Ça a l'air vraiment utile. Je suis au milieu d'une échéance en ce moment mais je vais essayer ça la semaine prochaine. PS Mon super appel n'entraîne-t-il pas le retour d'un formulaire? Je suis en train de modifier les paramètres et de retourner ce que get_form aurait retourné par lui-même. –

+0

Et qu'en est-il de l'utilisation de fieldsets avec cette solution? Si nous utilisons get_forms, nous semblons perdre la configuration des fieldsets et aussi du widget javascript DateTimeField. Merci. – vmassuchetto

+1

https://docs.djangoproject.com/fr/1.4/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_form semble être une bien meilleure solution. @ ryan-duffield – Saurabh

6

Ceci est ma solution:

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) 

L'espoir peut aider

+1

Plutôt que de supprimer le champ, vous pouvez le rendre en lecture seule (Django 1.2 et plus) - utilisez simplement self.readonly_fields au lieu de self.exclude. – jturnbull

+0

Ce n'est pas thread-safe. Ou il est thread-safe juste parce que vous avez d'autres conditions. Essayez de modifier kwargs ["exclude"] au lieu de self.exclude. – pista329

3

Ne pas changer la valeur des attributs de soi parce que ce n'est pas thread-safe. Vous devez utiliser les hooks pour remplacer ces valeurs.

6

Pour créer des formulaires d'administration personnalisés, nous avons défini une nouvelle classe qui peut être utilisée comme mixin.L'approche est très souple:

  • ModelAdmin: définir un jeu de champs contenant

    tous les champs
  • ModelForm: restreindre les champs étant représentés

  • FlexibleModelAdmin: remplaçant get_fieldsets méthode de ModelAdmin; retourne une fieldset réduite qui ne contient que les champs définis sous la forme d'administration


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) 

Dans le modèle d'administration que vous définissez fieldsets_proposed qui sert de modèle et contient tous les champs.

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) 

Dans vos formulaires de modèle, vous pouvez maintenant définir les champs à exclure/inclus. get_fieldset() de la classe mixin s'assure que seuls les champs définis dans le formulaire sont retournés.

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

Vous pouvez faire fieldsets et form propriétés et les ont émettent des signaux pour obtenir les formulaires/fieldsets souhaités.

Questions connexes