Best way to optimize queries like this in Django - django

I am trying to lower the amount of queries that my django app is using, but I am a little confused on how to do it.
I would like to get a query set with one hit to the database and then filter items from that set. I have tried a couple of things, but I always get queries for each set.
let's say I want to get all names from my DB, but also separate out the people just named Ted. Both the names and the ted set will be used in the template.
This will give me two sets, one with all names and one with Ted.. but also hits the database twice:
namelist = People.objects.all()
tedList = namelist.filter(name='ted')
Is there a way to filter the first set without hitting the data base again?

tedList = [person for person in namelist if person.name == 'ted']
This will filter the initial QueryList on the client side.

Related

Graphene-Django possible to filter a set?

newly working with GraphQl and wondering is it possible to filter a set in a query? I'm still new to database design as well so could be an issue there.
So I run the below query, managerGwPicks has a field player with is a player object containig their name etc.
This player object contains a set of all the weeks they have played which is a separate table in my database.
So as can be seen in the above image when I display the set it shows all the gameweek data whereas ideally I would like it filtered by the gameweek:21 parameter passed to the managerGwPicks query.
I'm not sure it should be possible as there is no direct link between the managerGwPicks and playergwstats tables but I'd like to be sure that my thinking is correct.
My solution for my front end would be to have two queries, one similar to what I have getting the player information and a second query using the player id and gameweek to query playergwstats to get the player stats for the individual week. Does this sound like a reasonable approach?
It's preferable to avoid query patterns where you have to do multiple back-and-forths between the client and the server. If you can imagine making the link on the client then you can do it directly on the server. If you can go from a managerId and gameweek to a list of players and you can go from players to playergwstats then you can create a join that goes from your two parameters to all the relevant players.
I've covered patterns like this in a series of posts on GraphQL for SQL Developers - look at the join that's used to go from a booking reference to a series of tickets and flights.

Django table or Dict: performance?

I have multiple small key/value tables in Django, and there value never change
ie: 1->"Active", 2->"Down", 3->"Running"....
and multiple times, I do some get by id and other time by name.
So I'm asking, if it's not more optimize to move them all as Dict (global or in models) ?
thank you
Generally django querysets are slower than dicts, so if you want to write model with one field that has these statuses (active, down, running) it's generally better to use dict until there is need for editability.
Anyway I don't understand this kind of question, the performance benefits are not really high until you got ~10k+ records in single QS, and even by then you can cast the whole model to list by using .values_list syntax. Execution will take approximately part of second.
Also if I understand, these values should be anyway in models.CharField with choices field set, rather than set up by fixture in models.ForeignKey.

Django - Where IN with multiple columns/fields

I have a query that needs to fetch from a table that meets two columns requirements exactly. So if I have users table with columns, age and score.
SELECT * FROM users where (age, score) IN ((5,6), (9,12), (22,44)..);
In my web app, I am getting these pairs from an ajax request, and the number could be quite big. How do I construct a query for this in Django?
I am working on Postgres database
One solution I come up with, would be to use django.db.models.Q object and construct exactly same query as you've written:
ques = Q(age=5) & Q(score=6) | Q(age=9) & Q(score=12) ...
User.objects.filter(ques)
This would return the desired queryset, but, I'd be concerned about the size of the iteration performance of the received values (using ajax).
On the other hand, I don't recall better solution for now. If something comes up, would update the answer. Hope, this helps.

Filter on a list of tags

I'm trying to select all the songs in my Django database whose tag is any of those in a given list. There is a Song model, a Tag model, and a SongTag model (for the many to many relationship).
This is my attempt:
taglist = ["cool", "great"]
tags = Tag.objects.filter(name__in=taglist).values_list('id', flat=True)
song_tags = SongTag.objects.filter(tag__in=list(tags))
At this point I'm getting an error:
DatabaseError: MultiQuery does not support keys_only.
What am I getting wrong? If you can suggest a completely different approach to the problem, it would be more than welcome too!
EDIT: I should have mentioned I'm using Django on Google AppEngine with django-nonrel
You shouldn't use m2m relationship with AppEngine. NoSQL databases (and BigTable is one of them) generally don't support JOINs, and programmer is supposed to denormalize the data structure. This is a deliberate design desicion: while your database will contain redundant data, your read queries will be much simpler (no need to combine data from 3 tables), which in turn makes the design of DB server much simpler as well (of course this is made for the sake of optimization and scaling)
In your case you should probably get rid of Tag and SongTag models, and just store the tag in the Song model as a string. I of course assume that Tag model only contains id and name, if Tag in fact contains more data, you should still have Tag model. Song model in that case should contain both tag_id and tag_name. The idea, as I explained above, is to introduce redundancy for the sake of simpler queries
Please, please let the ORM build the query for you:
song_tags = SongTag.objects.filter(tag__name__in = taglist)
You should try to use only one query, so that Django also generates only one query using a join.
Something like this should work:
Song.objects.filter(tags__name__in=taglist)
You may need to change some names from this example (most likely the tags in tags__name__in), see https://docs.djangoproject.com/en/1.3/ref/models/relations/.

How to limit columns returned by Django query?

That seems simple enough, but all Django Queries seems to be 'SELECT *'
How do I build a query returning only a subset of fields ?
In Django 1.1 onwards, you can use defer('col1', 'col2') to exclude columns from the query, or only('col1', 'col2') to only get a specific set of columns. See the documentation.
values does something slightly different - it only gets the columns you specify, but it returns a list of dictionaries rather than a set of model instances.
Append a .values("column1", "column2", ...) to your query
The accepted answer advising defer and only which the docs discourage in most cases.
only use defer() when you cannot, at queryset load time, determine if you will need the extra fields or not. If you are frequently loading and using a particular subset of your data, the best choice you can make is to normalize your models and put the non-loaded data into a separate model (and database table). If the columns must stay in the one table for some reason, create a model with Meta.managed = False (see the managed attribute documentation) containing just the fields you normally need to load and use that where you might otherwise call defer(). This makes your code more explicit to the reader, is slightly faster and consumes a little less memory in the Python process.