Django interface d'administration: utilisation d'un filtre horizontal avec le champ ManyToMany en ligne
J'ai un champ modèle Django que j'aimerais aligner. Le domaine est une relation de plusieurs à plusieurs. Il y a donc des "Projets" et "profil Utilisateur". Chaque profil d'utilisateur peut sélectionner n'importe quel nombre de projets.
actuellement, j'ai la vue" tabulaire " en ligne qui fonctionne. Y a-t-il un moyen d'avoir un "filtre horizontal" pour que je puisse facilement ajouter et supprimer des projets d'un profil d'utilisateur?
voir l'image ci-jointe pour un exemple.
Voici le Code modèle pour le profil de L'utilisateur:
class UserProfile(models.Model):
user = models.OneToOneField(User, unique=True)
projects = models.ManyToManyField(Project, blank=True, help_text="Select the projects that this user is currently working on.")
et le code modèle pour un projet:
class Project(models.Model):
name = models.CharField(max_length=100, unique=True)
application_identifier = models.CharField(max_length=100)
type = models.IntegerField(choices=ProjectType)
account = models.ForeignKey(Account)
principle_investigator = models.ForeignKey(User)
active = models.BooleanField()
Et l'admin code pour l'afficher:
class UserProfileInline(admin.TabularInline):
model = UserProfile.projects.through
extra = 0
verbose_name = 'user'
verbose_name_plural = 'users'
class ProjectAdmin(admin.ModelAdmin):
list_display = ('name', 'application_identifier', 'type', 'account', 'active')
search_fields = ('name', 'application_identifier', 'account__name')
list_filter = ('type', 'active')
inlines = [UserProfileInline,]
admin.site.register(Project, ProjectAdmin)
2 réponses
Le problème n'est pas d'avoir des inlines; c'est à partir de la voie ModelForm
s du travail en général. Ils construisent seulement des champs de forme pour les champs réels sur le modèle, pas des attributs de gestionnaire liés. Cependant, vous pouvez ajouter cette fonctionnalité au formulaire:
from django.contrib.admin.widgets import FilteredSelectMultiple
class ProjectAdminForm(forms.ModelForm):
class Meta:
model = Project
userprofiles = forms.ModelMultipleChoiceField(
queryset=UserProfile.objects.all(),
required=False,
widget=FilteredSelectMultiple(
verbose_name='User Profiles',
is_stacked=False
)
)
def __init__(self, *args, **kwargs):
super(ProjectAdminForm, self).__init__(*args, **kwargs)
if self.instance.pk:
self.fields['userprofiles'].initial = self.instance.userprofile_set.all()
def save(self, commit=True):
project = super(ProjectAdminForm, self).save(commit=False)
if commit:
project.save()
if project.pk:
project.userprofile_set = self.cleaned_data['userprofiles']
self.save_m2m()
return project
class ProjectAdmin(admin.ModelAdmin):
form = ProjectAdminForm
...
une petite révision s'impose probablement. Tout d'abord, nous définissons un userprofiles
champ de formulaire. Il va utiliser un ModelMultipleChoiceField
, qui, par défaut, aboutira à une boîte de sélection multiple. Puisqu'il ne s'agit pas d'un champ réel sur le modèle, nous ne pouvons pas simplement l'ajouter filter_horizontal
, donc on lui dit d'utiliser simplement le même widget,FilteredSelectMultiple
, qu'elle utiliserait si elle était listée dans filter_horizontal
.
nous avons d'abord placé le queryset comme UserProfile
set, vous ne pouvez pas encore le filtrer ici, car à ce stade de la définition de la classe, la forme n'a pas été instanciée et n'a donc pas de instance
encore fixé. En conséquence, nous outrepassons __init__
de sorte que nous puissions définir la valeur initiale du champ queryset filtré.
Enfin, nous remplacer le save
méthode, de sorte que nous pouvons définir le contenu du gestionnaire lié à la même chose que ce qui était dans les données POST du formulaire, et vous avez terminé.
un petit ajout quand il s'agit d'une relation de plusieurs à plusieurs avec lui-même. On pourrait vouloir s'exclure des choix:
if self.instance.pk:
self.fields['field_being_added'].queryset = self.fields['field_being_added'].queryset.exclude(pk=self.instance.pk)
self.fields['field_being_added'].initial = """Corresponding result queryset"""