2010-11-30 9 views
10

La configuración admin filter_horizontal de Django ofrece un buen widget para editar una relación de muchos a muchos. Pero es una configuración especial que quiere una lista de campos, por lo que solo está disponible en el modelo (administrador para) que define el ManyToManyField; ¿Cómo puedo obtener el mismo widget en el (administrador para) otro modelo, leyendo la relación al revés?¿Cómo acceder a ambas direcciones de ManyToManyField en Django Admin?

Mis modelos se parecen a esto (no dude en hacer caso omiso de la complicación User/UserProfile, es el caso de uso real, aunque):

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

yo puede conseguir un widget agradable en la forma de administración para UserProfile con

filter_horizontal = ('sites',) 

pero no puedo ver cómo obtener el equivalente en el administrador Site.

también puedo conseguir parte vías mediante la adición de una línea de SiteAdmin, definida como:

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

Es rotonda y poco manejable sin embargo; el widget no es en absoluto intuitivo para simplemente administrar la relación de muchos a muchos.

Por último, hay un truco described here que implica la definición de otra ManyToManyField en Site y asegurarse de que apunta a la misma tabla de base de datos (y saltar a través de unos aros porque Django no es realmente diseñado para tener diferentes campos en diferentes modelos que describen la misma datos). Espero que alguien me pueda mostrar algo más limpio.

Respuesta

7

he aquí una solución (más o menos) ordenada, gracias a http://blog.abiss.gr/mgogoulos/entry/many_to_many_relationships_and y con una solución para un error de Django tomado 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) 

Se utiliza el mismo artilugio como el ajuste filter_horizontal, pero en forma fija en la forma.

+0

¡Muchas gracias! :-D – Neal

+0

¿Alguien sabe de una versión actualizada de esta idea que está actualizada para django 1.4? Por un lado, el error se ha corregido (en los últimos dos años), y para el caso, no estoy seguro de por qué el alcance de SiteAdmin debe tener alguna idea de lo que significa user_profiles. Y de hecho, actualmente estoy recibiendo el error Tipo de excepción: \t ImproperlyConfigured Excepción Valor: \t 'HospitalAdmin.fields' se refiere al campo '' USER_PROFILES que falta de la forma. Por supuesto, los nombres de modelo son diferentes, pero la estructura es la misma. Hospital = Sitio. –

Cuestiones relacionadas