2017-03-29 64 views
0

問題:

我如何能提供不同的用戶對在管理同ManyToManyField選擇不同的子集,並有每個用戶的選擇隻影響他們的選擇?Django的:我怎樣才能提供不同的用戶選擇不同的子集相同ManyToManyField

方案:

我正在構建交互式地圖網絡應用程序。可以有許多地圖。可以有很多MapItems。 MapItems可以在很多地圖上,地圖可以有很多地圖項目。因此一個ManyToMany關係。

每個地圖都有一個所有者,我只想要一個地圖的所有者能夠從他/她的地圖添加或刪除MapItems。

這裏是我的模型的相關部分:

class Map(models.Model): 
    # Omit 
    owner = models.ForeignKey(User, default=1) 

class MapItem(models.Model): 
    # Omit 
    map = models.ManyToManyField(Map, default=None, blank=True) 

MapItem.map由MapItem管理界面上<select>表示:

<select multiple="multiple" id="id_map" name="map"> 
    <option value="1">Bob's Map</option> 
    <option value="2">Sally's Map</option> 
</select> 

我想鮑勃只可以選擇選擇/取消選擇Bob的地圖,甚至不會看到Sally的地圖作爲選項。

我已經能夠通過重寫ModelAdmin上的get_form()來過濾admin <select>窗口小部件中顯示的選項。

def get_form(self, request, obj=None, **kwargs): 
    kwargs['form'] = MapItemAdminForm 
    form = super(MapItemAdmin, self).get_form(request, obj, **kwargs) 
    form.base_fields['map'].queryset = form.base_fields['map'].queryset.filter(Q(owner=request.user) | Q(groups__in=request.user.groups.all())) 
    return form 

到目前爲止好。這給了我一個選擇只有所需的選項:

<select multiple="multiple" id="id_map" name="map"> 
    <option value="1">Bob's Map</option> 
</select> 

問題出現在鮑勃保存時。當Bob保存時,它會清除Sally地圖的任何保存值。所以如果Sally的地圖被選中,當鮑勃保存時(儘管鮑勃看不見),莎莉的地圖被取消選擇。

有沒有更好的方法來解決這個問題?有沒有辦法確保保存不變的值(如選擇Sally的地圖)?

+0

您需要驗證輸入數據,如果試圖挽救無效值給出一個錯誤。 –

回答

0

@ lufte的回答很接近,但不是我所需要的。它確實讓我在正確的氣味。這是我的解決方案:

save_model非常適合調整非ManyToMany字段的值。但是,ManyToMany字段 無法在此方法中受到影響,因爲無論發生什麼更改will be cleared prior to being saved

save_related,另一方面,正是我所需要的。我能夠確定我的用戶應該能夠在get_form中影響哪些地圖,並通過其他方式將其保存在save_related中。DOCS.

下面是一些代碼以供參考:

def get_form(self, request, obj=None, **kwargs): 
     form = super(MapItemAdmin, self).get_form(request, obj, **kwargs) 

     # Filter already selected maps 
     # and create a list of map current user can't touch 
     self.existing_maps = [m.id for m in obj.map.all() \ 
     if not m.owner == request.user and not \ 
     m.groups.filter(id__in=request.user.groups.all())] 

     # Filter the options that will be displayed in the admin <select> 
     form.base_fields['map'].queryset = \ 
     form.base_fields['map'].queryset.filter(Q(owner=request.user) \ 
     | Q(groups__in=request.user.groups.all())) 
     return form 

    def save_related(self, request, form, formsets, change): 
     super(MapItemAdmin, self).save_related(request, form, formsets, change) 

     # Re-add any previously selected maps that the current user can't touch 
     for em in self.existing_maps: 
      form.instance.map.add(em) 
0

嘗試覆蓋ModelAdmin的save_model方法。

其中,您將需要刪除屬於當前用戶的所有關係(而不是刪除所有關係,這是當前行爲)並保存所有提交的關係(您知道屬於當前用戶,因爲您已經過濾選項,但是你應該重新驗證一下,因爲HTTP請求可能會被篡改)。

相關問題