ModelChoiceField in django admin gives 'Select a valid choice. That choice is not one of the available choices.' error

1.6k Views Asked by At

Hej!

I want a field in my django admin area where the user can select from given choices in the database. For example get a list of countries and choose one. But I will always get the ' Select a valid choice. That choice is not one of the available choices.' error when you try to save the new instance.

#models.py

class PlaceSection(models.Model):
    code = models.CharField(max_length=1)

        def code_str(self):
        return self.code

# admin.py

class InstiForm(forms.ModelForm):
    place_sections = forms.ModelChoiceField(
        PlaceSection.objects.values(),
        widget=Select2Widget,
    )
    

    class Meta:
        model = Something
        fields = [
            "place_section"]


class InstiAdmin(admin.ModelAdmin):
    form = InstiForm
    save_on_top = True
    def save_model(self, request, obj, form, change):
    fieldsets = [
        (
            ("General"),
                {"fields": [
                    "place_sections"
                    ]
                }
            )
        ]

I do get the right choices in the admin dropdown but when I select one and save the error occurs.

Does anyone has an idea how to fix this (in the admin) found only similar problems without the admin part and no solution worked for me.

Help is really appreciated! :)

Edit:

I fixed the issue in my admin-area but now can't filter for PlaceSection in my forms/views. The needed fields are there, but after the 'search' the TypeError 'PlaceSection' object is not iterable occurs. It seems to be a NoneType and empty but I don't understand what I'm doing wrong.

Any further help is appreciated as well! :)

# forms.py

class SearchForm(forms.Form):
    place_sections = forms.ModelMultipleChoiceField(
        queryset=PlaceSection.objects.all(), widget=Select2MultipleWidget, required=False)     

# views.py

def search_institution(request):
    if request.method == "POST":
        form = SearchForm(request.POST)
        if form.is_valid():
            query = filter_query(form)
            context = {"result_data": serialize(query), "form": form, "show_form": False}
            return render(request, "stakeholders/search_form.html", context)
    else:
        form = SearchForm()

    context = {
        "result_data": serialize(Institution.objects.all()),
        "form": form, 
        "show_form": True
    }
    return render(request, "stakeholders/search_form.html", context)

# query.py

def filter_query(form):
    query = Institution.objects.all()
    if form.cleaned_data["place_sections"]:
        place_sections_query = Institution.objects.none()
        for section in form.cleaned_data["place_sections"]:
            place_sections_query = (
                    place_sections_query
                    | Institution.objects.filter(place_sections__in=section)
            )
        query = query.intersection(place_sections_query)
    return query

2

There are 2 best solutions below

6
moddayjob On BEST ANSWER

ModelChoiceField accepts a queryset argument. Your code is missing that.

place_sections = forms.ModelChoiceField(
        PlaceSection.objects.values(),
        widget=Select2Widget,
    )

should be as follows:

place_sections = forms.ModelChoiceField(
        queryset=PlaceSection.objects.all(),
        widget=Select2Widget,
    )

And probably not values() but .all()

Check out the documentation: https://docs.djangoproject.com/en/3.2/ref/forms/fields/#django.forms.ModelChoiceField

0
piah On

@moddayjob helped me a lot!

Complete solution for my problem is:

# models.py 

class PlaceSection(models.Model):
    code = models.CharField(max_length=1)

    def code_str(self):
        return self.code

    def __str__(self):
        return f"{self.code}, {self.description_german}"

class Institution(models.Model):
   place_sections = models.ManyToManyField(
        PlaceSection,
    ) 

   def serialize(self):
       return {"place_sections": ", ".join([place.code for place in self.place_sections.all()])}

# admin.py

@admin.register(NaceSection)
class PlaceSectionAdmin(admin.ModelAdmin):
    search_fields = [
        "code",
        "place_sections",
    ]


class InstitutionForm(forms.ModelForm):
        model = Institution 
        fields = [
            "place_sections"
        ]


@admin.register(Institution)
class InstitutionAdmin(admin.ModelAdmin):
    form = InstitutionForm
    save_on_top = True

    fieldsets = ["place_sections"]
    autocomplete_fields = ["place_sections"]
# query.py
def filter_query(form):
    query = Institution.objects.all()
        if form.cleaned_data["place_sections"]:
        place_sections_query = (
            Institution.objects.filter(place_sections__in=form.cleaned_data["place_sections"])
            )
        query = query.intersection(place_sections_query)
# forms.py

class SearchForm(forms.Form):
    place_sections = forms.ModelMultipleChoiceField(
        queryset=PlaceSection.objects.all(), widget=Select2MultipleWidget, required=False)