Opened 3 years ago

Closed 3 years ago

#32432 closed Bug (duplicate)

ModelForm does not respect ModelChoiceField's to_field_name attribute

Reported by: gopackgo90 Owned by: nobody
Component: Forms Version: 3.1
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by gopackgo90)

This is the same issue mentioned in #17657 but for ModelChoiceField instead of ModelMultipleChoiceField. This bug is present in Django 2.2.18 and Django 3.1.6. The first two tests were taken directly from #17657 just to show that ModelMultipleChoiceField still works as expected and the equivalent ModelChoiceField tests are added after, the last of which fails:

# models.py

from django.db import models


class Foo(models.Model):

    slug = models.CharField(max_length=40, unique=True)
    title = models.CharField(max_length=40, unique=True)

    def __str__(self):
        return self.title


class Bar(models.Model):

    foos = models.ManyToManyField(Foo)


class Baz(models.Model):

    foo = models.ForeignKey(Foo, on_delete=models.CASCADE)
# tests.py

from django.test.testcases import TestCase
from django import forms
from .models import Foo, Bar, Baz


class TestModelRelationshipChoiceWithFieldName(TestCase):

    @classmethod
    def setUpTestData(cls):
        spam = Foo.objects.create(title="Spam", slug="spam")
        ham = Foo.objects.create(title="Ham", slug="ham")
        eggs = Foo.objects.create(title="Eggs", slug="eggs")
        cls.m2m_instance = Bar.objects.create()

        cls.m2m_instance.foos.add(spam)
        cls.m2m_instance.foos.add(ham)
        cls.m2m_instance.foos.add(eggs)

        cls.fk_instance = Baz.objects.create(foo=eggs)

    def test_multiple_without_field_name(self):

        class Form(forms.ModelForm):

            foos = forms.ModelMultipleChoiceField(Foo.objects.all())

            class Meta:
                model = Bar
                fields = '__all__'

        form = Form(instance=self.m2m_instance)

        self.assertEquals(
            str(form["foos"]),
            '<select name="foos" required id="id_foos" multiple>\n'
            '  <option value="1" selected>Spam</option>\n\n'
            '  <option value="2" selected>Ham</option>\n\n'
            '  <option value="3" selected>Eggs</option>\n\n'
            '</select>'
        )

    def test_multiple_with_field_name(self):

        class Form(forms.ModelForm):

            foos = forms.ModelMultipleChoiceField(Foo.objects.all(), to_field_name="slug")

            class Meta:
                model = Bar
                fields = '__all__'

        form = Form(instance=self.m2m_instance)

        # Fixed in #17657, options weren't selected.
        self.assertEquals(
            str(form["foos"]),
            '<select name="foos" required id="id_foos" multiple>\n'
            '  <option value="spam" selected>Spam</option>\n\n'
            '  <option value="ham" selected>Ham</option>\n\n'
            '  <option value="eggs" selected>Eggs</option>\n\n'
            '</select>'
        )

    def test_one_without_field_name(self):

        class Form(forms.ModelForm):

            foo = forms.ModelChoiceField(Foo.objects.all())

            class Meta:
                model = Baz
                fields = '__all__'

        form = Form(instance=self.fk_instance)

        self.assertEquals(
            str(form["foo"]),
            '<select name="foo" required id="id_foo">\n'
            '  <option value="">---------</option>\n\n'
            '  <option value="1">Spam</option>\n\n'
            '  <option value="2">Ham</option>\n\n'
            '  <option value="3" selected>Eggs</option>\n\n'
            '</select>'
        )

    def test_one_with_field_name(self):

        class Form(forms.ModelForm):

            foo = forms.ModelChoiceField(Foo.objects.all(), to_field_name="slug")

            class Meta:
                model = Baz
                fields = '__all__'

        form = Form(instance=self.fk_instance)

        # Fails! Option isn't selected.
        self.assertEquals(
            str(form["foo"]),
            '<select name="foo" required id="id_foo">\n'
            '  <option value="">---------</option>\n\n'
            '  <option value="spam">Spam</option>\n\n'
            '  <option value="ham">Ham</option>\n\n'
            '  <option value="eggs" selected>Eggs</option>\n\n'
            '</select>'
        )

Change History (2)

comment:1 by gopackgo90, 3 years ago

Description: modified (diff)

comment:2 by Mariusz Felisiak, 3 years ago

Resolution: duplicate
Status: newclosed
Type: UncategorizedBug

Duplicate of #28316.

Note: See TracTickets for help on using tickets.
Back to Top