我在用户对象中有一个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")
这将为我提供用户所关注的用户列表,但在他们加入时按订单排序。我希望以下列表的顺序符合用户跟随它们的顺序。
答案 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,其中描述了如何以多对多关系指定中间模型。