Django

Code

Ticket #5247 (new)

Opened 1 year ago

Last modified 7 months ago

ModelMultipleChoiceField doesn't select initial choices

Reported by: uhlr@us.ibm.com Assigned to: nobody
Milestone: Component: Forms
Version: SVN Keywords: ModelMultipleChoiceField SelectMultiple
Cc: Triage Stage: Accepted
Has patch: 1 Needs documentation: 0
Needs tests: 0 Patch needs improvement: 0

Description

When using a ModelMultipleChoiceField?, initial values are not selected. After some investigation, I discovered that this was because SelectMultiple?.render() was comparing the primary key of the choices to the unicode string of each value; this obviously only works if one's model returns the primary key, which is near-universally suboptimal.

I have modified SelectMultiple? to call a method value_to_str() (perhaps not the best name) which defaults to returning the force_unicode() of the value; I've added a subclass ModelSelectMultiple? which overrides this to return SelectMultiple?.value_to_str(value._get_pk_val()). Finally, I modified ModelMultipleChoiceField? to use a ModelSelectMultiple? widget rather than a SelectMultiple?.

This does what's expected, and is extensible in the future.

Attachments

multipatch.patch (2.4 kB) - added by uhlr@us.ibm.com on 08/24/07 10:41:13.
svn diff for patch application
patch6702.diff (2.8 kB) - added by baumer1122 on 11/19/07 12:53:05.
patch against #6702 that passes tests
patch.diff (1.6 kB) - added by baumer1122 on 11/19/07 23:14:54.
better patch

Change History

08/24/07 10:41:13 changed by uhlr@us.ibm.com

  • attachment multipatch.patch added.

svn diff for patch application

08/24/07 10:42:55 changed by uhlr@us.ibm.com

Note also that in my SVN branch smart_unicode() is used; in my installed version force_unicode() is used instead. In my patch I use smart_unicode(); if it has gone away then simply replace it with force_unicode().

09/15/07 15:53:02 changed by PhiR

might be a duplicate of #5481 which also has a patch.

09/15/07 18:28:23 changed by rcoup

It's not a duplicate, but its semi-relevant. In #5481, whatever ends up as keys in ChoiceField?.choices gets faithfully returned as cleaned_data - be it integer, string, object, etc.

Should creating keys be the widgets responsibility or the fields?

11/19/07 12:53:05 changed by baumer1122

  • attachment patch6702.diff added.

patch against #6702 that passes tests

11/19/07 16:55:25 changed by lukeplant

  • needs_better_patch set to 1.
  • needs_tests set to 1.

Just by looking at them, you can see the patches can't work. ModelMultipleChoiceField is defined as a function when it should be a class. In the latest patch, it is then imported into another model and never used!

To determine correctness, there should be a test which fails without the patch, and passes with it.

11/19/07 23:13:34 changed by baumer1122

  • needs_better_patch deleted.
  • needs_tests deleted.

OK, here's a better patch, although I'm not sure it is the right one. It works for me but I'm not sure that testing for _get_pk_val is the best way to determine whether we're working with a model instance or not. Unfortunately, django.db.models can't be imported here to use isinstance

Here is a simple test case for the problem:

models.py:

from django.db import models

class MyModel(models.Model):
    name = models.CharField(max_length=100)

forms.py:

from django import newforms as forms
from myapp.models import MyModel

class MyForm(forms.Form):
    my_field = forms.ModelMultipleChoiceField(queryset=MyModel.objects.all())
from myapp import forms
from myapp.models import MyModel
MyModel.objects.create(name="one")
f = forms.MyForm({'my_field':MyModel.objects.all()})
f['my_field'].data #correct
f['my_field'].as_widget() #incorrect, without patch nothing is selected

11/19/07 23:14:54 changed by baumer1122

  • attachment patch.diff added.

better patch

02/19/08 02:53:43 changed by brosner

I really don't think special casing objects is the right thing to do here (Especially a hacky type checking using hasattr). While what is described doesn't work, I feel this is a very uncommon use-case that can be easily fixed by simple using list comprehension:

>>> form = forms.MyForm(initial={"my_field": [o.pk for o in MyModel.objects.all()]})
>>> print form["my_field"]
<select multiple="multiple" name="my_field" id="id_my_field">
<option value="1" selected="selected">Test 1</option>
<option value="2" selected="selected">Test 2</option>
<option value="3" selected="selected">Test 3</option>
<option value="4" selected="selected">Test 4</option>

02/28/08 09:04:40 changed by jacob

  • stage changed from Unreviewed to Accepted.

02/28/08 09:14:01 changed by brosner

Jacob,

I meant to close this ticket as a wontfix, but looks like I forgot to do that, per my reasoning above. Do you see that the current patch something that is acceptable or another way to solve this? I feel a simple list comprehension above would be fine the correct way to solve this.

02/28/08 09:55:05 changed by brosner

Ugh, ok, I thought about this a bit more on my way into work. I am completely missing the point ;) Discard what I said earlier. I am going to look into this a bit more.

02/28/08 10:08:09 changed by jacob

Yeah, I would expect if I've got a ModelMultipleChoiceField I should be able to do initial={'f': MyModel.objects.filter(....)} and have that Just Work™.

04/27/08 16:33:25 changed by drano

I have the same problem with initial choice selected. I have applied the patch, and the problem is solved. Then, why this patch is not included in the trunk ?


Add/Change #5247 (ModelMultipleChoiceField doesn't select initial choices)




Change Properties
Action