why does django add each character to the list

Given a variable task = ‘abc’ we update the session variable as follows:

request.session[‘tasks’] = [task]

this works but seems like we are adding a list to a list. If we try the following:

request.session[‘tasks’] = task our session variable becomes:

[‘a’,‘b’,‘c’] instead of [‘abc’]

could someone explain why the second approach doesn’t work?

Can you include the code that shows that request.session['tasks'] == ['a', 'b', 'c']? That doesn’t seem right.

Hi Tim, thanks for the reply. I’m just starting to learn django. Here’s what I have in views.py

from django.shortcuts import render
from django import forms
from django.http import HttpResponseRedirect
from django.urls import reverse

class NewTaskForm(forms.Form):
task = forms.CharField(label=‘New Task’)
priority = forms.IntegerField(label =‘priority’,
min_value=1,max_value=5)

Create your views here.

def index(request):

if "tasks" not in request.session:
    request.session['tasks'] = []

return render(request, "tasks/index.html", {
    # "tasks": tasks
    "tasks": request.session['tasks']
})

def add(request):
if request.method == “POST”:
task = request.POST.get(‘task’)
form = NewTaskForm(request.POST)
if form.is_valid():
task = form.cleaned_data[“task”]

        request.session['tasks'] += [task]
        # or we can try doing it this way
        # request.session['tasks'] += task            
        
        return HttpResponseRedirect(reverse("tasks:index"))            
    else:
        return render(request, "tasks/add.html",{
            "form": form
        })

return render(request, "tasks/add.html",{
    "form": NewTaskForm()
})

and then in index.html we have:

{% extends ‘tasks/layout.html’ %}

{%  block body %}
    <h1>Tasks</h1>
    <ul>
    {% for task in tasks %}
        <li>{{task}}</li>
    {% empty %}
        <li>No tasks</li>
    {% endfor %}
    </ul>
    <a href="{% url 'tasks:add' %}">Add a new task</a>
{% endblock %}

HERE’S THE PROBLEM:

if we use request.session[‘tasks’] += [task] where task = ‘abc’

we get in the html abc

but if we use:

if we use request.session[‘tasks’] += ‘abc’
we get in the html :
a
b
c

Okay cool. The session library is working as it should, but there seems to be a misunderstanding on strings in python. A string in python is iterable, so using for value in "some string" will have an iteration for each character in that string. This is why you are seeing 'a', 'b', 'c' being displayed individually.

If request.session["tasks"] is a list, then you can concatenate another list to it via request.session["tasks"] += [val1, val2] or you can directly append a single value via request.session["tasks"].append(value).

In short continue using request.session["tasks"] += [task] or switch to:

request.session['tasks'].append(task)

Tim,

I understand what you are saying but if I print(request.session[‘tasks’] after I set request.session[‘tasks’] += ‘abc’ I get [‘a’, ‘b’, ‘c’] if I use request.session[‘tasks’] = ‘abc’ I get abc

if request.session[‘tasks’] is a list why when adding request.session[‘tasks’] += [task] do I not have a list of lists? What I end up with is a list of strings (which is what I want).

UPDATE, ahh I think I got it. In python when you add a list to a list you just extend the list. the other ways will add each iterable element

I’m not explaining myself well. When request.session['tasks'] += 'abc' gets executed, the string abc is considered a list, so it will combine the lists. For example:

x = [1, 2, 3]
x += [4, 5]
assert x == [1, 2, 3, 4, 5]

In your code this means:

request.session['tasks'] = [taskA]
request.session['tasks'] += 'abc'
assert request.session['tasks'] == [taskA, 'a', 'b', 'c']

This is because an iterator on a string in python will go over each individual value. For example:

for value in 'abc':
    print(value)
> "a"
> "b"
> "c"

Thus when you do request.session["tasks"] += 'abc' you’re combining the existing list request.session["tasks"] and the list of ["a", "b", "c"] (this is a simplification of strings). So if you want to use the += operator with a list, you need to use a list of strings or use .append rather than the += operator.

1 Like