Opened 8 years ago

Closed 7 years ago

Last modified 3 years ago

#4907 closed Uncategorized (worksforme)

MultipleChoiceField cleaned_data returns last choice

Reported by: hattawayd+django@… Owned by: adrian
Component: Forms Version: master
Severity: Normal Keywords: MultipleChoiceField cleaned_data
Cc: wangbin@… Triage Stage: Unreviewed
Has patch: yes Needs documentation: no
Needs tests: yes Patch needs improvement: no
Easy pickings: yes UI/UX: no

Description

When using a MultipleChoiceField, it is possible for the user to select multiple choices,
however when accessing cleaned_data, only the last choice is in the dictionary.
I've investigated somewhat, and this is happening before the clean method of the field object gets called. I haven't had a chance to investigate further.

Attachments (2)

Screenshot-Add comm | Django site admin - Mozilla Firefox-1.png (70.4 KB) - added by Wang Chun <wangchun@…> 7 years ago.
Screenshot-Add comm | Django site admin - Mozilla Firefox.png (70.3 KB) - added by Wang Chun <wangchun@…> 7 years ago.

Download all attachments as: .zip

Change History (12)

comment:1 Changed 8 years ago by SmileyChris

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to worksforme
  • Status changed from new to closed

The code for a SelectMultiple widget seems fine

    def value_from_datadict(self, data, files, name):
        if isinstance(data, MultiValueDict):
            return data.getlist(name)
        return data.get(name, None)

I'm going to put this down to user error somewhere along the way since I haven't heard of this before and you'd think that it would be a common problem if it was happening to everyone.

Don't be afraid to reopen if you can duplicate this.

comment:2 follow-up: Changed 7 years ago by Wang Chun <wangchun@…>

  • Resolution worksforme deleted
  • Status changed from closed to reopened

Simply speaking, if it was a ManyToMany, and has 10+ options, if you select 12, then it's option 1 and option 2, not option 12.

comment:3 in reply to: ↑ 2 Changed 7 years ago by russellm

  • Resolution set to worksforme
  • Status changed from reopened to closed

Replying to Wang Chun <wangchun@exoweb.net>:

Simply speaking, if it was a ManyToMany, and has 10+ options, if you select 12, then it's option 1 and option 2, not option 12.

This doesn't clarify anything. If you believe you can reproduce the problem described by this ticket, you need to provide full instructions on how to duplicate the problem, not a vague 1 line comment.

Changed 7 years ago by Wang Chun <wangchun@…>

Changed 7 years ago by Wang Chun <wangchun@…>

comment:4 Changed 7 years ago by Wang Chun <wangchun@…>

  • Resolution worksforme deleted
  • Status changed from closed to reopened

sorry about the unclear description above.

Create models like:

from django.db import models

class Publication(models.Model):
    title = models.CharField(max_length=20)

    class Admin:
        pass

    def __unicode__(self):
        return self.title

class Person(models.Model):
    name = models.CharField(max_length=20)

    class Admin:
        pass

    def __unicode__(self):
        return self.name

class Comm(models.Model):
    title = models.CharField(max_length=20)
    pubs = models.ForeignKey(Publication)
    attendees = models.ManyToManyField(Person)

    class Admin:
        pass

    def __unicode__(self):
        return self.title

As in attached image http://code.djangoproject.com/attachment/ticket/4907/Screenshot-Add%20comm%20%7C%20Django%20site%20admin%20-%20Mozilla%20Firefox-1.png : I created 13 person objects in django admin, when I was trying to add a comm with initial parameter "attendees=1&attendees=2", only the attendee "person1" (id=2) was selected.

As in attached image http://code.djangoproject.com/attachment/ticket/4907/Screenshot-Add%20comm%20%7C%20Django%20site%20admin%20-%20Mozilla%20Firefox.png : When I was trying to set the parameter to "attendees=12", person11 (id=12) should be selected, but here in the test, person0 (id=1) and person1 (id=2) was selected. There is no way to select person11 with the "attendees" URL query string.

comment:5 Changed 7 years ago by wangbin <wangbin@…>

  • Cc wangbin@… added

comment:6 Changed 7 years ago by russellm

  • Resolution set to worksforme
  • Status changed from reopened to closed

I have absolutely no idea what you're doing here. The model you provide works fine for me, and I have no difficulty using the admin interface to assign attendees.

The screenshots you provided suggest that there is something VERY significant about your setup that you are not telling me. You say you are trying to set the attendees on a Comm object, but the URL in your screenshot has GET parameters. I don't know how you manufactured those URLS, but the Django admin doesn't use GET arguments to modify anything (and neither should any other web application - GET requests are not supposed to modify server state).

On top of that, the error you are reporting relates to the admin interface in trunk - the reported problem for this ticket was that "MultipleChoiceField cleaned_data returns last choice", which is a newforms issue, and therefore by definition has nothing to do with trunk.

Might I suggest that you raise this issue on the users mailing list, so that the whole community can see (and hopefully fix) the problem you are having. When you send your message to django-users, be sure to include a description of _everything_ you are doing, not just a few random screenshots and a model.

comment:7 Changed 7 years ago by hotani

  • Resolution worksforme deleted
  • Status changed from closed to reopened

I believe I just ran into this. It is happening when I attempt to manually process a MultipleChoiceField in a view. The data is a list of users contained in request.POSTusers?.

When I loop through this in a view, it should add each user to the target model:

for u in request.POST['users']:
  new_status = MsgStatus(user=User.objects.get(pk=u))
  new_status.save()

However, I keep getting an error: "User matching query does not exist." Doing the same from django shell works fine. When I added the offending IDs to a string and passed it back to the form, the problem became apparent. For a list of 3 users selected in the field, 123, 345, 654 - the last one is being broken apart in the loop. Instead of adding '123', '345', and '654', the function is attempting to add '6', '5', and '4' which is the last element in the list separated out into single digit numbers. No matter how many selections I make in the field, what is being sent to the model is always the same.

This is in SVN version 8063 (today).

comment:8 Changed 7 years ago by SmileyChris

  • Resolution set to worksforme
  • Status changed from reopened to closed

You should be using form.cleaned_data instead of request.POST (even if you were using it you'd need to use .POST.getlist(...))

Try asking in the forums or on IRC for problems like this, often it's a pebkac ;)

comment:9 Changed 7 years ago by hotani

Thanks, I eventually found the problem to be my ignorance of the 'getlist' method of request.POST. Once I used request.POST.getlist('users') it behaved as expected.

comment:10 Changed 3 years ago by anonymous

  • Easy pickings set
  • Has patch set
  • Needs tests set
  • Severity set to Normal
  • Type set to Uncategorized
  • UI/UX unset
Note: See TracTickets for help on using tickets.
Back to Top