简体   繁体   中英

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?

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

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.

Had the same problem and just ran a trackback Turns out that the second run is the rest_framework's rendering files calling view.get_queryset().

Try calling it from the command line and then checking the results.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM