Reputation: 6238
Users can upload three different types of content onto our site: image, video, audio. Here are the models for each type:
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)
I have a page called library.html
, which renders all the items that a user has uploaded, in order from most recently uploaded to oldest uploads (it displays the title
and upload_date
of each instance, and puts a little icon on the left symbolizing what kind of item it is).
Assuming it requires three separate queries, how can I merge the three querysets? How can I make sure they are in order from most recently uploaded?
Upvotes: 4
Views: 2749
Reputation: 36491
As an alternative, you can use multi-table inheritance and factor common attributes into a superclass model. Then you just order_by
upload date on the superclass model. The third-party app django-model-utils provides a custom manager called Inheritance manager that lets you automatically downcast to the subclass models in your query.
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)
Then, your query is just:
MediaItem.objects.all().order_by('upload_date').select_subclasses()
This way, you get what you want with one just query (with 3 joins). Plus, your data is better normalized, and it's fairly simple to support all sorts more complicated queries, as well as pagination.
Even if you don't go for that, I'd still use abstract base class inheritance to conceptually normalize your data model, even though you don't get the database-side and ORM benefits.
Upvotes: 5
Reputation: 6238
Referencing the question, this is the exact solution I used. Influenced by monkut's answer and the top answer from Frantzdy's link in his comment (thanks guys).
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)
Upvotes: 1
Reputation: 43832
attrgetter
can be used to pull out attributes of objects that you may want to key a sort by.
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")
Upvotes: 0