Pregunta

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, así que solo busco las Categorías que están disponibles en la Ciudad que el Cliente ha seleccionado.

¿Es esto posible? ¿Tendré que crear un widget para ello? Y si es así, ¿cómo copio el comportamiento del campo estándar ManyToMany en él, 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)
¿Fue útil?

Solución

Ok, esta es mi solución usando las clases anteriores. Agregué muchos más filtros 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 las " categorías " ¡Lista 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.

Otros consejos

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

Puede hacer exactamente eso utilizando el atributo limit_choices_to de models.ManyToManyField . Entonces, cambiando 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, ya que limit_choices_to , está disponible para este mismo propósito.

Pero una cosa a tener en cuenta, 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 " automóviles " son el campo ManyToMany.

Marque este enlace para más información.

Creo que esto es lo que estás buscando:

http://blog.philippmetzler.com/?p=52

usamos django-smart-selects:

http://github.com/digi604/django-smart-selects

Philipp

Como 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 las categorías disponibles en la ciudad seleccionada.

Como dice Ryan, debe haber algún javascript para cambiar dinámicamente las opciones en función de lo que el usuario seleccione. La solución publicada funciona si la ciudad se guarda y el formulario de administración se vuelve a cargar, eso es cuando funciona el filtro, pero piense en una situación en la que un usuario quiera editar un objeto y luego cambie el menú desplegable de la ciudad, pero las opciones en la categoría no se actualizarán.

Category.objects.filter(available_in=cityobject)

Eso debería hacerlo. 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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top