Termos
Termos

Reputation: 694

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.

Upvotes: 0

Views: 127

Answers (3)

Tanveer Alam
Tanveer Alam

Reputation: 5275

"""
Case 1:
Here we have declared the result and some_string as static Class variable 
"""
class Demo_1():
    result = []
    some_string = ""

    def do_something(self):
        Demo_1.some_string = Demo_1.some_string + "Python "
        self.result.append(1)
        self.result.append(2)
        self.result.append(3)
        return self.result

demo = Demo_1()
print Demo_1.result
result = demo.do_something()
print Demo_1.result

demo = Demo_1()
result = demo.do_something()
print Demo_1.result

demo = Demo_1()
result = demo.do_something()
print Demo_1.result

print result
print demo.some_string

print "Demo_1 class attributes :-", dir(Demo_1)

"""
Case1 Output :
    []
    [1, 2, 3]
    [1, 2, 3, 1, 2, 3]
    [1, 2, 3, 1, 2, 3, 1, 2, 3]
    [1, 2, 3, 1, 2, 3, 1, 2, 3]
    Python Python Python 
    Demo_1 class attributes :- ['__doc__', '__module__', 'do_something', 'result', 'some_string']

As you can see both result and some_string exists in Demo_1's attributes 
which you can access by both by Class name as well as it's instance 
"""

print "-----------------------------------------------------------------"

"""
Case 2:
Here we have declared the result variable as Class instance variable.
So each time we create an instance of class it creates new memory for that instance.
"""
class Demo_2():

    def __init__(self):
        self.result = []
        self.some_string = " "

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

demo = Demo_2()
result = demo.do_something()
print demo.result

demo = Demo_2()
result = demo.do_something()
print demo.result

demo = Demo_2()
result = demo.do_something()
print demo.result

print result
print "Demo_1 class attributes :-", dir(Demo_2)
print Demo_2.some_string

"""
Case2 Output :
    [1, 2, 3]
    [1, 2, 3]
    [1, 2, 3]
    [1, 2, 3]
    Demo_1 class attributes :- ['__doc__', '__init__', '__module__', 'do_something']
    Traceback (most recent call last):
      File "bl.py", line 83, in <module>
        print Demo_2.some_string
    AttributeError: class Demo_2 has no attribute 'some_string'


As you can see Class Demo_2 has no attributes result or some_string as 
they are instance variable.
"""

See more about static Class variable Here

Upvotes: 0

Vishnu Upadhyay
Vishnu Upadhyay

Reputation: 5061

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

Upvotes: 10

d-coder
d-coder

Reputation: 13943

Why don't you try initializing the result=[] inside your do_something method something like this ?

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

Upvotes: 1

Related Questions