0

Hi Stackoverflow people,

I would like to change the m2m widget in the admin pages (and later in the actual django site) to a more user friendly double list (like this one).

I understand that django.contrib.admin.widgets.FilteredSelectMultiple could do this for me. However, I have trouble to get it to work. I have added the code below to my admin.py, but the widget is not changing when I view the model in the admin app.

I have tried to adopt the code from here. Every SupplierProfile should connect to one or more countries from the WorldBorder model (based on the GeoDjango example)

Where is the flaw in the code? I can't see why it would not be displayed. Thank you for your help!

from django import forms
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.contrib.gis import admin
from django.utils.translation import ugettext_lazy as _

from apps.profile.models import (UserProfile,
                                  SupplierProfile)
from apps.gis_data.models import WorldBorder


class WorldBorderAdmin(admin.ModelAdmin):
    filter_horizonal = ('name',)

class SupplierProfileAdminForm(forms.ModelForm):
    distribution_location_country = forms.ModelMultipleChoiceField(
        queryset = WorldBorder.objects.all(), 
            required = False,
            widget = FilteredSelectMultiple(
            verbose_name = _('Distribution Country'),
            is_stacked=False
        )
     )

    class Meta:
        model = SupplierProfile

    def __init__(self, *args, **kwargs):
        super(SupplierProfileAdminForm, self).__init__(*args, **kwargs)

        if self.instance:
          self.fields['distribution_location_country'].initial = self.instance.distribution_location_country.all()

    def save(self, commit=True):
        profile = super(SupplierProfileAdminForm, self).save(commit=False)

        profile.distribution_location_country = self.cleaned_data['distribution_location_country']

        if commit:
            profile.save()
            profile.save_m2m()

        return profile

class SupplierProfileAdmin(admin.ModelAdmin):
    form = SupplierProfileAdminForm

admin.site.register(SupplierProfile, admin.OSMGeoAdmin)

Updated code of admin.py

Is it possible to define the double list as stated below? "distribution_location_country" is the m2m field in my SupplierProfile. For some reason, it is still not coming through.

from django import forms
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.contrib.gis import admin

class SupplierProfileAdmin(admin.OSMGeoAdmin):
    filter_horizontal = ('distribution_location_country', )

admin.site.register(SupplierProfile, SupplierProfileAdmin)
Community
  • 1
  • 1
neurix
  • 4,126
  • 6
  • 46
  • 71

1 Answers1

1

Your register line seems to be wrong:

admin.site.register(SupplierProfile, admin.OSMGeoAdmin)

doesn't register your customized SupplierProfileAdmin with your model.

Perhaps you want the base class of SupplierProfileAdmin to be OSMGeoAdmin instead of ModelAdmin:

class SupplierProfileAdmin(admin.OSMGeoAdmin):
    form = SupplierProfileAdminForm

and your register line to be

admin.site.register(SupplierProfile, SupplierProfileAdmin)

Also, I'm not sure about this, but you might just be able to use

filter_horizonal = ('name_of_the_m2m_field_on_the_model', )

on your SupplierProfileModel instead of that custom field on the form?

agf
  • 171,228
  • 44
  • 289
  • 238
  • Hi agf, what is the correct registration? -> admin.site.register(SupplierProfile, admin.SupplierProfileAdmin) or -> admin.site.register(SupplierProfile, SupplierProfileAdmin)? If I go with the first one, I get the following error: "AttributeError Exception Value:v'module' object has no attribute 'SupplierProfileAdmin'", the 2nd solution also throws an error. Thank you for your help! – neurix Apr 01 '12 at 02:16
  • @neurix The first was a typo. What's the error on the second one? It appears correct. Did you try adjusting the base class? See my edit. – agf Apr 01 '12 at 02:17
  • Thank you for your help! with the changes from your post, I get new error "instance needs to have a primary key value before a many-to-many relationship can be used". I have tried the "filter_horizontal" earlier, but it also did not work. Would be the better solution. Do you have a thought on the new error? How can I assign a primary key? – neurix Apr 01 '12 at 02:26
  • Thank you for all your explanations. All models have an id field and I migrated the tables with south (i checked the sql database). Your 2nd idea looks much more clean and straight-forward, but for some reason, it won't show up. I notice that the field name of horizontal_filter has no influence; if I enter an random name, I do not get an error msg. Do you know why that is the case? I have update the simplified code in the original question. – neurix Apr 01 '12 at 03:12
  • @neurix Also, there was another typo in my answer -- I left the `t` out of `horizontal`. Make sure you didn't just copy / paste my error. – agf Apr 01 '12 at 03:26