Opened 6 years ago

Closed 4 years ago

#11352 closed New feature (wontfix)

get_object/list_or_none methods

Reported by: cpharmston Owned by: nobody
Component: Core (Other) Version: master
Severity: Normal Keywords:
Cc: Triage Stage: Design decision needed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


Hey all,

First time contributor (not just to Django, but to any open source project), so go easy on me.

Several times I've found myself wanting for a get_list_or_none() shortcut method. get_list_or_404 is nice, but there are some instances (search results, for example) where returning an empty QuerySet makes much more sense. Attached is a patch adding functional get_list_or_404 and get_object_or_404 methods to django.shortcuts. I am aware that in #2659 Adrian rejected get_object_or_404 as scope creep, but since that time objects.none() has been introduced, which would render these methods much more useful. Feel free to set it as wontfix if you still think it's scope creep, but these are certainly useful methods for me, and I'm sure they would be for others as well.

I have not run unit tests on this; it seems to me that it would make more sense to get community buy-in on the necessity for these methods first.

Feedback welcome. Thanks all!

Attachments (3)

object_list_404.diff (1.7 KB) - added by cpharmston 6 years ago.
Adds get_list_or_none and get_object_or_none methods to django.shortcuts
object_list_404-2.diff (1.7 KB) - added by cpharmston 6 years ago.
Modification: wraps get_list_or_none() return value in list()
object_list_404-3.diff (9.1 KB) - added by cpharmston 6 years ago.
Adds tests and documentation

Download all attachments as: .zip

Change History (12)

Changed 6 years ago by cpharmston

Adds get_list_or_none and get_object_or_none methods to django.shortcuts

comment:1 Changed 6 years ago by cpharmston

  • Needs documentation unset
  • Needs tests set
  • Patch needs improvement unset

comment:2 Changed 6 years ago by Alex

  • Patch needs improvement set

comment:3 Changed 6 years ago by cpharmston

  • Summary changed from get_object/list_or_404 methods to get_object/list_or_none methods

Whoops, obvious oversight! I forgot to wrap list() around the return value for get_list_or_none().

Changed 6 years ago by cpharmston

Modification: wraps get_list_or_none() return value in list()

comment:4 Changed 6 years ago by Alex

  • Triage Stage changed from Unreviewed to Design decision needed

Changed 6 years ago by cpharmston

Adds tests and documentation

comment:5 Changed 6 years ago by cpharmston

  • Needs tests unset
  • Patch needs improvement unset

Added a new patch with proper documentation and unit tests.

Sidebar: it may be worth considering renaming tests/get_object_or_404 to something like tests/dbapi_shortcuts.

comment:6 Changed 6 years ago by Alex

Returning a list from get_object_or_none makes no sense to me, it should return None .

comment:7 Changed 5 years ago by julien

  • Severity set to Normal
  • Type set to New feature

comment:8 Changed 4 years ago by ori

  • Easy pickings unset
  • UI/UX unset

I'm having a hard time understanding the rationale behind this feature. This pattern seems rather obscure, rather than so commonplace so as to warrant a shortcut method.

You can already do this quite succinctly:

query_set = Book.objects.filter(pk=999)
val = query_set.get() if query_set else Book.objects.none()

(This assumes that your query set may return one or no results. A larger result set will cause a MultipleObjectsReturned exception to be raised.)

It's possible I'm missing something obvious, but I can't help the feeling that having functions that expect a model instance or an empty QuerySet is an anti-pattern. A QuerySet is a collection; an empty QuerySet is still just an empty collection. Alex's proposal (that get_object_or_none return None instead) is more palatable, but I think that in order for this to be compelling a realistic use-case ought to be presented.

comment:9 Changed 4 years ago by lukeplant

  • Resolution set to wontfix
  • Status changed from new to closed

I agree with Ori that I can't see the rationale for these:

1) get_object_or_none is unhelpful - it returns either a single object or an empty QuerySet, which means you then still need to test what type of thing you've got i.e. a list of things or a single thing, which I agree seems to promote an anti-pattern. If you just want to silence the DoesNotExist you get from the get() call if there are no matching items - don't use get(), just use list() on the QuerySet. The only other case this function would be useful is if you want an empty list for the case where get() returns zero items or it returns more than 1 item, but you want a single object if it returns exactly 1 item. This is certainly not a common case in my experience.

2) get_list_or_none seems even more bizarre. This method just seems to be a rather inefficient way of doing list(queryset.filter(**kwargs)) - list(queryset.none()) is always exactly equal to an empty list, and empty lists are empty lists. (It's also incorrectly documented as having something to do with DoesNotExist exceptions).

I think these things must be based on some misconception about how lists in Python work, or something, I'm afraid I can't work out the intention here.

Note: See TracTickets for help on using tickets.
Back to Top