1

I have a model called Keyword and a model called Statement, and I've been customizing the form for adding or changing statements. Each Keyword object has an m2m (many to many) relationship with Statement objects, and I wanted users to be able to select keywords to associate. The default widget for m2m fields isn't useful in my case because there are many Keyword objects so I needed something better than that. I used the FilteredSelectMultiple widget in order to get the adjustments I needed.

Here's the code for that.

In 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,]

in 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

So now I have a filter_horizontal menu for my inline, just like I wanted. But there's one problem: There's no plus sign to add new keywords.

I know that the RelatedFieldWidgetWrapper is necessary to resolve this, and I've found tons of examples of people using it. However, I haven't been able to find one that suits my situation. The most immediate problem I'm having right now is trying to insert something into the "rel" parameter. The "rel" parameter typically defines "a relation of the two models involved," going off of this popular example implementation: http://dashdrum.com/blog/2012/07/relatedfieldwidgetwrapper/

I don't know what to indicate for this relation nor how to indicate it because I'm working with an inline. So I'm not actually working with a field called "keywords," I am doing a reverse look up of the m2m relationship between Keyword and Statement. So I don't know what the name could be to describe the relationship.

All of the examples I've found haven't really talked about what to do in this situation. Most examples easily get the field of interest from one of the models and then get its type or relationship, but with an inline model and a reverse relation I can't necessarily do that.

Byron Smith
  • 587
  • 10
  • 32
  • Did you try to set `extra` and `max_num` inn your Inline? – Max M Aug 09 '17 at 11:29
  • hadn't. I will in a moment but... what would those properties be doing in this context? – Byron Smith Aug 09 '17 at 12:00
  • `extra` defines how many extra inlines will be displayed on default. `max_num` limits the number of inlines. So if your default value `max_num` is equal or less than your default value of `extra` no additional inline can be added. I your issue is caused by your modelForm that might not be the solution - but give it a try. – Max M Aug 09 '17 at 12:03
  • I see. Unfortunately I tried `max_num = 3` and `extra = 2` (and some other variants) but that didn't work out. – Byron Smith Aug 09 '17 at 12:08
  • Anothr issue actually is that the traditional inline is below the inline with filter_horizontal. So when I made these changes, they affected that model but did not affect the inline with filter_horizontal. – Byron Smith Aug 09 '17 at 12:11
  • potentially useful link that I will work with later: http://www.hoboes.com/Mimsy/hacks/replicating-djangos-admin/reusing-djangos-filter_horizontal/ – Byron Smith Aug 09 '17 at 12:13

1 Answers1

0

I managed to make ends meet with a many to many relation and a custom widget of an inline model, like the one you are describing.

Inspired from this answer and this post here is the result using my models because you do not provide a models.py in your question and you also have extra -unnecessary for this occasion- information in your code.

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
raratiru
  • 8,748
  • 4
  • 73
  • 113