使用django-rest-framework获取模型的随机对象

时间:2013-12-11 14:49:08

标签: django random django-rest-framework

在我的Django项目中,我需要提供一个视图,使用django-rest-framework从模型中获取随机对象。我有这个ListAPIView:

class RandomObject(generics.ListAPIView):
   queryset = MyModel.objects.all().order_by('?')[:1]
   serializer_class = MyModelSerializer
   ...

它工作正常但order_by('?')在大数据库上启动时需要花费大量时间。所以我决定随机使用Python。

import random

def pick_random_object():
   return random.randrange(1, MyModel.objects.all().count() + 1)

class RandomObject(generics.ListAPIView):
   queryset = MyModel.objects.all().filter(id = pick_random_object())
   ...

我试图使用它时发现了一件奇怪的事情。我启动了Django开发服务器并发送了一些GET请求,但我对所有请求都有完全相同的对象。当dev服务器重新启动并发送另一组请求时,我得到另一个对象,但对于所有请求仍然完全相同 - 即使首先使用random.seed()。同时,当我试图通过REST而不是通过python manage.py shell获取随机对象时,每次调用pick_random_object()时都会得到随机对象。

所以当使用shell时一切看起来都很好,使用REST时行为很奇怪,我不知道出了什么问题。

所有内容都在Django开发服务器(python manage.py runserver)上执行。

2 个答案:

答案 0 :(得分:2)

正如@CarltonGibson所注意到的,querysetRandomObject类的属性。因此它缓存,以后不能更改。因此,如果您想在某些APIView中创建一些可更改的查询集(例如在每个请求中获取随机对象),则必须覆盖get_queryset()方法。而不是

class RandomObject(generics.ListAPIView):
   queryset = MyModel.objects.all().filter(id = pick_random_object())
   ...

你应该这样写:

class RandomObject(generics.ListAPIView):
   #queryset = MyModel.objects.all().filter(id = pick_random_object())
   def get_queryset(self):
      return MyModel.objects.all().filter(id = pick_random_object())

此处pick_random_object()是一种从模型中获取随机id的方法。

答案 1 :(得分:1)

由于它是类的一个属性,因此当加载类时,即启动开发服务器时,您的查询集将获得evaluated and cached

我会尝试提取主键列表using values_list() - flat=True示例完全符合您的需要。 Ideally cache that。随机选择一个主键,然后在需要时将其用于get()实际对象。

那么,怎么样?

我在视图上定义了一个方法。如果忘记了缓存,实现可能会这样:

# Lets use this...
from random import choice

def random_MyModel(self):
    """Method of RandomObject to pick random MyModel"""
    pks =  MyModel.objects.values_list('pk', flat=True).order_by('id')
    random_pk = choice(pks)
    return MyModel.objects.get(pk=random_pk)

然后,您可能希望在此处缓存第一个查找。上面链接的缓存文档解释了如何做到这一点。如果您确实将结果外观缓存到db.models signals以了解何时无效 - 我想您post_save,检查created标记和post_delete

我希望有所帮助。