Opened 5 years ago
Last modified 5 years ago
#32432 closed Bug
ModelForm does not respect ModelChoiceField's to_field_name attribute — at Initial Version
| 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
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>'
)
Note:
See TracTickets
for help on using tickets.