2009-12-15 78 views
4

我在用户对象中有一个ManyToManyField,它用于映射用户所关注的用户。我试图展示他们最近关注的人的子集列表。 .order_by()中是否有一个技巧可以让我通过ManyToManyField的ID进行排序?数据在那里,对吗?我如何根据Django中的ManyToManyField的ID进行排序?

# (people the user is following) 
following = models.ManyToManyField(User, related_name="following", blank=True) 

theuser.following.filter(user__is_active=True).order_by("user__id") 

这会给我一个用户列表,他们加入后会按照用户的顺序排列。我希望以下列表的顺序按照用户跟随他们的顺序进行。

+0

有趣/奇怪的问题。 ManyToMany用于执行连接的中间表的id字段很有趣,因为...? – 2009-12-15 03:58:38

+0

请张贴一些代码。 – czarchaic 2009-12-15 06:36:53

+2

@peter我认为该表中的id应显示所建立关系的顺序,以便他可以完成他的“你最近遵循的:”主意。 – 2009-12-15 18:45:05

回答

0

我不确定您是否可以通过常规ManytoManyField来实现此目标。你可以尝试明确定义中间模型。

nb:未经测试的代码!

class Person(models.Model) 
    name = models.CharField(max_length=30) 

class FollowerRelationship(models.Model) 
    follower = models.ForeignKey(Person, related_name = following_set) 
    following = models.ForeignKey(Person, related_name = follower_set) 

然后,您可以在shell中创建以下关系,如下所示。

# Create Person objects 
>>> a = Person(name="Alice") 
>>> a.save() 
>>> b = Person(name="Bob") 
>>> b.save() 
>>> c = Person(name="Chris") 
>>> c.save() 

# Let Alice follow Chris and Bob 
>>> FollowerRelationship.objects.create(follower=a, following=c) 
>>> FollowerRelationship.objects.create(follower=a, following=b) 

您可以创建FollowerRelationship对象爱丽丝是跟随者,通过连接表的id订购的queryset的,用线:

>>> qs = FollowerRelationship.objects.filter(follower=a).order_by('id') 
>>> [fr.following for fr in qs] 

请注意,您通过FollowerRelationship必须循环对象,以获得关系中的'follow'Person

您可能还想看看Django文档中的Extra fields on many-to-many relationships,该文档介绍了如何以多对多关系指定中间模型。

2

我只是找到了一种方法来做到这一点,而无需为关系创建类。它依赖于extra功能,可让您添加更多列以输出。在您的例子看起来会像:

theuser.following.filter(user__is_active=True)\ 
    .extra(select={'creation_seq': 'appname_user_user_following.id'})\ 
    .order_by("creation_seq") 

注意appname_user_user_following是关系表中的Django在幕后创建名称。它是确定性的,你可以通过元机制获得和设置,但它对硬编码来说非常安全。

这里是一个的被盖下创建了假表和列名的SQL的一个例子:

SELECT (appname_user_user_following.id) AS `creation_seq`, `appname_user`.`id` 
FROM `appname_user` INNER JOIN `appname_user_user_following` ON 
(`appname_user`.`id` = `appname_user_user_following`.`user_id`) WHERE 
`appname_user_user_following`.`user_followed_id` = 1 ORDER BY `creation_seq` ASC'; 
+0

这对我有效。你应该把代码放在花括号后面,因为它需要一个字典。 – Archarachne 2015-11-20 08:06:33

+1

完成。谢谢@Archarachne – 2015-11-23 17:03:55

1

实际上(至少在Django 1.10),则不需要使用extra功能而是可以直接按字段排序。只需使用自动创建的表格名称后跟“.id”作为参数order_by。例如。

pizza.toppings.all().order_by('appname_pizza_toppings.id')

article.tags.all().order_by('appname_article_tags.id')

对于这个特殊的问题:

theuser.following.filter(user__is_active=True)\ .order_by("appname_user_user_following.id")

许多其他的解决方案建议创建通过表自定义,并增加一个字段,但如果你只是想通过排序通过表自动生成的id然后这是没有必要的。

相关问题