从多对多关系返回一组随机排序的不同对象
Posted
技术标签:
【中文标题】从多对多关系返回一组随机排序的不同对象【英文标题】:Returning a randomly ordered set of distinct objects from a ManyToMany relationship 【发布时间】:2011-11-06 19:29:53 【问题描述】:我正在使用带有 Postgresql 8.4 的 Django 1.3,并且我有如下模型(删除了不相关的东西):
class Service(models.Model):
name = models.CharField(max_length=80)
class Location(models.Model):
name = models.CharField(max_length=80)
services = models.ManyToManyField(Service, through='LocalService')
class LocalService(models.Model):
location = models.ForeignKey(Location)
service = models.ForeignKey(Service)
我正在尝试获取一组不同的 Service 对象,这些对象按链接的 Location 对象的属性进行过滤,并随机排序。我首先尝试了这个:
Service.objects.filter(location__name__icontains='o').distinct().order_by('?')
...但这会引发此异常:
DatabaseError:对于 SELECT DISTINCT,必须出现 ORDER BY 表达式 在选择列表中
google了一下,发现要在SQL层面实现这种结果,需要将DISTINCT和ORDER BY放在不同的查询级别,即:使用子查询。如果我对一组 DISTINCT 的结果进行子查询,我可以像这样随机排序它们:
SELECT *
FROM (
SELECT DISTINCT s.*
FROM profile_service s
JOIN profile_localservice ls
ON ls.service_id = s.id
JOIN profile_location l
ON ls.location_id = l.id
WHERE l.name LIKE '%o%'
) as temptable
ORDER BY RANDOM()
我是否需要在此 SQL 查询中使用 Manager.raw() 方法来获取我的模型实例集,或者是否有更简单的方法可以从 Django API 中执行此操作?
【问题讨论】:
您是否尝试交换“distinct()”和“order_by()”? @akonsu:是的,我试过了。它导致相同的异常 如果您尝试创建子查询,请使用extra()
@Pannu:我尝试使用extra()
方法的tables
参数。当我简单地指定一个表名时它就可以工作,但是每当我提供一个子查询时,我都会得到一个DatabaseError
异常。即使子查询正在运行,我也知道如何在 SELECT 和 WHERE 子句中使用它,但我不确定如何将它用作模型实例的源。
【参考方案1】:
根据您的确切要求,以下可能会起作用(并且可能比ORDER BY Random()
表现更好)。我不确定 Postgresql,但 mysql 对任何数据集进行随机排序确实很慢。
services = list(Service.objects.filter(location__name__icontains='o').distinct())
random.shuffle(services)
【讨论】:
谢谢@Alex,我想这会实现我所追求的。以上是关于从多对多关系返回一组随机排序的不同对象的主要内容,如果未能解决你的问题,请参考以下文章