Django管理界面:使用horizo​​ntal_filter与内联ManyToMany字段 [英] Django admin interface: using horizontal_filter with inline ManyToMany field

查看:127
本文介绍了Django管理界面:使用horizo​​ntal_filter与内联ManyToMany字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个我想要内联的Django模型字段。该领域是一对多关系。所以有项目和用户个人资料。每个用户配置文件都可以选择任意数量的项目。



目前,我已经有了表格式的内联视图。有没有办法拥有一个横向过滤器,以便我可以轻松地从用户个人资料中添加和删除项目?



请参见附件的示例。 img src =https://i.stack.imgur.com/v9bQE.pngalt =在此输入图像描述>



以下是User Profile:

  class UserProfile(models.Model):
user = models.OneToOneField(User,unique = True )
projects = models.ManyToManyField(Project,blank = True,help_text =选择此用户正在处理的项目。)

项目的模型代码:

  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)
a ctive = 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)


解决方案

问题不在于内联;一般来说,这是从 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)
如果提交:
project.save()

如果proje ct.pk:
project.userprofile_set = self.cleaned_data ['userprofiles']
self.save_m2m()

返回项目

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

演练可能是有序的。首先,我们定义一个 userprofiles 表单字段。它将使用一个 ModelMultipleChoiceField ,默认情况下会导致一个多选框。由于这不是模型上的实际字段,所以我们不能将它添加到 filter_horizo​​ntal 中,所以我们可以直接使用相同的小部件, FilteredSelectMultiple ,如果它在 filter_horizo​​ntal 中列出,它将使用。



我们最初将查询集设置为整个 UserProfile 集合,您不能在此处过滤它,但是,因为在类定义的这个阶段,表单尚未实例化,因此没有设置实例。因此,我们覆盖 __ init __ ,以便我们可以将过滤的查询集设置为字段的初始值。



最后,我们覆盖 save 方法,以便我们可以将相关管理器的内容设置为与表单POST数据相同,并完成。


I have a Django model field that I'd like to inline. The field is a many-to-many relationship. So there are "Projects" and "User profiles". Each user profile can select any number of projects.

Currently, I've got the "tabular" inline view working. Is there a way to have a "horizontal filter" so that I can easily add and remove projects from a user profile?

Please see the attached picture for an example.

Here's the model code for the User Profile:

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.")

And the model code for a Project:

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()

And the admin code for the view:

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)

解决方案

The problem isn't from having inlines; it's from the way ModelForms work, in general. They only build form fields for actual fields on the model, not related manager attributes. However, you can add this functionality to the form:

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
    ...

A little walkthrough is probably in order. First, we define a userprofiles form field. It will use a ModelMultipleChoiceField, which by default will result in a multiple select box. Since this isn't an actual field on the model, we can't just add it to filter_horizontal, so we instead tell it to simply use the same widget, FilteredSelectMultiple, that it would use if it were listed in filter_horizontal.

We initially set the queryset as the entire UserProfile set, you can't filter it here, yet, because at this stage of the class definition, the form hasn't been instantiated and thus doesn't have it's instance set yet. As a result, we override __init__ so that we can set the filtered queryset as the field's initial value.

Finally, we override the save method, so that we can set the related manager's contents to the same as what was in the form's POST data, and you're done.

这篇关于Django管理界面:使用horizo​​ntal_filter与内联ManyToMany字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆