2009-05-14 6 views
9

J'ai un modèle qui a un champ nommé « Etat »:comment modifier les choix sur les pages d'administration - django

class Foo(models.Model): 
    ... 
    state = models.IntegerField(choices = STATES) 
    ... 

Pour chaque état, les choix possibles sont un sous-ensemble de tous les États. Par exemple:

if foo.state == STATES.OPEN:  #if foo is open, possible states are CLOSED, CANCELED 
    ... 
if foo.state == STATES.PENDING: #if foo is pending, possible states are OPEN,CANCELED 
    ... 

En conséquence, lorsque des changements de foo.state à un nouvel état, son ensemble de choix possibles change également. Comment puis-je implémenter cette fonctionnalité sur les pages Admin add/change?

Répondre

9

Vous devez use a custom ModelForm dans la classe ModelAdmin pour ce modèle. Dans la méthode __init__ de mesure ModelForm, vous pouvez définir dynamiquement les choix pour ce champ:

class FooForm(forms.ModelForm): 
    class Meta: 
     model = Foo 

    def __init__(self, *args, **kwargs): 
     super(FooForm, self).__init__(*args, **kwargs) 
     current_state = self.instance.state 
     ...construct available_choices based on current state... 
     self.fields['state'].choices = available_choices 

Vous utiliseriez comme ceci:

class FooAdmin(admin.ModelAdmin): 
    form = FooForm 
+0

Que se passe-t-il sur les vues 'add' pour l'admin, puisqu'il n'y a pas self.instance, vous ne pouvez pas dépendre de l'instance pour le filtrage, il serait bien d'avoir l'objet request là –

+0

Oui, ce ModelForm devrait gérer l'absence d'auto-instance et de définir correctement les choix initiaux disponibles. Je ne sais pas pourquoi l'objet de requête est pertinent, mais vous y avez accès dans ModelAdmin.add_view (http://code.djangoproject.com/browser/django/trunk/django/contrib/admin/options.py# L704). –

+0

Est-il possible de changer les choix dans le modèle lui-même? Après tout, les choix sont initialement spécifiés dans le modèle, lors de la création du champ. –

-1

Je vois ce que vous essayez de faire, mais pourquoi ne pas simplement les afficher tous et si la personne choisit l'état actuel (déjà réglé), ne changez rien?

vous pouvez aussi construire juste une vue avec un formulaire pour fournir cette fonctionnalité

+0

c'est une possibilité, mais pas très élégante et sécurisée. changer l'état déclenche certains calculs et modifications des données à effectuer, donc je ne veux vraiment pas faire confiance aux utilisateurs, même s'ils sont des administrateurs. – shanyu

0

Cela semble être un emploi pour certains javascript. Vous voulez que la liste d'éléments dans une zone de sélection change en fonction de la valeur d'autre chose, qui est probablement une case à cocher ou un bouton radio. La seule façon de le faire de façon dynamique - sans que l'utilisateur enregistre le formulaire et recharger la page - serait avec javascript.

Vous pouvez charger un javascript personnalisé dans la page d'administration d'un modèle en utilisant la classe Media de ModelAdmin, documentée here.

+1

Non, il essaie de définir les choix pour la prochaine valeur d'un champ en fonction de la valeur actuelle de ce même champ - une différence clé. Changer les options dynamiquement côté client n'est donc pas pertinent; en fait, ce serait très déroutant. –

12

Lorsque vous créez une nouvelle interface d'administration pour un modèle (par exemple MyModelAdmin), il existe des méthodes spécifiques pour remplacer les choix par défaut d'un champ. Pour un choice field générique:

class MyModelAdmin(admin.ModelAdmin): 
    def formfield_for_choice_field(self, db_field, request, **kwargs): 
     if db_field.name == "status": 
      kwargs['choices'] = (
       ('accepted', 'Accepted'), 
       ('denied', 'Denied'), 
      ) 
      if request.user.is_superuser: 
       kwargs['choices'] += (('ready', 'Ready for deployment'),) 
     return super(MyModelAdmin, self).formfield_for_choice_field(db_field, request, **kwargs) 

Mais vous pouvez aussi passer outre des choix pour ForeignKey et Many to Many relations.

+3

Cela devrait être la réponse acceptée car c'est la solution la plus simple et la meilleure. –

+0

@shanyu Cela devrait être la réponse acceptée car c'est la façon la plus pythonique de gérer le problème. – Jay

Questions connexes