Django-filter: Filtrado por atributo del modelo de clave externa

Creado en 9 ene. 2019  ·  4Comentarios  ·  Fuente: carltongibson/django-filter

¡Hola!

Estaba trabajando en un problema en el trabajo y me preguntaba cuál es la forma más idiomática de abordarlo. Tenemos varios campos de filtro ModelMultipleChoiceFilter para claves externas de un modelo. Estoy tratando de averiguar cómo filtrar por un atributo único en las claves externas mientras uso un widget CheckboxSelectMultiple , sin exponer las claves primarias en las URL.

Aquí hay un ejemplo que (más o menos) muestra cómo lo tengo configurado en este momento.

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

class Foo(models.Model):
    prop = models.CharField(max_length=55, unique=True)

    def __str__(self):
        return self.name


class Bar(models.Model):
    foo = models.ForeignKey(Foo, related_name="bars")
# app/filters.py
import django_filters
from app.models import Bar, Foo

class BarFilter(django_filters.FilterSet):
    foo = django_filters.ModelMultipleChoiceFilter(
        queryset=Foo.objects.all(),
        widget=CheckboxSelectMultiple(),
        label="Foo",
        label_suffix="",
    )

    class Meta:
        model = bar
        fields = ['foo']

Esto funciona totalmente bien en la vista. Los filtros funcionan y filtran correctamente con los widgets adecuados. Sin embargo, la URL tiene la clave principal, por lo que en este ejemplo /?foo=1 , mientras que quiero que se lea /?foo=<prop value> , para evitar exponer mi pk y hacer que las URL sean más legibles.

Intenté modificar campos como este, porque en otras partes de Django tiende a funcionar:

# app/filters.py
...snip...
    class Meta:
        model = bar
        fields = ['foo__prop']

Esto hace que la URL responda a /?foo=<prop value> como se desee, pero ahora no usa CheckboxSelectMultiple para el formulario. Intenté convertir el atributo en foo__prop también, pero la representación del formulario seguía siendo incorrecta.

Tengo la sensación de que lo que estoy tratando de hacer es compatible teniendo en cuenta que casi funciona, pero parece que no puedo averiguar cómo conseguirlo. Si esto está fuera del alcance admitido actual, puedo escribir mi propio formulario para manejar esto. ¡Muchas gracias por la ayuda y por el fantástico proyecto!

Comentario más útil

Hola, gracias por tomarse el tiempo para responder.

¡Me has puesto en el camino correcto! Tuve la oportunidad de implementar esto ayer, ¡y usar el argumento field_name funcionó!

Para cualquiera en el futuro que pueda leer este número, así es aproximadamente como salió el código:

# app/filters.py
...snip
class BarFilter(django_filters.FilterSet):
    foo = django_filters.ModelMultipleChoiceFilter(
        queryset=Foo.objects.all(),
        field_name="foo__prop", # This lets us keep the url as "/?foo=<value>
        to_field_name="prop",
        widget=CheckboxSelectMultiple(),
        label="Foo",
        label_suffix="",
    )

    class Meta:
        model = bar
        fields = ['foo']

Puede encontrar una referencia a esto en la documentación que @carltongibson mencionó. Específicamente, consulte la sección sobre filtros ModelMultipleChoice.

De todos modos, ¡muchas gracias por tomarse el tiempo para ayudarme!

Todos 4 comentarios

Hola. Buen tema. Estrictamente una pregunta de uso, pero tan bien expresada, es un placer leerla.

¿Miraste el argumento field_name para los filtros?
https://django-filter.readthedocs.io/en/master/ref/filters.html

Esto le permitiría usar foo_prop como objetivo para su filtro foo.

Me imagino que eso simplemente funcionaría ... tal vez debas establecer opciones en el widget o algo así (pero eso debería manejarse ...)

Hola, gracias por tomarse el tiempo para responder.

¡Me has puesto en el camino correcto! Tuve la oportunidad de implementar esto ayer, ¡y usar el argumento field_name funcionó!

Para cualquiera en el futuro que pueda leer este número, así es aproximadamente como salió el código:

# app/filters.py
...snip
class BarFilter(django_filters.FilterSet):
    foo = django_filters.ModelMultipleChoiceFilter(
        queryset=Foo.objects.all(),
        field_name="foo__prop", # This lets us keep the url as "/?foo=<value>
        to_field_name="prop",
        widget=CheckboxSelectMultiple(),
        label="Foo",
        label_suffix="",
    )

    class Meta:
        model = bar
        fields = ['foo']

Puede encontrar una referencia a esto en la documentación que @carltongibson mencionó. Específicamente, consulte la sección sobre filtros ModelMultipleChoice.

De todos modos, ¡muchas gracias por tomarse el tiempo para ayudarme!

Súper. Me alegro de que lo hayas resuelto. ¡Bien hecho!

Gran trabajo ! Gracias !

¿Fue útil esta página
0 / 5 - 0 calificaciones