2009-08-04 87 views
33

我有一個與另一個對象具有多對多關係的對象。
在Django Admin中,這會在多選框中產生很長的列表。在Django中過濾ManyToMany框管理

我想過濾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) 

回答

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功能非常強大,我有點驚訝它沒有在文檔/書中覆蓋更多。

0
Category.objects.filter(available_in=cityobject) 

應該這樣做。該視圖應具有用戶選擇的城市,無論是在請求中還是作爲該視圖功能的參數。

+0

但即時通訊談論django管理員,你是說我應該複製標準視圖並添加上面? – schmilblick 2009-08-04 11:24:40

+0

啊,我完全錯過了你的問題標題中的整個「Django Admin」部分。我仍然認爲這是正確的方法,但我不確定你會把它放在哪裏,或者甚至可能。 – AlbertoPL 2009-08-04 11:41:56

1

由於您選擇的是同一表單中的客戶所在的城市和類別,因此您需要一些JavaScript動態縮小類別選擇器,以便僅選擇所選城市中的可用類別。

+0

我不覺得熱衷於在JavaScript上迭代數以萬計的DOM元素,並與另一個巨大的列表進行比較。我會說Javascript絕對不是要走的路,當從數據庫中選擇類別時,必須完成這一步。 – schmilblick 2009-08-04 11:52:15

12

據我所知,你基本上是想根據一些標準(根據城市的類別)來篩選顯示的選擇。

您可以使用limit_choices_to屬性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,可用於這個目的。

但有一點需要注意,limit_choices_to在帶有自定義中間表的ManyToManyField上使用時不起作用。希望這可以幫助。

+0

這看起來像可以工作!然而......它讓我意識到我必須重新建模我的模型:) 在閱讀文檔時,管理員並不關心limit_choices_to,那麼你會怎麼做呢? – schmilblick 2009-08-05 06:39:18

+0

我試圖按照描述@sim的方式來做同樣的事情,但我在/ admin/foo/bar /中得到一個'ValueError'的錯誤:int()的基數爲10:'city'`。有什麼我缺少如何實現這種過濾方法嗎? – nhinkle 2013-10-13 06:44:27

0

就像Ryan說的那樣,必須有一些javascript來根據用戶選擇的內容動態改變選項。如果保存了城市並重新加載了管理員表單,那麼當過濾器工作時,發佈的解決方案就可以工作,但考慮用戶想要編輯對象然後更改城市下拉菜單但類別中的選項不會刷新的情況。

4

另一種方法是用formfield_for_manytomany在Django Admin中。

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瞭解更多信息。