Opened 7 years ago

Closed 7 years ago

#29201 closed Bug (invalid)

Rendering issues when using ArrayField(models.BooleanField())

Reported by: linluc Owned by:
Component: contrib.postgres Version: 2.0
Severity: Normal Keywords: ArrayField BooleanField SplitArrayWidget rendering
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

My goal is to replace 50 Boolean fields with one ArrayField(models.BooleanField(), size=50) so I am prototyping this approach. I have not found a single online example with such combination (ArrayField + BooleanField) and also this area is very poorly documented. I am running into numerous issues and that makes me feel that it was never properly tested. Well, I am offering my help in future testing regarding this issue.

Here is my simple model (using Django 2.0.3):

class Test1Model(models.Model):
   user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
   user_choices = ArrayField(models.BooleanField(), default=(), size=5, null=True)

form:

class Test1Form(forms.ModelForm):
   class Meta:
      model = Test1Model 
      
      fields = ('user_choices',)

      widgets = {
         'user_choices' : SplitArrayWidget(forms.CheckboxInput(),5)
      }

view:

def run_test1(request):
   if request.method == 'POST':
      test_form = Test1Form(instance=request.user.test1model, data=request.POST)

      if test_form.is_valid():
         test_form.save()
      else:
        print(test_form.errors)
   else:
      test_form = Test1Form(instance=request.user.test1model)
   return render(request, 'test1/test1.html' , {'test_form': test_form})

template (test1.html):

<!DOCTYPE html>
<html>
<head>
<title>TEST1</title>
</head>
<body>

<form action="." method="post" autocomplete="off">

     {{ test_form.as_p }}
     {% csrf_token %}
    
    <p><input type="submit" value="Submit"></p>

</form>

</body>
</html>

Here you will encounter a bug which I already reported (https://code.djangoproject.com/ticket/29197) but it is easy to fix by moving the template directory.

After fixing the template issue the initial page renders OK, 5 check-boxes are present (see attached image, section A).

Problem 1: by default all check-boxes are required and I was unable to reverse that. Adding "required = False" caused the following error:

TypeError: __init__() got an unexpected keyword argument 'required'

See the image, section B.

OK, for the purpose of prototyping I checked all check boxes and submitted the form. The output was highly unexpected (image, section C).

The output page includes 24 check-boxes and by looking at the generated HTML we can see why (hint: value=""):

<p><label for="id_user_choices_0">User choices:</label>
<input type="checkbox" name="user_choices_0" value="T" checked required id="id_user_choices_0" />
<input type="checkbox" name="user_choices_1" value="r" checked required id="id_user_choices_1" />
<input type="checkbox" name="user_choices_2" value="u" checked required id="id_user_choices_2" />
<input type="checkbox" name="user_choices_3" value="e" checked required id="id_user_choices_3" />
<input type="checkbox" name="user_choices_4" value="," checked required id="id_user_choices_4" />
<input type="checkbox" name="user_choices_5" value="T" checked required id="id_user_choices_5" />
<input type="checkbox" name="user_choices_6" value="r" checked required id="id_user_choices_6" />
<input type="checkbox" name="user_choices_7" value="u" checked required id="id_user_choices_7" />
<input type="checkbox" name="user_choices_8" value="e" checked required id="id_user_choices_8" />
<input type="checkbox" name="user_choices_9" value="," checked required id="id_user_choices_9" />
<input type="checkbox" name="user_choices_10" value="T" checked required id="id_user_choices_10" />
<input type="checkbox" name="user_choices_11" value="r" checked required id="id_user_choices_11" />
<input type="checkbox" name="user_choices_12" value="u" checked required id="id_user_choices_12" />
<input type="checkbox" name="user_choices_13" value="e" checked required id="id_user_choices_13" />
<input type="checkbox" name="user_choices_14" value="," checked required id="id_user_choices_14" />
<input type="checkbox" name="user_choices_15" value="T" checked required id="id_user_choices_15" />
<input type="checkbox" name="user_choices_16" value="r" checked required id="id_user_choices_16" />
<input type="checkbox" name="user_choices_17" value="u" checked required id="id_user_choices_17" />
<input type="checkbox" name="user_choices_18" value="e" checked required id="id_user_choices_18" />
<input type="checkbox" name="user_choices_19" value="," checked required id="id_user_choices_19" />
<input type="checkbox" name="user_choices_20" value="T" checked required id="id_user_choices_20" />
<input type="checkbox" name="user_choices_21" value="r" checked required id="id_user_choices_21" />
<input type="checkbox" name="user_choices_22" value="u" checked required id="id_user_choices_22" />
<input type="checkbox" name="user_choices_23" value="e" checked required id="id_user_choices_23" />
</p>
   

I should note that the values are saved in the database correctly, but still the Django included rendering choices (as_p, as_ul, as_table) are broken here.

Please also note that the label assignment is broken as well, there is only one label generated for all check-boxes.

Attachments (1)

ArrayError.png (22.4 KB ) - added by linluc 7 years ago.

Download all attachments as: .zip

Change History (2)

by linluc, 7 years ago

Attachment: ArrayError.png added

comment:1 by Tim Graham, 7 years ago

Resolution: invalid
Status: newclosed

The default form field is SimpleArrayField which isn't compatible with your widget override of SplitArrayWidget. You need to use the SplitArrayField form field with that widget.

Note: See TracTickets for help on using tickets.
Back to Top