Tim*_*man 9 python django sql-order-by django-models 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")
Run Code Online (Sandbox Code Playgroud)
这将为我提供用户所关注的用户列表,但在他们加入时按订单排序.我希望以下列表的顺序按用户跟随它们的顺序排列.
我刚刚找到了一种无需为关系创建类的方法。它依赖于extra允许您向输出添加其他列的功能。在您的示例中,它看起来像:
theuser.following.filter(user__is_active=True)\
.extra(select={'creation_seq': 'appname_user_user_following.id'})\
.order_by("creation_seq")
Run Code Online (Sandbox Code Playgroud)
请注意,这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';
Run Code Online (Sandbox Code Playgroud)
实际上(至少在 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 进行排序,则没有必要。
测试用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)
Run Code Online (Sandbox Code Playgroud)
我不确定你是否可以通过常规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)
Run Code Online (Sandbox Code Playgroud)
然后,您可以在 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)
Run Code Online (Sandbox Code Playgroud)
您可以创建一个FollowerRelationship对象查询集,其中 Alice 是关注者,按连接表的 id 排序,使用以下行:
>>> qs = FollowerRelationship.objects.filter(follower=a).order_by('id')
>>> [fr.following for fr in qs]
Run Code Online (Sandbox Code Playgroud)
请注意,您必须循环遍历对象,才能获得关系中的FollowerRelationship“关注” 。Person
您可能还想查看Django 文档中多对多关系的额外字段,它描述了如何在多对多关系中指定中间模型。
| 归档时间: |
|
| 查看次数: |
1754 次 |
| 最近记录: |