#26970 closed Bug (fixed)
Disabled ModelMultipleChoiceField does not validate anymore
| Reported by: | karyon | Owned by: | nobody | 
|---|---|---|---|
| Component: | Forms | Version: | 1.10 | 
| Severity: | Release blocker | Keywords: | |
| Cc: | johannes.linke@… | Triage Stage: | Accepted | 
| Has patch: | yes | Needs documentation: | no | 
| Needs tests: | no | Patch needs improvement: | no | 
| Easy pickings: | no | UI/UX: | no | 
Description (last modified by )
i have the following test:
    def test_foo(self):
        # Course has an m2m to degrees
        course = mommy.make(Course, semester=mommy.make(Semester), degrees=[mommy.make(Degree)])
        # get_form_data_from_instance creates a dict with all the attributes. contains "degrees: [4]"
        form_data = get_form_data_from_instance(ContributorCourseForm, course)
        # ContributorCourseForm is a simple ModelForm on Course
        form = ContributorCourseForm(form_data, instance=course)
        self.assertTrue(form.is_valid())
        
        # recreate form
        form = ContributorCourseForm(form_data, instance=course)
        # disable degrees field
        form.fields['degrees'].disabled = True
        self.assertTrue(form.is_valid())
the second assert fails. form.errors says "degrees: Enter a list of values." which doesn't make sense, since 1. it does have a degree (the form renders correctly with that degree selected), and 2. this shouldn't happen just because the field is disabled.
this showed up in 3744fc1666c41aeb4ed44f31605bafdb413b42bc, the fix for https://code.djangoproject.com/ticket/26917#comment:1
likely related: https://code.djangoproject.com/ticket/25980, same error message when providing a queryset as initial value to a disabled ModelMultipleChoiceField.
Change History (14)
comment:1 by , 9 years ago
| Cc: | added | 
|---|
comment:2 by , 9 years ago
| Description: | modified (diff) | 
|---|
comment:3 by , 9 years ago
| Description: | modified (diff) | 
|---|---|
| Summary: | disabled modelMultipleChoiceField does not validate anymore → Disabled ModelMultipleChoiceField does not validate anymore | 
comment:4 by , 9 years ago
| Description: | modified (diff) | 
|---|
comment:5 by , 9 years ago
comment:7 by , 9 years ago
here are two tests:
def test_disabled_model_multiple_choice_field(self):
    class WriterForm(forms.Form):
        persons = forms.ModelMultipleChoiceField(queryset=Writer.objects.all())
    person1 = Writer.objects.create(name="Person 1")
    form = WriterForm(data={'persons': [person1.pk]})
    self.assertTrue(form.is_valid())
    form = WriterForm(data={'persons': [person1.pk]})
    form.fields['persons'].disabled = True
    self.assertTrue(form.is_valid())
def test_disabled_model_multiple_choice_field2(self):
    class ArticleCategoriesForm(forms.ModelForm):
        categories = forms.ModelMultipleChoiceField(Category.objects.all(), required=False)
        class Meta:
            model = Article
            fields = ['categories']
    category1 = Category.objects.create(name="uiae")
    article1 = Article.objects.create(
                pub_date=datetime.date(1988, 1, 4),
                writer=Writer.objects.create(name='Test writer'),
                # categories= [category1.pk], # throws a warning
            )
    article1.categories.set([category1.pk]) # without this, the test passes
    # article1.categories = [category1.pk] # throws a warning
    # instance must be set, otherwise test passes
    form = ArticleCategoriesForm(data={'categories': [category1.pk]}, instance=article1)
    self.assertTrue(form.is_valid())
    form = ArticleCategoriesForm(data={'categories': [category1.pk]}, instance=article1)
    form.fields['categories'].disabled = True
    self.assertTrue(form.is_valid())
both fail at the second assert, the first one with "this field is required" (setting it to required=False or disabled=False makes the test pass), the second one with "please enter a list of values", like the original report.
i'm not sure what the protocol is, should i put the code somewhere else?
unrelated: note the warnings when assigning article.categories. the warning was "Direct assignment to the reverse side of a related set is deprecated due to the implicit save() that happens. Use article_set.set() instead." although i was not assigning to the reverse side. should i file a separate bug?
comment:8 by , 9 years ago
From what I see, test_disabled_model_multiple_choice_field fails on 1.9.x as well as 1.10.x so it doesn't seem to be a correct regression test. 
After applying 3744fc1666c41aeb4ed44f31605bafdb413b42bc to different points along the 1.10.x branch, I bisected the failure of test_disabled_model_multiple_choice_field2 to ded502024191053475bac811d365ac29dca1db61. I'll continue investigation later if no one else does.
Good spot on the deprecation message. Here's a PR to correct it.
comment:9 by , 9 years ago
| Component: | Uncategorized → Forms | 
|---|---|
| Has patch: | set | 
| Severity: | Normal → Release blocker | 
| Triage Stage: | Unreviewed → Accepted | 
| Type: | Uncategorized → Bug | 
Let me know if this PR solves your failures.
comment:10 by , 9 years ago
yes it does, thanks!
the first test was not fixed by this. should i create a new bug for that?
comment:11 by , 9 years ago
The first failure looks expected because disabled fields ignore what's in data and instead use what's in initial or instance.
Can you provide a test case for Django's test suite rather than your own project? Is this some change in Django 1.10 from 1.9? I thought we reverted to the 1.9 version of the code in a5f85d891b51d7ceb4f9e422e3e4f5c741062288.