我有一个要内联的Django模型字段。该字段是多对多关系。所以有“项目”和“用户档案”。每个用户配置文件可以选择任意数量的项目。
目前,我已经实现了“表格”内联视图。有没有一种方法可以让我有一个“水平过滤器”,这样我就可以很容易地在用户配置文件中添加和删除项目?
请看附件中的图片作为例子。
以下是用户配置文件的模型代码:
class UserProfile(models.Model):
user = models.OneToOneField(User, unique=True)
projects = models.ManyToManyField(Project, blank=True, help_text="Select the projects that this user is currently working on.")
和项目的模型代码:
class Project(models.Model):
name = models.CharField(max_length=100, unique=True)
application_identifier = models.CharField(max_length=100)
type = models.IntegerField(choices=ProjectType)
account = models.ForeignKey(Account)
principle_investigator = models.ForeignKey(User)
active = models.BooleanField()
和视图的管理代码:
class UserProfileInline(admin.TabularInline):
model = UserProfile.projects.through
extra = 0
verbose_name = 'user'
verbose_name_plural = 'users'
class ProjectAdmin(admin.ModelAdmin):
list_display = ('name', 'application_identifier', 'type', 'account', 'active')
search_fields = ('name', 'application_identifier', 'account__name')
list_filter = ('type', 'active')
inlines = [UserProfileInline,]
admin.site.register(Project, ProjectAdmin)
发布于 2012-07-26 04:36:40
问题不是因为有内联,而是ModelForm
的工作方式。它们只为模型上的实际字段构建表单域,而不是相关的管理器属性。但是,您可以将此功能添加到表单中:
from django.contrib.admin.widgets import FilteredSelectMultiple
class ProjectAdminForm(forms.ModelForm):
class Meta:
model = Project
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
...
做一个简单的演练可能是合适的。首先,我们定义一个userprofiles
表单域。它将使用ModelMultipleChoiceField
,这在默认情况下将导致多选框。由于这不是模型上的实际字段,因此我们不能只将其添加到filter_horizontal
中,因此我们告诉它只需使用相同的小部件FilteredSelectMultiple
,如果它在filter_horizontal
中列出,它将使用该小部件。
我们最初将查询集设置为整个UserProfile
集,但您不能在这里过滤它,因为在类定义的这个阶段,表单还没有被实例化,因此还没有它的instance
集。因此,我们覆盖了__init__
,这样我们就可以将过滤后的查询集设置为字段的初始值。
最后,覆盖save
方法,以便可以将相关管理器的内容设置为与表单的POST数据中的内容相同的内容,这样就完成了。
发布于 2014-05-01 06:07:22
在处理与自身的多对多关系时,这是一个次要的附加。一个人可能想把自己排除在选择之外:
if self.instance.pk:
self.fields['field_being_added'].queryset = self.fields['field_being_added'].queryset.exclude(pk=self.instance.pk)
self.fields['field_being_added'].initial = """Corresponding result queryset"""
发布于 2020-09-10 20:25:47
有一个更简单的解决方案,只需添加filter_horizontal
,如here所解释的那样
class YourAdmin(ModelAdmin)
filter_horizontal = ('your_many_to_many_field',)
之前:
之后:
https://stackoverflow.com/questions/11657682
复制相似问题