django how to get the 0th item from a possibly empty list
I have a simple blog app with the model "Post". If I delete all the entries in the Post model I get an error when I try reference the first item in the post list ordered by date, which I did like this:
latest_post = Post.objects.order_by('-date_created')[0]
The error is: IndexError: list index out of range
As a fix, I now get the item like this:
all_posts = Post.objects.order_by('-date_created')
latest_post = ()
if (all_posts):
latest_post = all_posts[0]
This works if there are no items in my model "Post", and no exception is thrown. However to me this seems like too much code to do something fairly simple. I assume there is a better way to do this 开发者_开发知识库using the django QuerySet API, but can't find anything in the documentation.
Any ideas?
EDIT: Strangely, this throws no error when there are no items in the Post model:
latest_post_list = Post.objects.all().order_by('-date_created')[1:10]
Nothing strange about that, it's completely expected behavior. An empty list (or queryset specifically in this case) evaluates to False so you never index into the queryset. While if you try to index into an empty list (like you do with the first approach) it will throw an IndexError.
What you've written will work, but it's not the best imo. A better way to write this would be like so
try:
latest_post = Post.objects.order_by('-date_created')[0]
except IndexError:
latest_post = None
This is a more pythonic way of writing it and is easier to read and understand what you're trying to do.
Or even better
try:
latest_post = Post.objects.latest('date_created')
except Post.DoesNotExist:
latest_post = None
Notice in this second example that it uses the latest() queryset method. Also note that the argument is simply the fieldname and not -fieldname. Also you can even specify in your models Meta class get_latest_by = 'date_created'
and then the line simply becomes latest_post = Post.objects.latest()
without even needing to specify the fieldname argument
A simple python fix would be to instead use
latest_post = Post.objects.order_by('-date_created')[0:1]
latest_post = Post.objects.order_by('-date_created')[:1]
if latest_post:
latest_post = latest_post[0]
This will not throw an exception and you can still check for a empty list condition on latest_post.
Your problem arises from using an absolute index IE: [0] which may or may not exist. By using a slice [:1] you are saying you want a list with the first item in the list if it exists... if it doesn't exist you will simply get an empty list.
精彩评论