user4910881
user4910881

Reputation:

Django Admin filter_horizontal not working

I'm trying to get filter horizontal to include the search and selected box division instead of the single column where you choose with ctrl multiple options.

I've included the filter horizontal in the admin.py but it doesn't work. I'm using the common class which imports from the admin.ModelAdmin could there be an issue because of this?

class ArticleAdmin(CommonAdmin):
    form = autocomplete_light.modelform_factory(Article)
    list_display = [
        'name',
        'categories_display',
        'modified_by',
        'created_by',
        'modified',
        'created',
        'visible',
    ]
    list_editable = ['visible']
    filter_horizontal = ('categories','tags')
    #list_filter = ('categories',)
    excludes = ['sortorder',]
    inlines = [
        HotItemInline,
        ArticleImageInline,
        ArticleYoutubeVideoInline,
        #RelatedArticleInline
    ]

    def formfield_for_manytomany(self, db_field, request, **kwargs):
        if db_field.name == "categories":
            try:
                category_root = Category.objects.get(slug='lifestyle')
                kwargs["queryset"] = Category.objects.filter(tree_id=category_root.tree_id).exclude(id=category_root.id)
            except Category.DoesNotExist:
                pass
        return super(CommonAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

the common admin

class CommonAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.ImageField: {'widget': PreviewImageWidget},
    }
    list_display = ['name', 'modified_by', 'created_by', 'modified', 'created', 'visible', 'get_absolute_url']
    search_fields = ['name', ]
    list_filter = ['modified', 'created', 'visible']
    ordering = ['-modified',]
    actions=[make_invisible, make_visible,]
    list_select_related = True

    class Media:
        js = (
            "/static/kb/js/admin/timeoptions.js",
        )

    def changelist_view(self, request, extra_context=None):
        if not request.GET.has_key('visible__exact'):
            q = request.GET.copy()
            q['visible__exact'] = 1
            request.GET = q
            request.META['QUERY_STRING'] = request.GET.urlencode()
        return super(CommonAdmin,self).changelist_view(request, extra_context=extra_context)

    def save_model(self, request, obj, form, change):
        if not obj.id:
            obj.created_by = request.user
            obj.created = datetime.datetime.today()
        obj.modified_by = request.user
        obj.modified = datetime.datetime.today()
        if hasattr(obj, 'name') and hasattr(obj, 'header') and hasattr(obj, 'title'):
            if not obj.header:
                obj.header = obj.name
            if not obj.title:
                obj.title = obj.name
        obj.save()

and the model

class Article(BaseItemModel):
    area = TreeForeignKey(Area, blank=True, null=True,)
    categories = TreeManyToManyField(Category)
    tags = models.ManyToManyField(Tag, blank=True)
    author = models.CharField(max_length=255, blank=True,)
    html = RichTextField(blank=True, null=True,)

    def share_content(self):
        html = self.html
        if not html:
            html = self.content
        return html.replace('"', "'").strip()

    @models.permalink
    def get_absolute_url(self):
        return ('article_detail', (), {'slug': self.slug})

Upvotes: 2

Views: 4317

Answers (1)

coder123
coder123

Reputation: 61

This is an older question, but I just had to deal with this same scenario. The answer is to both define filter_horizontal on the ModelAdmin as well as setting the widget directly on the TreeNodeMultipleChoiceField, which handles the indented display of mptt choices.

Here's a solution using the Article model from the question:

from django import forms, admin
from mptt.forms import TreeNodeMultipleChoiceField

class ArticleAdminForm(forms.ModelForm):
    categories = TreeNodeMultipleChoiceField(required=False,
        queryset = Category.objects.all(), 
        level_indicator = u'+--',
        widget = admin.widgets.FilteredSelectMultiple('Categories', False))
    class Meta:
        model = Article
        fields = '__all__'

class ArticleAdmin(admin.ModelAdmin):
    filter_horizontal = ('categories',)
    form = ArticleAdminForm

Upvotes: 5

Related Questions