在Django Admin中过滤ManyToMany框

时间:2009-08-04 10:31:44

标签: django django-admin django-forms many-to-many django-widget

我有一个与另一个对象有多对多关系的对象 在Django Admin中,这会在多个选择框中生成一个很长的列表。

我想过滤ManyToMany关系,所以我只提取客户选择的城市中可用的类别。

这可能吗?我是否必须为它创建一个小部件?如果是这样 - 我如何将行为从标准的ManyToMany字段复制到它,因为我也想要filter_horizo​​ntal函数。

这些是我的简化模型:

class City(models.Model):
    name = models.CharField(max_length=200)


class Category(models.Model):
    name = models.CharField(max_length=200)
    available_in = models.ManyToManyField(City)


class Customer(models.Model):
    name = models.CharField(max_length=200)
    city = models.ForeignKey(City)
    categories = models.ManyToManyField(Category)

7 个答案:

答案 0 :(得分:36)

好的,这是我使用上述类的解决方案。 我添加了一堆更多过滤器来正确过滤它,但我想在这里使代码可读。

这正是我想要的,我在这里找到了我的解决方案:http://www.slideshare.net/lincolnloop/customizing-the-django-admin#stats-bottom(幻灯片50)

将以下内容添加到我的admin.py:

class CustomerForm(forms.ModelForm): 
    def __init__(self, *args, **kwargs):
        super(CustomerForm, self).__init__(*args, **kwargs)
        wtf = Category.objects.filter(pk=self.instance.cat_id);
        w = self.fields['categories'].widget
        choices = []
        for choice in wtf:
            choices.append((choice.id, choice.name))
        w.choices = choices


class CustomerAdmin(admin.ModelAdmin):
    list_per_page = 100
    ordering = ['submit_date',] # didnt have this one in the example, sorry
    search_fields = ['name', 'city',]
    filter_horizontal = ('categories',)
    form = CustomerForm

这会过滤“类别”列表而不删除任何功能! (即:我仍然可以拥有我心爱的filter_horizo​​ntal:))

ModelForms非常强大,我有点惊讶它没有在文档/书中更多地介绍。

答案 1 :(得分:15)

据我所知,您基本上是想根据某些标准(根据城市的类别)过滤所显示的选项。

您可以使用limit_choices_to的{​​{1}}属性来完成此操作。所以将模型定义更改为......

models.ManyToManyField

这应该有效,因为class Customer(models.Model): name = models.CharField(max_length=200) city = models.ForeignKey(City) categories = models.ManyToManyField(Category, limit_choices_to = {'available_in': cityId}) 可用于此目的。

但有一点需要注意,limit_choices_to在具有自定义中间表的ManyToManyField上使用时无效。希望这会有所帮助。

答案 2 :(得分:5)

另一种方法是使用Django Admin中的formfield_for_manytomany

class MyModelAdmin(admin.ModelAdmin):
    def formfield_for_manytomany(self, db_field, request, **kwargs):
        if db_field.name == "cars":
            kwargs["queryset"] = Car.objects.filter(owner=request.user)
        return super(MyModelAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)

考虑到"汽车"是ManyToMany字段。

查看this link了解详情。

答案 3 :(得分:2)

我认为这就是你要找的东西:

http://blog.philippmetzler.com/?p=52

我们使用django-smart-choices:

http://github.com/digi604/django-smart-selects

菲利普

答案 4 :(得分:1)

由于您以相同的形式选择客户的城市和类别,因此您需要使用一些JavaScript来动态地将类别选择器缩小到所选城市中可用的类别。

答案 5 :(得分:0)

像Ryan所说,必须有一些javascript根据用户选择的内容动态更改选项。如果保存城市并重新加载管理表单,则发布的解决方案有效,即过滤器工作时,但想到用户想要编辑对象然后更改城市下拉但类别中的选项不会刷新的情况。

答案 6 :(得分:-1)

Category.objects.filter(available_in=cityobject)

应该这样做。视图应该具有用户在请求中选择的城市,或者作为该视图函数的参数。