When you need just one record — the newest post, the first order, the latest comment — do not use order_by(...)[0] and handle the empty case yourself. Django ships four methods for this: first(), last(), latest(), and earliest(). The first two return None when there is no record; the last two pick the newest or oldest record by a datetime field and raise a clear error when nothing is found.
The Problem
The most familiar way to fetch a single record is to slice a queryset by index: Post.objects.order_by('-created_at')[0]. It works when the table has data, but it throws IndexError the moment the queryset is empty — an error that usually only shows up in production, when a new category has no posts yet or after data has been deleted. Another common mistake: calling latest() without declaring a datetime field, and Django raises ValueError asking you to pass a field name or declare get_latest_by in Meta.
# Error 1: IndexError when the category has no posts yetnewest = Post.objects.filter(category="django").order_by("-created_at")[0]# Error 2: ValueError because the model does not declare get_latest_bynewest = Post.objects.filter(category="django").latest()
The Solution
first() and last() are the safest choice when a record may not exist: they return None instead of raising, so a single if handles the case. first() takes the first record in the queryset’s current order, last() takes the last — for stable results, always call order_by() first instead of relying on the database’s default order.
newest = Post.objects.filter(category="django").order_by("-created_at").first()if newest is None: return render(request, "empty.html")oldest = Post.objects.filter(category="django").order_by("created_at").first()
When you mean “newest by datetime”, latest() and earliest() read more clearly: they take the field name as an argument, or use get_latest_by declared in the model’s Meta. Unlike first(), they raise DoesNotExist when there is no record — the right behavior when the data must exist, because the error surfaces immediately instead of spreading as a None further away.
class Post(models.Model): title = models.CharField(max_length=200) created_at = models.DateTimeField(auto_now_add=True) class Meta: get_latest_by = "created_at"newest = Post.objects.filter(category="django").latest()oldest = Post.objects.filter(category="django").earliest()# Equivalent to: latest("created_at") and earliest("created_at")
Putting It Into Practice
A quick rule for choosing: if the data may be empty — a category page, a new user’s profile page — use first() with a None check; if the data must exist — the newest post on the homepage, the most recent order in a report — use latest() so errors surface early. And declare get_latest_by in Meta as soon as you create a model with a datetime field: that one line keeps every latest() call in the codebase short and consistent.
Related Posts
- Django: Fetch Objects Safely with get_object_or_404 — Skip try/except DoesNotExist in 5 Minutes
- Django: Paginate Lists with Paginator in 5 Minutes, Skip Hand-Written offset/limit
- Django: Group Stats with values() + annotate() — GROUP BY in a Single Query
FAQ
How is first() different from [0]?
[0] raises IndexError when the queryset is empty, while first() returns None. Both fetch only one record from the database (adding LIMIT 1), so performance is equivalent.
Does last() load the whole table?
No. Django reverses the ordering and fetches one record, equivalent to ORDER BY ... DESC LIMIT 1 at the SQL level. But always call order_by() first so you know exactly what “last” means.
How is latest() different from order_by(‘-created_at’).first()?
latest() raises DoesNotExist when there is no record, while first() returns None. latest() also needs a datetime field (as an argument or via get_latest_by), while first() uses the queryset’s current ordering.
Can I use latest() with a field that is not a date?
Yes, Django accepts any ordered field such as a number or a string, but you should only use it with a DateField or DateTimeField; with other fields, the method name becomes misleading.
💬 Have you tried this approach in your own project? If you ran into an error or know a more concise way to do it, leave a comment below — I read every one and will add the best ideas to the post.
Sources
- Django documentation, QuerySet API reference — first() / last(): https://docs.djangoproject.com/en/6.1/ref/models/querysets/#first
- Django documentation, QuerySet API reference — latest() / earliest(): https://docs.djangoproject.com/en/6.1/ref/models/querysets/#latest
- Django documentation, Model Meta options — get_latest_by: https://docs.djangoproject.com/en/6.1/ref/models/options/#get-latest-by
