Django get_object_or_404 with select_related causes form checkbox widget weird behavior : Django 1.4 bug?

1.6k Views Asked by At

I come with a really strange Django 1.4 behaviour wich sounds like a bug to me. I looked anywhere if someone experienced it, but didn't find anything.

My concern is about Django form creation using ModelForm, with a model containing boolean field.

Let Post and Topic two models wich should look like :

class Topic(models.Model):
    my_bool = models.BooleanField(default=False)

class Post(models.Model):
    topic = models.ForeignKey(Topic, related_name='posts')

Now, I'm gonna try to generate a form using TopicForm a class definied elsewhere :

post = Post.objects.get(pk=id_post)
f = TopicForm(instance=post.topic)
print f

It works fine : if in DB my_bool is False, the checkbox is not checked. If my_bool is True, the checkbox is checked. Here is the result :

<p><label for="id_my_bool">my_bool:</label> <input type="checkbox" name="my_bool" id="id_my_bool" /></p>

The problem !

OK, so here is the problem : if I use get_object_or_404 to get my Post object, then my_bool field will always be checked ! Look at this :

post = get_object_or_404(Post.objects.select_related('topic'), pk=id_post)
f = TopicForm(instance=post.topic)
print f

Output (weird) :

<p><label for="id_my_bool">my_bool:</label> <input checked="checked" type="checkbox" name="my_bool" value="0" id="id_my_bool" /></p>

Nota : I tryed several other ways to get the Post object, which all work fine :

  • post = Post.objects.filter(pk=id_post)[0]
  • post = get_object_or_404(Post, pk=id_post)
  • post = Post.objects.get(pk=id_post)

The only thing which makes it bug is :

post = get_object_or_404(Post.objects.select_related('topic'), pk=id_post)

Comments

Have you got any idea ?

Thank you very much in advance !

2

There are 2 best solutions below

0
Liubov On BEST ANSWER

Had the same bug in my app and found opened ticket. It seems the main problem is in pair select_related & MySQL: MySQL returns integers for booleans but Django can't associate them with corresponding model when using select_related; consequently, CheckboxInput gets value 0 instead of False and treats it like value in checkbox list.

You can:

  1. use patch from ticket;
  2. or avoid using select_related;
  3. or patch CheckboxInput widget:

    class SingleCheckboxInput(forms.CheckboxInput):
        def render(self, name, value, attrs=None):
            if value in (0, 1):
                value = bool(value)
            return super(SingleCheckboxInput, self).render(name, value, attrs)
    
    class TopicForm(django.forms.ModelForm):
        class Meta:
            model = Topic
            widgets = {'my_bool': SingleCheckboxInput}
    
0
gloriajw On

I see a similar bug, where if I uncheck all boxes, POST data is empty! if I uncehck only one, POST data arrives. Instead of calling get_object_or_404(), examine your inbound request.POST data.