12

我在用户对象中有一个 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

4 回答 4

7

事实上(至少在 Django 1.10 中),您不需要使用该extra功能,而是可以直接按字段排序。只需使用通过表名自动创建的后跟“.id”作为 .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 进行排序,那么这不是必需的。

于 2017-02-16T02:16:53.360 回答
6

I just found a way to do this without having to create a class for the relationship. It relies on the extra feature that lets you add additional columns to output. In your example it would look like:

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

Notice that appname_user_user_following is the name of the relationship table Django creates under the covers. It's deterministic and something you can get and set via meta-mechanisms, but it's pretty much safe to hardcode.

Here's an example of the SQL that's being created under the covers with fake table and columns names:

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';
于 2014-08-14T18:23:32.990 回答
4

经测试Django 1.11.10

您不必对关系表名称进行硬编码(如何读取模型实例的数据库表名称?)。

所以@Ry4an Brase 的答案的更新看起来像

recently_followed = '-{}.id'.format(theuser.following.through._meta.db_table)  
theuser.following.filter(user__is_active=True).order_by(recently_followed)
于 2018-03-14T10:32:09.837 回答
0

我不确定您是否可以通过常规ManytoManyField. 您可以尝试显式定义中间模型。

注意:未经测试的代码!

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 文档中多对多关系的额外字段,该文档描述了如何在多对多关系中指定中间模型。

于 2009-12-15T23:28:03.753 回答