2010-11-30 4 views
10

Le paramètre admin filter_horizontal de Django donne un joli widget pour éditer une relation many-to-many. Mais c'est un paramètre spécial qui veut une liste de champs, donc il est seulement disponible sur le modèle (admin pour le) qui définit le ManyToManyField; comment puis-je obtenir le même widget sur le (admin pour le) autre modèle, en lisant la relation en arrière?Comment accéder aux deux directions de ManyToManyField dans Django Admin?

Mes modèles ressemblent à ceci (vous pouvez ignorer la complication User/UserProfile, c'est le vrai cas d'utilisation bien):

class Site(models.Model): 
    pass 
class UserProfile(models.Model): 
    user = models.OneToOneField(to=User,unique=True) 
    sites = models.ManyToManyField(Site,blank=True) 

je peux obtenir un widget bien sur le formulaire admin pour UserProfile avec

filter_horizontal = ('sites',) 

mais ne peut pas voir comment obtenir l'équivalent sur l'administrateur Site.

Je peux aussi faire une partie du chemin en ajoutant une ligne à SiteAdmin, défini comme:

class SiteAccessInline(admin_module.TabularInline): 
    model = UserProfile.sites.through 

Il est rond-point et unhandy bien; le widget n'est pas du tout intuitif pour gérer simplement la relation many-to-many.

Enfin, il y a un truc described here qui consiste à définir un autre ManyToManyField sur Site et en vous assurant qu'il pointe vers la même table de base de données (et sauter à travers quelques cerceaux parce que Django est pas vraiment conçu pour avoir des champs différents sur différents modèles décrivant les mêmes Les données). J'espère que quelqu'un peut me montrer quelque chose de plus propre.

Répondre

7

est ici un (plus ou moins) solution bien rangé, grâce à http://blog.abiss.gr/mgogoulos/entry/many_to_many_relationships_and et un correctif pour un bug Django pris de http://code.djangoproject.com/ticket/5247

from django.contrib import admin as admin_module 

class SiteForm(ModelForm): 
    user_profiles = forms.ModelMultipleChoiceField(
     label='Users granted access', 
     queryset=UserProfile.objects.all(), 
     required=False, 
     help_text='Admin users (who can access everything) not listed separately', 
     widget=admin_module.widgets.FilteredSelectMultiple('user profiles', False)) 

class SiteAdmin(admin_module.ModelAdmin): 
    fields = ('user_profiles',) 

    def save_model(self, request, obj, form, change): 
     # save without m2m field (can't save them until obj has id) 
     super(SiteAdmin, self).save_model(request, obj, form, change) 
     # if that worked, deal with m2m field 
     obj.user_profiles.clear() 
     for user_profile in form.cleaned_data['user_profiles']: 
      obj.user_profiles.add(user_profile) 

    def get_form(self, request, obj=None, **kwargs): 
     if obj: 
      self.form.base_fields['user_profiles'].initial = [ o.pk for o in obj.userprofile_set.all() ] 
     else: 
      self.form.base_fields['user_profiles'].initial = [] 
     return super(SiteAdmin, self).get_form(request, obj, **kwargs) 

Il utilise le même widget comme le réglage filter_horizontal, mais figés dans le code la forme.

+0

Merci beaucoup! :-D – Neal

+0

Quelqu'un sait-il d'une version mise à jour de cette idée qui est mise à jour pour django 1.4? Pour l'un, le bug a été corrigé (au cours des deux dernières années), et je ne sais pas pourquoi l'étendue SiteAdmin devrait avoir une idée de ce que signifie user_profiles. Et en fait, je reçois actuellement l'erreur Exception Type: \t ImproperlyConfigured Exception Valeur: \t « HospitalAdmin.fields » fait référence à champ qui manque de la forme « user_profiles ». Bien sûr, les noms des modèles sont différents, mais la structure est la même. Hôpital = Site. –

Questions connexes