我有一个名为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_horizontal菜单,就像我想要的那样。但是存在一个问题:添加新关键字没有加号。
我知道RelatedFieldWidgetWrapper
是解决这个问题的必要条件,而且我发现了很多人使用它的例子。但是,我还没能找到一个适合我情况的产品。我现在遇到的最直接的问题是试图在" rel"参数。 " rel"参数通常定义"所涉及的两个模型的关系,"离开这个流行的示例实现:http://dashdrum.com/blog/2012/07/relatedfieldwidgetwrapper/
我不知道该关系的内容,也不知道如何表明,因为我正在使用内联。所以我实际上并没有使用名为"关键字的字段,"我正在反向查看Keyword
和Statement
之间的m2m关系。所以我不知道描述这段关系的名称是什么。
我发现的所有例子都没有真正谈到在这种情况下该怎么做。大多数示例很容易从其中一个模型中获得感兴趣的领域,然后得到它的类型或关系,但是使用内联模型和反向关系我不一定能做到这一点。
答案 0 :(得分:0)
我设法通过多对多关系和内联模型的自定义小部件来满足,就像你正在描述的那样。
受到this answer和this 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