我正在尝试增强django管理界面,类似于在this SO post的公认答案中所做的事情。我在User表和Project表之间有多对多关系。在django管理员中,我希望能够将用户分配到一个项目,如下图所示:
python - Django管理界面: using horizontal_filter with ManyToMany field with intermediate table-LMLPHP

使用简单的ManyToManyField可以很好地工作,但是问题是我的模型使用throughManyToManyField参数来使用中间表。我无法使用save_m2m()set()函数,并且对如何改编以下代码以使其正常工作一无所知。

该模型:

class UserProfile(models.Model):
    user = models.OneToOneField(User, unique=True)
    projects = models.ManyToManyField(Project, through='Membership')

class Project(models.Model):
    name = models.CharField(max_length=100, unique=True)
    application_identifier = models.CharField(max_length=100)
    type = models.IntegerField(choices=ProjectType)
    ...

class Membership(models.Model):
    project = models.ForeignKey(Project,on_delete=models.CASCADE)
    user = models.ForeignKey(UserProfile,on_delete=models.CASCADE)

    # extra fields
    rating = models.IntegerField(choices=ProjectType)
    ...
admin.py中用于小部件的代码:
from django.contrib.admin.widgets import FilteredSelectMultiple

class ProjectAdminForm(forms.ModelForm):
    class Meta:
        model = Project
        fields = "__all__" # not in original SO post

    userprofiles = forms.ModelMultipleChoiceField(
        queryset=UserProfile.objects.all(),
        required=False,
        widget=FilteredSelectMultiple(
            verbose_name='User Profiles',
            is_stacked=False
        )
    )

    def __init__(self, *args, **kwargs):
        super(ProjectAdminForm, self).__init__(*args, **kwargs)
            if self.instance.pk:
                self.fields['userprofiles'].initial = self.instance.userprofile_set.all()

    def save(self, commit=True):
        project = super(ProjectAdminForm, self).save(commit=False)
        if commit:
            project.save()

        if project.pk:
            project.userprofile_set = self.cleaned_data['userprofiles']
            self.save_m2m()

        return project

class ProjectAdmin(admin.ModelAdmin):
    form = ProjectAdminForm
    ...

注意:中间模型中的所有其他字段都不需要在Project Admin View 中进行更改(它们是自动计算的),它们都具有默认值。

谢谢你的帮助!

最佳答案

我可以找到解决此问题的方法。这个想法是:

  • 当且仅当它们是新的时才在Membership表中创建新条目(否则,它将擦除Membership表中其他字段的现有数据)
  • 删除从成员资格表
  • 中取消选择的条目

    为此,我替换了:
    if project.pk:
        project.userprofile_set = self.cleaned_data['userprofiles']
        self.save_m2m()
    

    经过:
    if project.pk:
        # Get the existing relationships
        current_project_selections = Membership.objects.filter(project=project)
        current_selections = [o.userprofile for o in current_project_selections]
    
        # Get the submitted relationships
        submitted_selections = self.cleaned_data['userprofiles']
    
        # Create new relation in Membership table if they do not exist
        for userprofile in submitted_selections :
            if userprofile not in current_selections:
                Membership(project=project,userprofile=userprofile).save()
    
        # Remove the relations that were deselected from the Membership table
        for project_userprofile in current_project_selections:
            if project_userprofile.userprofile not in submitted_selections :
                project_userprofile.delete()
    

    关于python - Django管理界面: using horizontal_filter with ManyToMany field with intermediate table,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44714416/

    10-12 18:44