through theme template one many example actions django django-admin django-forms many-to-many django-widget

theme - many to many filter django



Filtre el cuadro ManyToMany en Django Admin (7)

Tengo un objeto con una relación de muchos a muchos con otro objeto.
En el administrador de Django esto da como resultado una lista muy larga en un cuadro de selección múltiple.

Me gustaría filtrar la relación ManyToMany, de modo que solo obtengo Categorías disponibles en la Ciudad que el Cliente haya seleccionado.

es posible? ¿Tendré que crear un widget para eso? Y si es así, ¿cómo copio el comportamiento del campo estándar ManyToMany, ya que también me gustaría la función filter_horizontal?

Estos son mis modelos simplificados:

class City(models.Model): name = models.CharField(max_length=200) class Category(models.Model): name = models.CharField(max_length=200) available_in = models.ManyToManyField(City) class Customer(models.Model): name = models.CharField(max_length=200) city = models.ForeignKey(City) categories = models.ManyToManyField(Category)


Ya que está seleccionando la ciudad y las categorías del cliente de la misma forma, necesitará algunos javascript para reducir dinámicamente el selector de categorías a solo las categorías disponibles en la ciudad seleccionada.


Category.objects.filter(available_in=cityobject)

Deberias hacer eso. La vista debe tener la ciudad que el usuario seleccionó, ya sea en la solicitud o como un parámetro para esa función de vista.


Ok, esta es mi solución usando las clases anteriores. Agregué varios filtros más para filtrarlo correctamente, pero quería que el código fuera legible aquí.

Esto es exactamente lo que estaba buscando, y encontré mi solución aquí: http://www.slideshare.net/lincolnloop/customizing-the-django-admin#stats-bottom (diapositiva 50)

Agregue lo siguiente a mi admin.py:

class CustomerForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(CustomerForm, self).__init__(*args, **kwargs) wtf = Category.objects.filter(pk=self.instance.cat_id); w = self.fields[''categories''].widget choices = [] for choice in wtf: choices.append((choice.id, choice.name)) w.choices = choices class CustomerAdmin(admin.ModelAdmin): list_per_page = 100 ordering = [''submit_date'',] # didnt have this one in the example, sorry search_fields = [''name'', ''city'',] filter_horizontal = (''categories'',) form = CustomerForm

¡Esto filtra la lista de "categorías" sin eliminar ninguna funcionalidad! (es decir: todavía puedo tener mi amado filter_horizontal :))

El ModelForms es muy poderoso, estoy un poco sorprendido de que no esté cubierto más en la documentación / libro.


Como dice Ryan, tiene que haber algún javascript para cambiar dinámicamente las opciones según lo que el usuario seleccione. La solución publicada funciona si la ciudad se guarda y se vuelve a cargar el formulario de administrador, eso es cuando el filtro funciona, pero piensa en una situación donde un usuario quiere editar un objeto y luego cambia la ciudad desplegable pero las opciones en categoría no se actualizan.



Por lo que puedo entender, es que básicamente desea filtrar las opciones mostradas según algunos criterios (categoría según la ciudad).

Puedes hacer exactamente eso usando limit_choices_to attribute of models.ManyToManyField . Entonces, cambie la definición de su modelo como ...

class Customer(models.Model): name = models.CharField(max_length=200) city = models.ForeignKey(City) categories = models.ManyToManyField(Category, limit_choices_to = {''available_in'': cityId})

Esto debería funcionar, como limit_choices_to , está disponible para este propósito.

Pero hay que tener en cuenta que limit_choices_to no tiene ningún efecto cuando se usa en ManyToManyField con una tabla intermedia personalizada. Espero que esto ayude.


Otra forma es con formfield_for_manytomany en Django Admin.

class MyModelAdmin(admin.ModelAdmin): def formfield_for_manytomany(self, db_field, request, **kwargs): if db_field.name == "cars": kwargs["queryset"] = Car.objects.filter(owner=request.user) return super(MyModelAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)

Teniendo en cuenta que los "autos" son el campo ManyToMany.

Mira este enlace para más información.