django在内联的自定义管理表单中添加绿色加号?

时间:2017-08-08 21:20:11

标签: python django django-forms django-admin

我有一个名为Keyword的模型和一个名为Statement的模型,我一直在自定义表单以添加或更改语句。每个Keyword对象与Statement个对象之间存在m2m(多对多)关系,我希望用户能够选择要关联的关键字。 m2m字段的默认小部件在我的情况下并不常用,因为有许多关键字对象,所以我需要更好的东西。我使用了FilteredSelectMultiple小部件来获得我需要的调整。

这是代码。

在admin.py

    class KeywordInline(admin.TabularInline):
        model = Keyword.statement.through
    class StatementAdmin(admin.ModelAdmin):
        list_display = ('statement_id', 'title', 'author', 'released_by', 'issue_date', 'access', 'full_text',)
        list_filter = (StatementListFilter, 'released_by', 'issue_date', 'access',)
        search_fields = ('statement_id', 'title', 'author', 'issue_date',)
        inlines = [ KeywordInline,]

在forms.py

    class StatementForm(forms.Modelform):
         statement_keywords = forms.ModelMultipleChoiceField(
            queryset=Keyword.objects.all(),
            required=False,
            widget=FilteredSelectMultiple(
               verbose_name='Keywords Associated with Statement',
               is_stacked=False
           )
        )
        class Meta:
           model = Statement
        def __init__(self, *args, **kwargs):
           super(StatementForm, self).__init__(*args, **kwargs)
           if self.instance.pk:
              self.fields['statement_keywords'].initial = self.instance.keyword_set.all()

        def save(self, commit=True):
           statement = super(StatementForm, self).save(commit=False)
           if commit:
             statement.save()
           if statement.pk:
               statement.keyword_set = self.cleaned_data['keyword']
           self.save_m2m()

    return statement

所以现在我的内联有一个filter_horizo​​ntal菜单,就像我想要的那样。但是存在一个问题:添加新关键字没有加号。

我知道RelatedFieldWidgetWrapper是解决这个问题的必要条件,而且我发现了很多人使用它的例子。但是,我还没能找到一个适合我情况的产品。我现在遇到的最直接的问题是试图在" rel"参数。 " rel"参数通常定义"所涉及的两个模型的关系,"离开这个流行的示例实现:http://dashdrum.com/blog/2012/07/relatedfieldwidgetwrapper/

我不知道该关系的内容,也不知道如何表明,因为我正在使用内联。所以我实际上并没有使用名为"关键字的字段,"我正在反向查看KeywordStatement之间的m2m关系。所以我不知道描述这段关系的名称是什么。

我发现的所有例子都没有真正谈到在这种情况下该怎么做。大多数示例很容易从其中一个模型中获得感兴趣的领域,然后得到它的类型或关系,但是使用内联模型和反向关系我不一定能做到这一点。

1 个答案:

答案 0 :(得分:0)

我设法通过多对多关系和内联模型的自定义小部件来满足,就像你正在描述的那样。

受到this answerthis post的启发,这是使用我的模型的结果,因为您没有在您的问题中提供models.py,并且您还有额外的 - 不需要这个场合 - 信息在你的代码。

models.py

class MasterModel(models.Model):
    pass


class ThirdModel(models.Model):
    pass


class InlineModel(models.Model):
    '''
         It should also be working with a ForeignKey 
         but I have not tested it.
    '''
    master_key = models.OneToOneField(MasterModel)
    the_field = models.ManyToManyField(ThirdModel)

forms.py

from django.contrib.admin import site as admin_site
from django.contrib.admin.widgets import RelatedFieldWidgetWrapper


class InlineModelForm(forms.Modelform):
     the_field = forms.ModelMultipleChoiceField(
        queryset=ThirdModel.objects.all(),
        required=False,
        widget=(
            <the_custom_widget with attributes etc>
        )
     )

    def __init__(self, *args, **kwargs):
       super().__init__(*args, **kwargs)
       self.fields['the_field'].widget = (
           RelatedFieldWidgetWrapper( 
               self.fields['the_field'].widget,
               self.instance._meta.get_field('the_field').rel,            
               admin_site,
           )
       )

    class Meta:
       model = InlineModel
       fields = '__all__'

admin.py:

class InlineModelAdminInline(admin.TabularInline):
    model = InlineModel
    form = InlineModelForm


@admin.register(MasterModel)
class MasterModelAdmin:
    inlines = (InlineModelAdminInline, )


@admin.register(InlineModel)
class InlineModelAdmin:
    form = InlineModelForm


@admin.register(ThirdModel)
class ThirdModelAdmin:
    pass