[Fixed]-Django ModelChoiceField has no plus button

19πŸ‘

βœ…

You need to set a RelatedFieldWidgetWrapper wrapper in your model form:

The RelatedFieldWidgetWrapper (found in django.contrib.admin.widgets)
is used in the Admin pages to include the capability on a Foreign Key
control to add a new related record. (In English: puts the little green plus sign to the right of the control.)

class MyCustomUserCreationForm(models.ModelForm)
    ...
    location = forms.ModelChoiceField(queryset=Location.objects.all())

    def __init__(self, *args, **kwargs):
        super(MyCustomUserCreationForm, self).__init__(*args, **kwargs)
        rel = ManyToOneRel(self.instance.location.model, 'id') 
        self.fields['location'].widget = RelatedFieldWidgetWrapper(self.fields['location'].widget, rel, self.admin_site)

I could make a mistake in the example code, so see these posts and examples:

πŸ‘€alecxe

8πŸ‘

I have created method based on the answers above:

def add_related_field_wrapper(form, col_name):
    rel_model = form.Meta.model
    rel = rel_model._meta.get_field(col_name).rel
    form.fields[col_name].widget = 
    RelatedFieldWidgetWrapper(form.fields[col_name].widget, rel, 
    admin.site, can_add_related=True, can_change_related=True)

And then calling this method from my form:

class FeatureForm(forms.ModelForm):
    offer = forms.ModelChoiceField(queryset=Offer.objects.all(), required=False)
    package = forms.ModelChoiceField(queryset=Package.objects.all(), required=False)
    def __init__(self, *args, **kwargs):
        super(FeatureForm, self).__init__(*args, **kwargs)
        add_related_field_wrapper(self, 'offer')
        add_related_field_wrapper(self, 'package')

That works fine on Django 1.8.2.

πŸ‘€dan.goriaynov

2πŸ‘

Google pointed me to this page when searching how to get a β€œ+” icon next to fields in a custom form with ForeignKey relationship, so I thought I’d add.

For me, using django-autocomplete-light did the trick very well, using the β€œadd another” functionality.

πŸ‘€SaeX

1πŸ‘

You don’t even need to go that far, and besides, these answers are probably outdated as NONE of them worked for me in any capacity.

What I did to solve this is, as long as you have the ForeignKey field already in your model, then you can just create your custom ModelChoiceField:

class LocationModelChoiceField(forms.ModelChoiceField):
    def label_from_instance(self, obj):
        return "%" % (obj.name)

The key next is NOT to create a custom field for the ModelChoiceField in your ModelForm (ie location = forms.ModelChoiceField(Location.objects.all()))

In other words, leave that out and in your ModelForm have something like this:

class UserAdminForm(forms.ModelForm):

    class Meta:
        model = User
        fields = '__all__'

Lastly, in your ModelAdmin:

class UserAdmin(admin.ModelAdmin):
    model = User
    form = UserAdminForm

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'location':
        return LocationModelChoiceField(queryset=Location.objects.order_by('name')) # if you want to alphabetize your query
    return super().formfield_for_foreignkey(db_field, request, **kwargs)
πŸ‘€Devin B.

0πŸ‘

Alternative Method : Using .remote_field instead of rel

def add_related_field_wrapper(self,form, col_name):
    rel_model = form.Meta.model
    rel = rel_model._meta.get_field(col_name).remote_field
    form.fields[col_name].widget = RelatedFieldWidgetWrapper(form.fields[col_name].widget, rel, admin.site, can_add_related=True, can_change_related=True)


def __init__(self, *args, **kwargs):
    super(CustomerAdminForm, self).__init__(*args, **kwargs)
    self.add_related_field_wrapper(self, 'offer')
    self.add_related_field_wrapper(self, 'package')

Thankyou,

πŸ‘€Lenate John

Leave a comment