Search code examples
pythondjangoclass-variables

Django strange behaviour


I have a view in Django which calls external library/class. The problem is that for some reason Django keeps caching results coming from previous calls of that class.

Please consider the following simple example:

Django view:

from some_path import Demo
def test_view(request):
    demo = Demo()
    result = demo.do_something()
    return render(request, 'test.html',
                            { 'result':result }
                )

Demo class:

class Demo():
    result = []

    def do_something(self):
        self.result.append(1)
        self.result.append(2)
        self.result.append(3)
        return self.result

You expect result to be [1, 2, 3], right ? WRONG!

The first time a page is loaded you'll get the correct result. But on all following requests it will keep incrementing: [1, 2, 3, 1, 2, 3]... [1, 2, 3, 1, 2, 3, 1, 2, 3] ...

So my question is obvious - what is going on here ? How do i receive [1, 2, 3] every time i call a class inside Django view ?

Django 1.7 / MacOS X.


Solution

  • Define result in __init__ as an instance attribute.

    class Demo():
    
        def __init__(self):
            self.result = []
    
        def do_something(self):
            self.result.append(1)
            self.result.append(2)
            self.result.append(3)
            return self.result
    

    If you print result in your code then you will get that result is assigning just once,

    class Demo():
        result = []
        print result
    
        def ...
            .
            .
    
    d = Demo()
    print d.do_something()
    print d.do_something()
    e = Demo()
    print e.do_something()
    >>> 
    []
    [1, 2, 3]
    [1, 2, 3, 1, 2, 3]
    [1, 2, 3, 1, 2, 3, 1, 2, 3]
    

    result is a mutable object, whenever you made an instance of the class it refer result to the same reference. In case of Immutable object:-

    class Demo():
        result = 1
    
        def do_something(self):
            self.result += 1
    
    d = Demo()
    d.do_something()
    
    
    d.do_something()
    e = Demo()
    e.do_something()
    print d.result, e.result
    

    Output:-

    >>> 
    3 2