Django:如何从不同模型获取有序模型实例列表?

4 投票
3 回答
2698 浏览
提问于 2025-04-17 14:24

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

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,并在左边放一个小图标,表示这是什么类型的项目)。

假设需要三个单独的查询,我该如何合并这三个查询结果?我怎么才能确保它们是按最近上传的顺序排列的呢?

3 个回答

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")
5

作为一种替代方案,你可以使用多表继承,把共同的属性放到一个父类模型里。这样,你只需要在父类模型上用order_by来排序上传日期。还有一个第三方应用django-model-utils提供了一个叫做继承管理器的自定义管理器,可以让你在查询时自动转换为子类模型。

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

关于这个问题,这是我使用的确切解决方案。受到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)

撰写回答