Django - 根据模板中用户定义的顺序对对象进行排序

时间:2013-08-13 14:46:44

标签: django django-models django-templates

我希望用户能够使用javascript在表格中订购对象列表。然后,在django函数中,我想基于相同的顺序对这些对象进行排序,而不是基于属性。

有可能吗?我正在考虑将pk的列表从模板传递到视图,然后根据此列表对对象进行排序,但我还没有找到方法来实现它。

enter image description here

3 个答案:

答案 0 :(得分:2)

我认为查询集不可能。请尝试以下方法:

pk_list = [2, 1, 3, 4]
pk2obj = {obj.pk: obj for obj in Model.objects.all()}
objects_ordered = [pk2obj[pk] for pk in pk_list]

pkg2obj是pk和模型实例对象之间的映射。为了制作字典,我使用了dictionary comprehension

如果要省略已删除的对象:

objects_ordered = [pk2obj[pk] for pk in pk_list if pk in pk2obj]

否则,如果您要使用默认值(以下代码中的None)替换已删除的对象:

objects_ordered = [pk2obj.get(pk, None) for pk in pk_list]

答案 1 :(得分:1)

我之前必须解决这个问题。

如果您希望用户能够将其重新排序为用户定义的顺序,您可以轻松定义一个字段来存储此订单。

正如您所说,最初,您可以根据idupload_date DateTimeField按顺序提供服务。但您也可以在模型中使用名为positionorder的{​​{3}}来表示用户定义的顺序。

class MediaItem(models.Model):
    user = models.ForeignKey(User)
    upload_date = models.DateTimeField(auto_now_add = True)
    position = models.PositiveIntegerField()

每当用户更改前端的顺序时,JS就可以将新订单作为对象数组发送(即new_order = [{"pk":3, "position":1}, {"pk":1, "position":2}, {"pk":2, "position":3}])。该视图可以按pk查找每个实例,并更改position

for obj in new_order:
    media_item = MediaItem.objects.get(pk=obj['pk'])
    media_item.position = obj['position']
    media_item.save()

然后始终使用

进行查询
objects_ordered.objects.order_by('position')

这就是我们设法做到的方式。如果您对此方法有更具体的问题,请随时在评论中提问。

修改

如果同一个对象可以是许多不同组或列表的成员,并且您希望在该列表中存储成员资格的位置,则可以使用PositiveIntegerField来实现此目的。当您需要存储与两个相关对象之间的关系相关的数据时,直通模型很有用。除了上面显示的MediaItem类之外,这是您的其他模型的样子:

class Album(models.Model):
    media_items = models.ManyToManyField(MediaItem,
                                         related_name = 'album_media_items',
                                         through = 'Membership')

class Membership(models.Model):
    album = models.ForeignKey(Album,
                              related_name = 'album')
    media_item = models.ForeignKey(MediaItem,
                                   related_name = 'media_item')
    date = models.DateTimeField(auto_now_add = True)
    position = models.PositiveIntegerField()

然后,您可以查询Membership个实例,而不是MediaItem个实例。

# get id of list, or album...
alb = Album.objects.get(pk=id_of_album)
media_items = Membership.objects.filter(album=alb).order_by('position')
for item in media_items:
    # return the items, or do whatever...
    # keep in mind they are now in the user-defined order

答案 2 :(得分:1)

你可以这样做:

pk_list = [1,5,3,9]

foo = Foo.objects.filter(id__in=pk_list)

#Order your QuerySet in base of your pk_list using Lambda

order_foo = sorted(foo, key = lambda:x , pk_list.index(x.pk))