2009-12-16 7 views
3

Comment définir la valeur d'un champ (qui est pertinent pour la forme, mais pas directement basé sur le même modèle) sur un formulaire (modèle) lorsqu'il est affiché dans l'admin?Valeur d'affichage Django du champ supplémentaire dans le modèle

est ici une version simplifiée de ce que je (mon application réelle/modèle/etc est plus compliqué):

  • A building a beaucoup room s
  • A room a beaucoup de morceaux de equipment

Modèles:

#spaces/models.py 
from django.db import models  

class Building(models.Model): 
    name=models.CharField(max_length=32) 
    def __unicode__(self): 
     return self.name 

class Room(models.Model): 
    number=models.CharField(max_length=8) 
    building=models.ForeignKey(Building) 
    def __unicode__(self): 
     return self.number 

class Equipment(models.Model): 
    tech = models.CharField(max_length=64) 
    room = models.ForeignKey(Room) 
    def __unicode__(self): 
    return self.tech 

Lors de l'ajout ou de la modification d'un équipement, il serait bon de pouvoir limiter les choix room (par bâtiment). Ce que je peux faire: J'ajoute un champ building au ModelForm, puis, comme il est modifié par l'utilisateur, un bit de JQuery dans le fichier modèle met à jour dynamiquement la liste des room s. La partie admin.py ressemble:

#spaces/admin.py 
from demo.spaces.models import Building, Room, Equipment 
from django.contrib import admin 
from django import forms 


class EquipmentForm(forms.ModelForm): 
    class Meta: 
     model = Equipment 
    building = forms.ModelChoiceField(Building.objects) 

class EquipmentAdmin(admin.ModelAdmin): 
    form = EquipmentForm 

admin.site.register(Equipment, EquipmentAdmin) 
admin.site.register(Building) 
admin.site.register(Room) 

Lorsque vous ajoutez un nouveau morceau de equipment, tout cela fonctionne bien - mon code JQuery affiche ----- jusqu'à ce qu'un bâtiment est sélectionné, à quel point le menu déroulant du champ room est activé et rempli avec les room appropriés pour ce bâtiment.

Le problème est: lors de l'affichage d'une pièce d'équipement existant (demo.com/admin/spaces/equipment/12/) ou si le formulaire d'ajout ne valide pas, le champ Room affiche correctement la room --mais le champ building est effacé. La valeur de clé étrangère existe dans l'instance de formulaire et l'administrateur prend automagiquement en charge la définition du champ room à cette valeur, mais la valeur du champ building doit être définie par moi.

Je peux obtenir la valeur sans problème, car il est facile dans la initialisation du formulaire pour vérifier qu'il est une instance, puis traversant de nouveau jusqu'à obtenir la valeur:

def __init__(self, *args, **kwargs): 
    super(EquipmentForm, self).__init__(*args, **kwargs) 
    if 'instance' in kwargs: 
     building_value = kwargs['instance'].room.building 

Mais que fais-je avec cette valeur pour que le champ l'affiche? La seule chose que je n'ai pas encore essayée est d'ajouter plus de code dans mon template pour utiliser Jquery pour obtenir la valeur et la définir à la fin, mais je préfère ne pas avoir le javascript dans la page la valeur, car il semble que quelque chose devrait être fait lorsque le formulaire est rendu ...

Des pensées? Merci pour votre aide!

Répondre

1

Vérifiez le paramètre initial du Field dans les formulaires here. Peut-être que définir le bâtiment avec l'ensemble initial à un objet Building aiderait.


De même, avez-vous vraiment besoin de limiter les choix à un bâtiment?Je viens de trouver suffisamment de modifier la méthode de __unicode__Room, il montre à la fois Building et Room Numéro:

def __unicode__(self): 
    return "Room nr %s in %s" % (self.number, self.building) 

Ensuite, vous obtiendrez une liste de toutes les chambres, mais facile à trouver à quel bâtiment ils appartiennent à ...

+0

je serais beaucoup mieux en mesure de limiter les choix pour le bâtiment, depuis A) Il y aura B) Je veux utiliser la même procédure pour limiter d'autres clés étrangères dans d'autres endroits. – mightyhal

+0

L'argument field.initial n'aidera pas, puisque la valeur que je veux définir pour le bâtiment est dynamique (dépend de l'instance). Form.initial semble prometteur, en définissant self.initial ['building'] dans __init__, et un print self.initial crache un dictionnaire de tous les champs et leurs valeurs ... mais quand il rend, il ne définit pas la valeur pour la construction (bien que cela ressemble à ce qu'il devrait) – mightyhal

0

Que pensez-vous de cela?

def __init__(self, *args, **kwargs): 
super(EquipmentForm, self).__init__(*args, **kwargs) 
if 'instance' in kwargs: 
    self.data['building']=kwargs['instance'].room.building 
+0

modifier self.data ['bâtiment'] dans le __init__ n'a aucun effet. (laisser tomber un self.data d'impression dans le __init__ me donne un a {}, alors peut-être que j'ai besoin de surcharger autre chose que __init__ pour affecter le self.data, ou self.data n'est pas la bonne chose à modifier) – mightyhal

0

Cela fonctionne pour moi:

def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, 
       initial=None, error_class=ErrorList, label_suffix=':', 
       empty_permitted=False, instance=None): 
     if instance: 
      initial = initial or {} 
      initial['field_name'] = instance.some_value 

     super(MyCustomForm, self).__init__(data, files, auto_id, prefix,initial, 
       error_class, label_suffix,empty_permitted, instance) 

Je ne l'utilise pas intentionnellement * args, ** kwargs parce que je n'ai pas vérifié comment ce constructeur est appelé elswere dans le code (par exemple et initial pourrait être dans * args ou ** kwargs).

1

Celui-ci devrait fonctionner:

class EquipmentForm(ModelForm): 
    def __init__(self, *args, **kwargs): 
     kwargs['initial']=kwargs.get('initial',{}) 
     if kwargs['instance']: 
      kwargs['initial']['building']=kwargs['instance'].building 
     super(EquipmentForm, self).__init__(*args, **kwargs) 

Dans le views.py:

instance.building="some_building" 
form = EquipmentForm(request.POST, instance=instance) 
Questions connexes