Adding values to Django QuerySet
Asked Answered
P

1

5

Is there any way to append a non-Django supplied value to a query?

For instance, to find out if a store closed, I may run a function called get_closed_stores() which returns a list of closed stores.

Stores Closed

[00090, 00240, 00306, 00438, 03005, 05524]

Great, now we have store numbers for stores that are closed. Lets get those actual store objects.

Query

Store.objects.filter(
store_number__in=[00090, 00240, 00306, 00438, 03005, 05524]
)

We now have the QuerySet, but we have absolutely no way to detect when the store closed, because the database doesn't contain any information about emergency closings, but Sharepoint does. So back at get_closed_stores() we can return the Date Closed alongside the store number so our Closed Stores List (dictionary) would look more like below:

Store List with Dates

{
    [00090, '1/28/19 5:00PM'], 
    [00240,'1/28/19 5:00PM'], 
    [00306, '1/28/19 5:00PM'], 
    [00438,'1/28/19 5:00PM'], 
    [03005,'1/28/19 5:00PM'], 
    [05524, '1/28/19 5:00PM']
}

Now that the dates are with my store numbers, I can add this to my Queryset (ideally) and access it from my front end.

So annotate() would be ideal here if I were working with anything Django ORM related, but when it comes to "injecting" external data, what is it I'm looking for?

I can absolutely just make the call for each store from JS on my front end but I would rather not if I can get around it

Prelatism answered 29/1, 2019 at 0:48 Comment(0)
P
7

A QuerySet in itself isn't anything magical or special, in the end its still a dictionary, so I had the random notion to append to the dictionary the way I typically would, and it worked.

My function is now returning a dictionary:

{ "store_number": "close_date" }

My view takes this dictionary and uses the keys (store numbers) to Query the database and then appends the store's close date as store.close_date by simply saying:

store.close_date = store_list[store_number]

This is likely to change, but I want to keep it close to the original question to make it readable for future readers. Below is my view.

@login_required
def store_closures(request):
    store_list = get_closed_stores()
    store_nums = store_list.keys()
    closed_stores = Store.objects.filter(store_number__in=store_nums)
    for store in closed_stores:
        store.close_date = store_list["{:05d}".format(store.store_number)]
    return render(request, 'all_store_closures.html', {'closed_stores':closed_stores})

So if you want to add a non Django value to a queryset, you can just use the standard method of appending to a dictionary.

for obj in query:
    obj.desired_name = 'desired_value'

Which is, of course, accessed using {{ object.desired_name }} from your template.

Prelatism answered 29/1, 2019 at 2:5 Comment(2)
FWIW, this is fine if you want this to evaluate the queryset (by looping through it) however if you want to only make 1 query to the DB and get the same information you can use annotation to achieve the same results without needing to evaluate the queryset. Using annotation is more powerful than looping through the queryset which can lead to many and/or duplicate hits on the DB (N+1) when you don't want that.Niobous
@Niobous doesn't the queryset evaluated anyway when being displayed in the template?Frenchy

© 2022 - 2024 — McMap. All rights reserved.