2

在Django-Admin中,您可以在模型的字段上定义list_filter。这也适用于ManyToMany-Fields。Django Admin change_list过滤多个ManyToMany

class ModelA(models.Model): 
    name = models.CharField(max_length=100, verbose_name="Name") 

class ModelB(models.Model): 
    model_a_relation = models.ManyToManyField(ModelA) 

class ModelBAdmin(ModelAdmin): 
    list_filter = [model_a_relation, ] 

admin.site.register(ModelB, ModelBAdmin) 

现在,我可以通过ModelB的Admin object_list中的ModelA过滤ModelB的元素列表。

现在我的问题:是否可以过滤ModelA的多个对象?

在ModelB的change_view中,我使用django-autocomplete-light来定义关系。我可以使用这个小部件来筛选change_list吗?

我想象这个过滤器的背景中的查询,如ModelB.objects.filter(model_a_relation__in=names),其中名称是ModelA所选对象的列表。

感谢霍斯特

回答

3

我做了一个非常肮脏的尝试来解决我的问题。它的作品,我想与你分享。

为了更好地理解我在这个例子中的新型号:

class Tag(models.Model): 
    name = models.CharField(max_length=100, verbose_name="Name") 

class Book(models.Model): 
    tags = models.ManyToManyField(Tag) 
    read = models.BooleanField() 

class BookAdmin(ModelAdmin): 
    list_filter = ['read', ] 

admin.site.register(Book, BookAdmin) 

起初,我已改写了BookAdmin的changelist_view

def changelist_view(self, request, extra_context=None): 

    extra_context = extra_context if extra_context else {} 

    q = request.GET.copy() 

    tags = Tag.objects.all().values('id', 'name') 

    current_tags = q.get('tags__id__in', []) 
    tag_query = request.GET.copy() 
    if current_tags: 
     tag_query.pop('tags__id__in') 
     current_tags = current_tags.split(',') 
     all_tag = False 
    else: 
     all_tag = True 
    for tag in tags: 
     if str(tag['id']) in current_tags: 
      tag['selected'] = True 
      temp_list = list(current_tags) 
      temp_list.remove(str(tag['id'])) 
      tag['tag_ids'] = ','.join(temp_list) 
     else: 
      tag['selected'] = False 
      tag['tag_ids'] = ','.join(current_tags) 

    extra_context['tag_query'] = '?' if len(tag_query.urlencode()) == 0 else '?' + tag_query.urlencode() + '&' 
    extra_context['all_tag'] = all_tag 
    extra_context['tags'] = tags 

    return super(BookAdmin, self).changelist_view(request, extra_context=extra_context) 

正如你所看到的,我看看GET,是否有一些标签被选中或没有。然后,我为每个可能的标签构建新的GET参数。

再有就是我的自动覆盖change_list.html

{% extends "admin/change_list.html" %} 

{% block content %} 
    {{ block.super }} 

    <h3 id="custom_tag_h3"> Fancy Tag filter</h3> 
    <ul id="custom_tag_ul"> 

     <li{% if all_tag %} class="selected"{% endif %}> 
      <a href="{{ tag_query }}">All</a> 
     </li> 

     {% for tag in tags %} 
      <li{% if tag.selected %} class="selected"{% endif %}> 
       <a href="{{ tag_query }}tags__id__in={{ tag.tag_ids }}{% if not tag.selected %}{% if tag.tag_ids %},{% endif %}{{ tag.id }}{% endif %}">{{ tag.name }}</a> 
      </li> 
     {% endfor %} 

    </ul> 

    <script type="text/javascript"> 
     $('#changelist-filter').append($('#custom_tag_h3')); 
     $('#custom_tag_h3').after($('#custom_tag_ul')); 
    </script> 

{% endblock content %} 

这样,我有一个过滤器看起来像布尔read -filter在那里我可以激活多个选项。通过点击过滤器,一个新的ID被添加到查询中。另一次点击已经选择的选项将从查询中删除ID。点击全部从URL中删除洞tags_in-参数。

+0

如果django-autocomplete-light在变更列表过滤器中提供了自动完成支持,真的很棒! – jpic

+0

非常感谢您的支持!这正是我从SimpleListFilter接口中遗漏的。 – Moritz

0

另一种选择,让用户在改变列表视图中使用自动完成:

  • 设置ModelAdmin.search_fields由自动完成,即服务的字段进行搜索。

    class ModelBAdmin(ModelAdmin): 
        search_fields = ['model_a_relation__name'] 
    
  • override the changelist tomplatespawn an autocomplete on the search input

    <script type="text/javascript"> 
    $(document).ready(function() { 
        $('#searchbar').yourlabsAutocomplete({ 
         url: '{% url 'autocomplete_light_autocomplete' 'YourAutocompleteName' %}', 
         choiceSelector: '[data-value]', 
        }).input.bind('selectChoice', function(e, choice, autocomplete) { 
         $(this).val(choice.text()) 
           .parents('form').submit(); 
        }); 
    }); 
    </script> 
    
  • 确保没有JS错误添加此脚本后!

+0

非常感谢您的想法,但我不想专注于自动完成,而是关注用于过滤的多重选择的可能性。此外,我已经为ModelB的其他属性提供了自动完成功能的搜索栏,并且不希望它们与这些新内容混合在一起。我想在正确的过滤区使用自动完成Widget。 –

相关问题