Ivan Semochkin
Ivan Semochkin

Reputation: 8897

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?

Upvotes: 1

Views: 92

Answers (1)

pleasedontbelong
pleasedontbelong

Reputation: 20102

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)

Upvotes: 2

Related Questions