在管理页面中编辑M2M的双向关系

7 投票
1 回答
570 浏览
提问于 2025-04-15 15:48

首先,我想先说明一下我想要实现的目标,以防有其他更好的方法!

我希望能够在M2M(多对多)关系的两边都进行编辑(最好是在管理页面上,不过如果需要的话,也可以在普通页面上进行)。我想使用任何多选的界面来实现这个功能。

问题显然出现在反向关系上,因为主要的一方(定义关系的地方)自动工作得很好。

我尝试过这里的一些建议,想让一个内联的界面出现,这个方法是有效的,但界面并不是很好。

我在django的邮件列表上得到的建议是使用自定义的ModelForm。我已经做到让一个多选框出现,但它似乎没有“连接”到任何东西,因为它一开始没有选中任何内容,也不会保存所做的更改。

以下是相关的代码片段:

#models.py
class Tag(models.Model):
    name = models.CharField(max_length=200)

class Project(models.Model):
    name = models.CharField(max_length=200)
    description = models.TextField()
    tags = models.ManyToManyField(Tag, related_name='projects')

#admin.py
class TagForm(ModelForm):
    fields = ('name', 'projects')
    projects = ModelMultipleChoiceField(Project.objects.all(), widget=SelectMultiple())
    class Meta:
        model = Tag

class TagAdmin(admin.ModelAdmin):
    fields = ('name', 'projects')
    form = TagForm

任何帮助都将非常感激,无论是让上面的代码工作,还是提供一个更好的方法!

DavidM

1 个回答

2

之所以没有任何事情自动发生,是因为“项目”这个字段并不属于标签模型。这意味着你需要自己完成所有的工作。你可以在标签表单中做类似这样的事情:

def __init__(self, *args, **kwargs):
    super(TagForm, self).__init__(*args, **kwargs)
    if 'instance' in kwargs:
        self.fields['projects'].initial = self.instance.project_set.all()

def save(self, *args, **kwargs):
    super(TagForm, self).save(*args, **kwargs)
    self.instance.project_set.clear()
    for project in self.cleaned_data['projects']:
        self.instance.project_set.add(project)

请注意,这段代码没有经过测试,所以你可能需要稍微调整一下才能让它正常工作。

撰写回答