Baterson Baterson - 3 months ago 9
Python Question

Understanding VIew evaluation in Django

I build web application with Django REST Framework. There is one simple view, which return reference Information with db fields.

resources.py:


RESOURCES = {
'genres': GenreSerializer(Genre.objects.all(), many=True).data,
'authors': AuthorSerializer(Author.objects.all(), many=True).data,
......
}


class ResourceApiView(views.APIView):

def get(self, request):
params = request.query_params
response_dict = {}
if params:
# Return RESOURSES based on query params
for i in params:
q = RESOURCES.get(i)
if q:
response_dict[i] = q
else:
# Return all RESOURSES
response_dict = RESOURCES
return Response(response_dict,
status=status.HTTP_200_OK
)


It works fine, but when I add new object to one the resources querysets. Nothing happens, it show old queries.

I tried printed
RESOURSES
in my module, it printed once and other get requests don't trigger it.

Then I move
RESOURSES
directly in class
ResourceApiView
and it's behavior same like when
RESOURSES
where in module.

class ResourceApiView(views.APIView):

RESOURCES = {
'genres': GenreSerializer(Genre.objects.all(), many=True).data,
'authors': AuthorSerializer(Author.objects.all(), many=True).data,
......
}

def get(self, request):
...


It work fine only when I put
RESOURSES
in
get
method.

class ResourceApiView(views.APIView):

def get(self, request):
RESOURCES = {
'genres': GenreSerializer(Genre.objects.all(), many=True).data,
'authors': AuthorSerializer(Author.objects.all(), many=True).data,
......
}


But why is it happening? Why I can't evaluate queries from class attributes for each method call?

Answer

this is more related to python than to django. Let's say you hava file lib.py

def say_hello():
    print "hello"

GREETINGS = {
    "hello": say_hello()
}

now go to another python file (or the shell) and just import your lib.py, you'll print "hello" to the console because when you import the file It starts resolving the code inside so it's creating the GREETINGS variable (RESOURCES in your case) and calling the say_hello() method, for you it's executing the query. However python is smart enough that if you import the file again he'll remember that you just imported it before so it wont load the module again, cause it already has the module reference saved.

Your query is beeing executed once when the view was first loaded, and reimporting the view wont make the reference change

The same for placing RESOURCES as a class attribute. The code was executed when the class was imported (again you can test it by creating a class on the lib.py example)

hope this clarifies :) but maybe the docs explains it better https://docs.python.org/2/tutorial/modules.html

Note: I think that the .data on the serializer is actually executing the query. Without it your query and the serializer would just be stored as reference, because the ORM is lazy. Change your RESOURCES to improve the performance of your endpoint because right now if you request one single resource (e.g. 'authors) its still executing ALL the queries ('authors', 'genres', etc)

Comments