Mr Singh
Mr Singh

Reputation: 4220

How to sort Django QuerySet output by date?

I have data like this:

Data Created by this query:

data = Post.objects.filter(post_by=UserID).
       values_list('posted_date_time','post_id')
       .union(post_wishlist.objects.filter(user_id=UserID)
       .values_list('added_date_time', 'post_id'))

Can i make it better query where it provide shorted data according to date.

Output

<QuerySet [(datetime.datetime(2019, 6, 14, 20, 4, 58, 104805, tzinfo=<UTC>), UUID('b15be3c1-3f70-4ccb-af08-dba385f883a1')), 
          (datetime.datetime(2019, 6, 12, 18, 42, 38, 675120, tzinfo=<UTC>), UUID('f2ea2ad0-f228-43d7-823a-c824a041feb2')), 
          (datetime.datetime(2019, 6, 12, 17, 46, 38, 479890, tzinfo=<UTC>), UUID('16c66e9b-0cbf-4b6d-b848-78cf771f522c')),
          (datetime.datetime(2019, 6, 21, 20, 17, 15, 785171, tzinfo=<UTC>), UUID ('a169afcf-267b-4212-97e5-6221595ab107')),
          (datetime.datetime(2019, 6, 15, 7, 33, 34, 136331, tzinfo=<UTC>), UUID('9aac6b06-6622-4587-9956-5b517aaa11e8')),
          (datetime.datetime(2019, 6, 18, 16, 11, 49, 134458, tzinfo=<UTC>), UUID('00271b56-9ff7-4f9d-b9c0-2592ca9436d2')), 
          (datetime.datetime(2019, 6, 21, 21, 3, 53, 528261, tzinfo=<UTC>), UUID('df0d8905-5377-4b8d-99d9-eba644273eaa')),
          (datetime.datetime(2019, 6, 21, 21, 4, 6, 256957, tzinfo=<UTC>), UUID('c339d797-f37d-48ff-94a6-e6d1510e23cc')), 
          (datetime.datetime(2019, 6, 18, 17, 10, 18, 388505, tzinfo=<UTC>), UUID('00271b56-9ff7-4f9d-b9c0-2592ca9436d2'))]>

In the QuerySet i've multiple datetime instance with UUID,

I created this data using 2 different model and both model have different datetime field name, so i think we can't use CHAIN.

Here I want to sort according to datetime

Many Thanks in advance

Upvotes: 0

Views: 3081

Answers (1)

Resley Rodrigues
Resley Rodrigues

Reputation: 2288

If it's a single model, you can always go for order_by which is the best approach.

class ModelA(models.Model):
    timestamp = models.DateTimeField(default=timezone.now)

ModelA.objects.order_by("timestamp")

If you have multiple models, that have similar data (not necessarily fields), you can still use order_by.

class ModelB(models.Model):
    created = models.DateTimeField(default=timezone.now)
    title = models.CharField(max_length=32)


ModelA.objects.values("timestamp").union(
    ModelB.objects.annotate(timestamp=F("created")).values("timestamp")
).order_by("timestamp").values("timestamp")

It's important that the number of fields in both queries is exactly the same, and corresponding fields in the queries are of the same data type. (I might have used .values() too many times here. I can't recall the syntax at the top of my head.)

This, of course, is not as readable as sorting it in python.

data_a = ModelA.objects.values("timestamp")
data_b = ModelB.objects.annotate(timestamp=F("created")).values("timestamp")

final_data = sorted(data_a + data_b, key=lambda x: x["timestamp"])

Notice that in both cases, I've annotated and added a field called timestamp in the second model to match the name in the first. It just makes things easier.

The order_by has two advantages over the python sorted

  1. It's much faster in most cases as it happens at the DB which is optimized to handle such operations.
  2. It allows you to continue doing query manipulation. For example, if you want the lastest 10 results, you can .order_by("-timestamp")[10], but with Python, you would have to fetch all the data and then discard most of it. This can be super expensive and wasteful when you're dealing with large data sets.

Upvotes: 2

Related Questions