How to clear ordering when using .first() in django

Viewed 978

I have a query in database as follows. Whenever I try to do a .first() on the query, The equivalent query that gets run in the database is as follows

SELECT *  FROM “user" WHERE UPPER("user"."email"::text) = UPPER(%s) **ORDER BY** "registration_user"."id" ASC LIMIT 1

I want to get rid of the order by clause as it interferes with indexes being applied correctly in the db and is also a costly operation. How can I refactor the code below?

users = User.objects.filter(email__iexact=email)
users.query.**clear_ordering**(True)
if users.count() > 0 :
    return users.first()
1 Answers

If no ordering is specified, that would mean that two calls with .first() can return a different element, and non-determinism often results in a lot of problems.

The ORDER BY pk is added by the .first() [Django-doc] call, so it is not part of your query at all. If the queryset has no ordering, then .first() will add an ordering by pk (primary key), as is described in the documentation:

first()

Returns the first object matched by the queryset, or None if there is no matching object. If the QuerySet has no ordering defined, then the queryset is automatically ordered by the primary key. This can affect aggregation results as described in Interaction with default ordering or order_by().

If you really do not want an ordering, you can subscript the queryset:

users = User.objects.filter(email__iexact=email)
if users.exists():
    return users[0]

But that does not look like a very good idea. If no order is specified, then the database can return any record that matches the filtering condition, and it can thus return a different record each query.

Related