在我的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
)上执行。
答案 0 :(得分:2)
正如@CarltonGibson所注意到的,queryset
是RandomObject
类的属性。因此它缓存,以后不能更改。因此,如果您想在某些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
。
我希望有所帮助。