我如何按Django中的ManyToManyField的id排序?

时间:2009-12-15 03:25:12

标签: python django django-models sql-order-by manytomanyfield

我在用户对象中有一个ManyToManyField,它用于映射用户关注的用户。我正在尝试显示他们最近关注的人的子集列表。在.order_by()中是否有一个技巧可以让我按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")

这将为我提供用户所关注的用户列表,但在他们加入时按订单排序。我希望以下列表的顺序符合用户跟随它们的顺序。

4 个答案:

答案 0 :(得分:4)

我刚刚找到了一种方法,无需为关系创建一个类。它依赖于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';

答案 1 :(得分:3)

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

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进行排序,那么这不是必需的。

答案 2 :(得分:1)

使用Django 1.11.10进行测试。

您不必对关系表名称(How to read the database table name of a Model instance?)进行硬编码。

所以关于@ Ry4an Brase答案的更新可能看起来像

recently_followed = '-{}.id'.format(theuser.following.through._meta.db_table)  
theuser.following.filter(user__is_active=True).order_by(recently_followed)

答案 3 :(得分: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个对象的查询集,其中Alice是关注者,按连接表的id排序,并带有以下行:

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

请注意,您必须遍历FollowerRelationship个对象,才能在关系中获得“跟随”Person

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