#32432: ModelForm does not respect ModelChoiceField's to_field_name attribute
-------------------------------+--------------------------------------
     Reporter:  gopackgo90     |                    Owner:  nobody
         Type:  Uncategorized  |                   Status:  new
    Component:  Forms          |                  Version:  3.1
     Severity:  Normal         |               Resolution:
     Keywords:                 |             Triage Stage:  Unreviewed
    Has patch:  0              |      Needs documentation:  0
  Needs tests:  0              |  Patch needs improvement:  0
Easy pickings:  0              |                    UI/UX:  0
-------------------------------+--------------------------------------
Description changed by gopackgo90:

Old description:

> 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>'
>         )
> }}}

New description:

 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:


 {{{#!python
 # 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)
 }}}


 {{{#!python
 # 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>'
         )
 }}}

--

-- 
Ticket URL: <https://code.djangoproject.com/ticket/32432#comment:1>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/068.14c0d6eaa29065deaf149b6112e184ae%40djangoproject.com.

Reply via email to