Filtre ManyToMany box à Django Admin

j'ai un objet avec une relation de plusieurs à plusieurs avec un autre objet.

Dans L'Admin Django cela donne une liste très longue dans une boîte de sélection multiple.

j'aimerais filtrer la relation ManyToMany donc je ne récupère que les catégories qui sont disponibles dans la ville que le client a sélectionnée.

Est-ce possible? Est-ce que je vais devoir créer un widget pour ça? Et si oui - comment puis-je copier le comportement du champ standard ManyToMany à elle, puisque je voudrais le filter_horizontal fonction.

Voici mes modèles simplifiés:

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)
33
demandé sur schmilblick 2009-08-04 14:31:43

7 réponses

Ok, c'est ma solution en utilisant les classes ci-dessus. J'ai ajouté un tas d'autres filtres pour filtrer correctement, mais je voulais rendre le code lisible ici.

C'est exactement ce que je cherchais, et j'ai trouvé ma solution ici: http://www.slideshare.net/lincolnloop/customizing-the-django-admin#stats-bottom (diapo 50)

Ajouter ce qui suit à mon 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

ceci filtre la liste des" catégories " sans supprimer aucune fonctionnalité! (c'est à dire: je peux encore avoir mon bien-aimé filter_horizontal :))

Le ModelForms est très puissant, je suis un peu surpris qu'il ne soit pas plus couvert dans la documentation/Livre.

36
répondu schmilblick 2009-08-10 07:16:08

autant que je puisse vous comprendre, c'est que vous voulez fondamentalement filtrer les choix affichés en fonction de certains critères (catégorie selon la ville).

vous pouvez faire exactement cela en utilisant limit_choices_to l'attribut models.ManyToManyField. Donc changer la définition de votre modèle as...

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

Cela devrait fonctionner, comme limit_choices_to, est disponible à cet effet.

Mais une chose à noter, limit_choices_to n'a aucun effet lorsqu'il est utilisé sur un ManyToManyField avec une table intermédiaire personnalisée. Espérons que cette aide.

12
répondu simplyharsh 2013-10-15 10:13:12

une Autre façon est d' formfield_for_manytomany dans 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)

considérant que les" voitures " sont le champ ManyToMany.

Case ce lien pour plus d'info.

4
répondu Alberto García Garrigós 2017-08-15 09:34:36

je pense que c'est ce que vous êtes à la recherche de:

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

nous utilisons django-smart-sélectionne:

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

Philipp

2
répondu Googol 2010-12-10 16:38:57

puisque vous sélectionnez la ville du client et les catégories dans la même forme, vous auriez besoin de javascript pour réduire dynamiquement le sélecteur de catégories aux seules catégories disponibles dans la ville sélectionnée.

1
répondu Ryan Fugger 2009-08-04 11:36:34

comme dit Ryan, il doit y avoir du javascript pour changer dynamiquement les options en fonction de ce que l'utilisateur sélectionne. La solution postée fonctionne si la ville est sauvegardée et que le formulaire d'administration est rechargé, c'est quand le filtre fonctionne, mais pensez à une situation où un utilisateur veut éditer un objet et ensuite changer la ville tomber mais les options dans la catégorie ne se rafraîchit pas.

0
répondu Sharan666 2009-12-15 14:59:09
Category.objects.filter(available_in=cityobject)

ça devrait le faire. La vue doit avoir la ville que l'Utilisateur a sélectionnée, soit dans la requête, soit comme paramètre de cette fonction de vue.

-1
répondu AlbertoPL 2009-08-04 11:01:21