class Category(models.Model):
name = models.CharField(max_length=100)
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return self.name
你想要获取一个随机的分类。我们来看下几种替代方法。
最直接的方法是你可以用随机的 order_by
然后获取第一条记录。类似这样:
def get_random():
return Category.objects.order_by("?").first()
注意:order_by('?')
查询可能会性能很差,这取决于你在使用的数据库后端。
INSERT INTO entities_category
(name)
(SELECT Md5(Random() :: text) AS descr
FROM generate_series(1, 1000000));
你不需要理解以上SQL的所有细节,它创建了一百万个数字并使用 md5-s
来生成名称,然后将其插入到数据库中。
现在,你可以得到最大的id,生成一个范围在[1, max_id]中间的随机数,然后获取到数据而不需要给整张表排序(假设表中没有被删除的记录)。
In [1]: from django.db.models import Max
In [2]: from entities.models import Category
In [3]: import random
In [4]: def get_random2():
...: max_id = Category.objects.all().aggregate(max_id=Max("id"))['max_id']
...: pk = random.randint(1, max_id)
...: return Category.objects.get(pk=pk)
...:
In [5]: get_random2()
Out[5]: <Category: e2c3a10d3e9c46788833c4ece2a418e2>
In [6]: get_random2()
Out[6]: <Category: f164ad0c5bc8300b469d1c428a514cc1>
如果你的模型中有删除的纪录,你可稍微调整下函数,循环直到你获取到有效的 Category
。
In [8]: def get_random3():
...: max_id = Category.objects.all().aggregate(max_id=Max("id"))['max_id']
...: while True:
...: pk = random.randint(1, max_id)
...: category = Category.objects.filter(pk=pk).first()
...: if category:
...: return category
...:
In [9]: get_random3()
Out[9]: <Category: 334aa9926bd65dc0f9dd4fc86ce42e75>
In [10]: get_random3()
Out[10]: <Category: 4092762909c2c034e90c3d2eb5a73447>
while True:
循环会迅速返回,除非你的模型有大量的删除。我们使用 timeit
来看看差别。
In [14]: timeit.timeit(get_random3, number=100)
Out[14]: 0.20055226399563253
In [15]: timeit.timeit(get_random, number=100)
Out[15]: 56.92513192095794
get_random3
大概比 get_random
快了283倍。 get_random
是最通用的方式,除非你更改了Django生成id的默认方式–自增整数,或者有过太多的删除记录, get_random3
将会生效。