2

I have extended the group model, where I added some manytomany fields, and in the admin page, it likes this:

enter image description here

However, what I expected is this:

enter image description here

Here is how I implemented the m2m field:

class MyGroup(ProfileGroup):
    mobile = models.CharField(max_length = 15)
    email = models.CharField(max_length = 15)
    c_annotates = models.ManyToManyField(Annotation, verbose_name=_('annotation'), blank=True, null=True)
    c_locations = models.ManyToManyField(Location, verbose_name=_('locations'), blank=True, null=True)

And in the database there is a relational form which contains the pairs of group_id and location_id.

Is there anyone who knows how to do it? Thanks!

EDIT:

enter image description here

I implemented as above, the multiple select box actually shows up, but it cannot save... (Sorry, I was working on a virtual machine and it's offline now, so I have to clip the code from screen)

Robert
  • 2,189
  • 6
  • 31
  • 38

3 Answers3

4

latest 2017

govt_job_post is model having qualification as ManyToMany field.

class gjobs(admin.ModelAdmin):
    filter_horizontal = ('qualification',)

admin.site.register(govt_job_post, gjobs)

Max
  • 1,528
  • 21
  • 33
2

Problem solved. It can save the multiple choice field now.

class GroupAdminForm(forms.ModelForm):
    users = forms.ModelMultipleChoiceField(queryset=User.objects.all(),
                                       widget=FilteredSelectMultiple('Users', False),
                                       required=False)
    locations = forms.ModelMultipleChoiceField(queryset=Location.objects.all(),
                                       widget=FilteredSelectMultiple('Location', False),
                                       required=False)
    class Meta:
        model = Group

    def __init__(self, *args, **kwargs):
        instance = kwargs.get('instance', None)
            if instance is not None:
            initial = kwargs.get('initial', {})
            initial['users'] = instance.user_set.all()
            initial['locations'] = instance.c_locations.all()
            kwargs['initial'] = initial
        super(GroupAdminForm, self).__init__(*args, **kwargs)

    def save(self, commit=True):
        group = super(GroupAdminForm, self).save(commit=commit)

        if commit:
            group.user_set = self.cleaned_data['users']
            group.locations = self.cleaned_data['locations']
        else:
            old_save_m2m = self.save_m2m
            def new_save_m2m():
                old_save_m2m()
                group.user_set = self.cleaned_data['users']
                group.location_set = self.cleaned_data['locations']
            self.save_m2m = new_save_m2m
        return group
Robert
  • 2,189
  • 6
  • 31
  • 38
  • This looks like serious overkill if you're using this form in the admin. Just use the `filter_horizontal` built in behavior. – Peter DeGlopper Nov 11 '13 at 05:26
  • It's designed to give you a nice interface for standard `ManyToMany` fields. Where it gets tricky is trying to use it outside the admin, since it depends on some custom Javascript and CSS. – Peter DeGlopper Nov 11 '13 at 05:42
  • Work perfectly : `from django.contrib.admin.widgets import FilteredSelectMultiple` – CallMarl Dec 02 '20 at 19:10
1

Either I am overlooking something that makes your situation unusual or you are making it harder than it needs to be. Since you're using the admin, the vast majority of the code necessary to use the admin's more convenient multiselects is already available. All you should need to do is declare your ManyToMany fields, as you have, and then include those fields in your admin class's filter_horizontal attribute. Or filter_vertical if you want the boxes stacked, but your screenshot shows the horizontal case.

This by itself does not require a custom form for your admin.

Peter DeGlopper
  • 36,326
  • 7
  • 90
  • 83
  • I tried to add the filter_horizontal in MyGroupAdmin(GroupAdmin), but the multiple choices cannot save again... – Robert Nov 11 '13 at 05:54
  • I think since I am extending the GroupAdmin in contrib.auth, but not the admin page for custom models, it would be more complex. – Robert Nov 11 '13 at 05:57