Django form field queryset optimization - python

I have a form like this on Django app:
class CustomForm(forms.Form):
field1 = forms.ModelChoiceField(queryset=ModelA.objects.filter(type=A))
field2 = forms.ModelChoiceField(queryset=ModelA.objects.filter(type=B))
The Debug Toolbar tells me there are two duplicates querys on ModelA but the filter conditions it's different. Is this a bug?. Also I was wondering if there is a way to optimize this case and make only one query
Thanks!

ModelA.objects.filter(type=A) and ModelA.objects.filter(type=B) are two separate querysets, so require two queries.
In theory, you could do
ModelA.objects.filter(type__in=[A, B])
Which would get all objects where type=A or type=B. You could then filter the list in Python. However, this wouldn't necessarily perform any better. You wouldn't be able to use the ModelChoiceField any more, so your code would be more complicated.

Related

How does django take queryset without database hitting?

There are so many answers and articles to say queryset in django is lazy, it isn't evaluated until you actually do something with queryset.
My question is how is it possible? How does the methods, filter(), all() or order_by() etc, work not knowing what data the objects have?
I assume that hitting a database and knowing data in model objects is different. But, it doesn't make sense for me.
Cheers!
queryset aggragate all filters, excludes annotates and somethins like that and when you do something with this queryset, django generate query (from filters etc. do sql query) to database and after that do qyery do database

Query proformance on GenericForeignKey Django

I have optimized the query below the best I can.
message = Message.objects.defer('gateway', 'batch', 'content_type', 'sender',
'reply_callback')\
.select_related().get(pk=message_id)
However, the model has a field called billee (see below)
billee = generic.GenericForeignKey()
I don't seem to be able to use select_related or defer on this field, maybe because its a GenericForeignKey. Can someone explain why and then give me an example of how to achieve this?
select_related() can't prefetch generic relations (it works only with ForeignKey and OneToOneField), so You may need to write a raw SQL query if You really want to reduce this one additional query.
In case of fetching many messages at once You may use prefetch_related() which can follow generic relations (but still makes an additional query).

Queryset-like filtering of object collection in Django

I'm looking for a way to easily filter from a collection of Model objects without hitting the database each time. By definition, QuerySets are lazy and always will hit the DB. So I am wondering if there is anything existing that can do this. If not, perhaps its a good library to create.
For example:
all_records = object_set(Record.objects.filter(company=user.company))
object_set being a hypothetical function which would gather all of the objects in a QuerySet as static data. The result would be an "object manager" instance that could have filters run against it similar to QuerySet filters. This would be particularly useful in storing creating, updating, and deleting objects based on data from multidimensional lists of data.
for row in data:
for col in row:
# this would not hit the DB. Only filter within the "object_set" in memory.
all_records.filter(date=col.date, type=col.type, creator=col.user)
I realize I may be trying to solve this the wrong way, but regardless, I think this would be a great tool to have in Django. Does anyone know of an existing library or functionality within Django that would solve this problem? Thanks in advance!
I think the QuerySet's select_related method is what you want:
https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-related
Please, check out the managers.py in the following project: django-model-utils/.../managers.py
It should show you how he implemented the queryset
def get_query_set(self):
qs = super(QueryManager, self).get_query_set().filter(self._q)
if self._order_by is not None:
return qs.order_by(*self._order_by)
return qs
If long datasets is your motivation for this question use Redis cache in your Django project.
http://unfoldthat.com/2011/09/14/try-redis-instead.html

Django GenericForeignKey lookup for a given model

I use a voting app (django-ratings if that makes any difference) which uses django's GenericForeignKey, has a ForeignKey to User, and several other fields like date of latest change.
I'd like to get all the objects of one content type, that a single user voted for ordered by date of latest change. As far as I understand - all the info can be found in a single table (except the content_type which can be prefetched/cached). Unfortunately django still makes an extra query each time I request a content_object.
So the question is - how do I get all the votes on a given model, by a given user, with related objects and given ordering with minimum database hits?
Edit: Right now I'm using 2 queries - first selecting all the votes, getting all the objects I need, filtering by .filter(pk__in=obj_ids) and finally populating them to votes objects. But it seems that a reverse generic relation can help solve the problem
Have you checked out select_related()? That may help.
Returns a QuerySet that will automatically "follow" foreign-key relationships, selecting that additional related-object data when it executes its query. This is a performance booster which results in (sometimes much) larger queries but means later use of foreign-key relationships won't require database queries.
https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-related
Well right now we're using prefetch_related() from django 1.4 on a GenericRelation. It still uses 2 queries, but has a very intuitive interface.
From looking at the models.py of the django-ratings app, I think you would have to do user.votes.filter(content_type__model=Model._meta.module_name).order_by("date_changed") (assuming the model you want to filter by is Model) to get all the Vote objects. For the related objects, loop through the queryset getting content_object on each item. IMHO, this would result in the least DB queries.

Django filter against Multiple Item QuerySets

I have two Model's which are related with a ForeignKey field.
Let's call these objects Event and EventRegistration.
I can easily, for example, do this:
EventRegistration.objects.filter(event=Event.objects.get(name="Some Event"))
But, I cannot do something like this:
EventRegistration.objects.filter(event=Event.objects.all())
I know this is a contrived example, but is there a way to filter against whole QuerySets in a similar way to the second line of code?
EventRegistration.objects.filter(event__in=Event.objects.all())

Categories