Django:如何为不同的用户提供同一个ManyToManyField的不同选项子集 问题是:

Django:如何为不同的用户提供同一个ManyToManyField的不同选项子集 问题是:,django,django-admin,Django,Django Admin,如何在管理中为不同用户提供同一ManyToManyField的不同选项子集,并让每个用户的选择仅影响其选项 情景: 我正在构建一个交互式地图web应用程序。可以有很多地图。可以有许多MapItem。 地图项目可以位于多个地图上,并且地图可以有多个地图项目。因此,有很多关系 每个地图都有一个所有者,我只希望地图的所有者能够从其地图中添加或删除地图项 以下是我的模型的相关部分: class Map(models.Model): # Omit owner = models.Foreig

如何在管理中为不同用户提供同一ManyToManyField的不同选项子集,并让每个用户的选择仅影响其选项

情景: 我正在构建一个交互式地图web应用程序。可以有很多地图。可以有许多MapItem。 地图项目可以位于多个地图上,并且地图可以有多个地图项目。因此,有很多关系

每个地图都有一个所有者,我只希望地图的所有者能够从其地图中添加或删除地图项

以下是我的模型的相关部分:

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 multiple="multiple" id="id_map" name="map">
  <option value="1">Bob's Map</option>
  <option value="2">Sally's Map</option>
</select>
到目前为止还不错。这使我可以选择只包含所需选项的选项:

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

鲍勃的地图
当鲍勃储蓄时,问题就来了。当Bob保存时,它会清除Sally地图的所有保存值。因此,如果选择了Sally的地图,当Bob保存时(即使Bob看不到),Sally的地图将被取消选择


有没有更好的办法解决这个问题?是否有办法确保保存时保持不变的值(如选择了Sally的映射)?

尝试覆盖ModelAdmin的
save\u model
方法


在其中,您需要删除属于当前用户的所有关系(而不是删除作为当前行为的所有关系),并保存所有提交的关系(您知道它属于当前用户,因为您过滤了选项,但您可能应该在上一步中重新验证它,因为HTTP请求可能会被篡改)。

@lufte的答案很接近,但不是我所需要的。但它确实让我找到了正确的答案。以下是我的解决方案:

save\u model
非常适合调整非多个字段的值。但是,多个字段 在这种方法中不会受到影响,因为无论进行了什么更改

另一方面,
save_related
正是我所需要的。我能够确定我的用户应该能够在
get_form
中影响哪些地图,并将任何其他地图传递到
save_related
中保存

以下是一些代码供参考:

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)
def get_表单(self、request、obj=None、**kwargs):
form=super(MapItemAdmin,self).获取表单(请求,对象,**kwargs)
#筛选已选择的地图
#并创建当前用户无法触摸的地图列表
self.existing_maps=[obj.map.all()中m的m.id]\
如果不是,则m.owner==request.user,而不是\
m、 groups.filter(id\uu in=request.user.groups.all())]
#筛选将显示在“管理”对话框中的选项
form.base_字段['map']。queryset=\
form.base_字段['map'].queryset.filter(Q(owner=request.user)\
|Q(groups\uu in=request.user.groups.all())
报税表
def保存相关(自我、请求、表单、表单集、更改):
super(MapItemAdmin,self)。与保存相关(请求、表单、表单集、更改)
#重新添加当前用户无法触摸的所有以前选择的地图
对于自存_映射中的em:
form.instance.map.add(em)

如果试图保存无效值,则需要验证输入数据并给出错误。
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)