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

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

问题描述

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

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?

示例请看附图.

这是用户个人资料的型号代码:

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

以及项目的型号代码:

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)

推荐答案

问题不在于内联;一般来说,它来自 ModelForm 的工作方式.他们只为模型上的实际字段构建表单字段,而不是相关的经理属性.但是,您可以将此功能添加到表单中:

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

可能需要进行一些演练.首先,我们定义一个 userprofiles 表单域.它将使用 ModelMultipleChoiceField,默认情况下会产生一个多选框.由于这不是模型上的实际字段,我们不能只将它添加到 filter_horizo​​ntal,所以我们改为告诉它简单地使用相同的小部件 FilteredSelectMultiple,如果它被列在 filter_horizo​​ntal 中,它将使用它.

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.

我们最初将查询集设置为整个 UserProfile 集,你不能在这里过滤它,但是,因为在类定义的这个阶段,表单还没有被实例化,因此没有'还没有设置它的 instance.因此,我们重写了 __init__ 以便我们可以将过滤后的查询集设置为字段的初始值.

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.

最后,我们重写 save 方法,这样我们就可以将相关管理器的内容设置为与表单的 POST 数据中的内容相同,您就完成了.

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 管理界面:使用带有内联 ManyToMany 字段的 Horizo​​ntal_filter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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