Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django REST Framework: overriding get_queryset() sometimes returns a doubled queryset

I made a little endpoint, adapting DRF ReadOnlyModelViewSet, defined as follows:

class MyApi(viewsets.ReadOnlyModelViewSet):

    queryset = []
    serializer_class = MySerializer

    def get_queryset(self):
        print 'Debug: I am starting...\n\n\n\n'
        # do a lot of things filtering data from Django models by some information on neo4j and saving data in the queryset...
        return self.queryset

When I call MyApi via URL, it returns results without any problems, but sometimes it returns doubled result!! It's very strange...It's not a systematic error but happens only sometimes.

I use the line print 'Debug: I am starting...\n\n\n\n' in Apache log to investigate the problem. When that doubling happens, I read in the log:

Debug: I am starting...




Debug: I am starting...

It seems like get_queryset is called more than one time. It's very strange. I didn't report the detail of the logic inside that method, I think the problem is elsewhere or that is a bug...How can I solve?

like image 963
floatingpurr Avatar asked Aug 04 '15 12:08

floatingpurr


3 Answers

You have defined queryset as a class attribute.

class MyApi(viewsets.ReadOnlyModelViewSet):
    queryset = []

That means that each time you append to self.queryset, you are appending to the same list. Your get_queryset method is only called once, but self.queryset already has entries in it at the beginning of the method. To see the problem in action, print self.queryset in your method at the very beginning, before you change it.

You would be better to do something like:

class MyApi(viewsets.ReadOnlyModelViewSet):
    queryset = None  # this line is probably not required, but some code checking tools like it to be defined.

    def get_queryset(self):
        self.queryset = []
        ...
        return self.queryset
like image 141
Alasdair Avatar answered Nov 03 '22 00:11

Alasdair


If you are using a custom permission like DjangoModelPermissions. You need to check that the get_queryset method of your View is not being called.

For example, DjangoModelPermissions call this method here:

if hasattr(view, 'get_queryset'):
    queryset = view.get_queryset()
else:
    queryset = getattr(view, 'queryset', None)

If I use this permission just as it is. The method get_queryset will be called twice.

So I changed it to just this:

queryset = getattr(view, 'queryset', None)

As a result it is just called once. Hope this helps.

like image 4
oskargicast Avatar answered Nov 03 '22 02:11

oskargicast


You are defining queryset = [] as class attributes and class attributes are "shared by all instances". So, if you python process append some data to your queryset attribute, the subsequent view instances would have that data, only if they are created by the same process.

like image 1
levi Avatar answered Nov 03 '22 01:11

levi