Django:如何对来自不同模型的实例进行排序?

4

用户可以在我们的网站上上传三种不同类型的内容:图片、视频、音频。以下是每种类型的模型:

class ImageItem(models.Model):
    user = models.ForeignKey(User)
    upload_date = models.DateTimeField(auto_now_add=True)
    image = models.ImageField(upload_to=img_get_file_path)
    title = models.CharFiled(max_length=1000,
                             blank=True)

class VideoItem(models.Model):
    user = models.ForeignKey(User)
    upload_date = models.DateTimeField(auto_now_add=True)
    video = models.FileField(upload_to=vid_get_file_path)
    title = models.CharFiled(max_length=1000,
                             blank=True)

class AudioItem(models.Model):
    user = models.ForeignKey(User)
    upload_date = models.DateTimeField(auto_now_add=True)
    audio = models.FileField(upload_to=aud_get_file_path)
    title = models.CharFiled(max_length=1000,
                             blank=True)

我有一个名为library.html的页面,它按照最近上传的顺序呈现用户上传的所有项目(它会显示每个实例的titleupload_date,并在左侧放置一个小图标,表示它是什么类型的项目)。
假设需要三个单独的查询,如何合并这三个查询集?如何确保它们按最近上传的顺序排序?

2
看看这个答案 :) 排序不应该太难。 - Frantz Romain
3个回答

5
作为替代方案,您可以使用多表继承,并将共同属性因素化为超类模型。然后在超类模型上只需order_by上传日期即可。第三方应用程序django-model-utils提供了一个名为Inheritance Manager的自定义管理器,可让您自动向下转换到查询中的子类模型。
from model_utils.managers import InheritanceManager

class MediaItem(models.Model):
    objects = InheritanceManager()

    user = models.ForeignKey(User)
    upload_date = models.DateTimeField(auto_now_add=True)
    title = models.CharFiled(max_length=1000,
                             blank=True)

class ImageItem(MediaItem):
    image = models.ImageField(upload_to=img_get_file_path)

class VideoItem(MediaItem):
    video = models.FileField(upload_to=vid_get_file_path)

class AudioItem(MediaItem):
    audio = models.FileField(upload_to=aud_get_file_path)

那么,您的查询只是:

MediaItem.objects.all().order_by('upload_date').select_subclasses()

这样,您只需使用一个查询(带有3个连接),即可获得所需的内容。此外,您的数据规范化得更好,并且支持各种更复杂的查询和分页也相对简单。
即使您不使用此方法,我仍然建议使用抽象基类继承来概念上规范化您的数据模型,尽管您无法获得数据库端和ORM方面的优势。

1
这绝对是正确的做法。如果将来需要更多的媒体类型,它会更容易维护。此外,它具有良好面向对象编程的可重用性属性。 - CrazyCasta
向 Nasmon 大声喊话,感谢他发现了一个错别字。他的尝试编辑似乎被第三方管理员拒绝了,但我想给予应有的赞扬,因为我无法弄清如何覆盖并接受编辑。 - acjay

0

attrgetter 可以用于提取你希望根据其进行排序的对象属性。

from operator import attrgetter

results = []
results.extend(list(AudioItem.objects.filter(...)))
results.extend(list(VideoItem.objects.filter(...)))
results.extend(list(ImageItem.objects.filter(...))
results.sort(key=attrgetter("upload_date")

0
参考这个问题,这是我使用的确切解决方案。受monkut的答案以及Frantzdy评论中他链接的最佳答案的影响(谢谢大家)。
from itertools import chain
from operator import attrgetter

images = ImageItem.objects.filter(user=user)
video = VideoItem.objects.filter(user=user)
audio = AudioItem.objects.filter(user=user)
result_list = sorted(chain(images, video, audio),
                     key=attrgetter('upload_date'),
                     reverse=True)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接