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)
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.
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.
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.
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
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.
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.
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.