7

I've just started using class-based views in django. But there's an issue that is confusing for me. I ran the following code snippet with django 1.4.1 with multithreaded development server.

class TestView(TemplateView):
    template_name = 'test.html'
    count = 0
    mylist = [1, ]

    def get(self, request, *args, **kwargs):
        self.count += 1
        self.mylist.append(self.mylist[-1] +1)
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)

    def get_context_data(self, **kwargs):
        context = super(TestView, self).get_context_data(**kwargs)
        context['count'] = self.count
        context['mylist'] = self.mylist
        return context

The template just outputs the context variables count and mylist. When this view is called e.g. up to 5 times the output will look like this:

count: 1
mylist: [1, 2, 3, 4, 5, ]

And now I'm confused. The django docs says, that each request has its own individual class instance.

So how it is possible to extend mylist over several requests? Why the count variable was not incremented?

Simeon Visser
  • 118,920
  • 18
  • 185
  • 180
user1603806
  • 141
  • 1
  • 3

3 Answers3

1

lists are mutable. ints are immutable

You can append to a list, and it is still the same reference on your class. But when you do self.count += 1, you are creating a new int object each time, which becomes the scope of that instance. The value never affects the class.

If, for instance, you set it up like this:

count = [0]

def get(self):
    self.count[0] += 1

You would find that count will be incremented between instances, because you are modifying a member of the list, and not replacing the object each time. Not that I recommend that container. Just an example.

You could specifically modify the class directly by doing something like this:

count = 0

def get(self):
    self.__class__.count += 1

This will replace the int object on the class level each time.

But I would be very careful trying to persist data on the class between threads like this. it is not thread safe. There isn't really an issue with read-only data, but to be changing it from a bunch of different threads could be problematic. It would be a lot better if you stored your data in the database.

jdi
  • 90,542
  • 19
  • 167
  • 203
1

If you need something available over several requests, you need to add it to the session. An ivar is not the place for that. For thread-safety, the as_view method returns a brand new instance of the class each time, which is not effected by anything else that happens on any other instances of the same class. This is by design and you'd have numerous problems if it wasn't the case.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
0

On each request, a view is created and called anew, with no knowledge of a previous view. To keep some information across several views you need to put it in a persistent storage, which in Django usually means either database if you need long-term storage, or sessions for short-term persistence.

Also, there is no need almost ever to override get (and post); everything you did there can be done in the get_context_data method.

Berislav Lopac
  • 16,656
  • 6
  • 71
  • 80