Skip to content

Commit cae92ae

Browse files
committed
Fixed #4373 -- Modified the get_object_or_404/get_list_or_404 shortcuts to also accept QuerySets. Thanks SuperJared.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5746 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent 63cc023 commit cae92ae

File tree

4 files changed

+60
-23
lines changed

4 files changed

+60
-23
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ answer newbie questions, and generally made Django that much better:
242242
Thomas Steinacher <http://www.eggdrop.ch/>
243243
nowell strite
244244
Sundance
245+
SuperJared
245246
Radek Švarz <http://www.svarz.cz/translate/>
246247
Swaroop C H <http://www.swaroopch.info>
247248
Aaron Swartz <http://www.aaronsw.com/>

django/shortcuts/__init__.py

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from django.template import loader
88
from django.http import HttpResponse, Http404
99
from django.db.models.manager import Manager
10+
from django.db.models.query import QuerySet
1011

1112
def render_to_response(*args, **kwargs):
1213
"""
@@ -16,40 +17,46 @@ def render_to_response(*args, **kwargs):
1617
return HttpResponse(loader.render_to_string(*args, **kwargs))
1718
load_and_render = render_to_response # For backwards compatibility.
1819

20+
def _get_queryset(klass):
21+
"""
22+
Return a QuerySet from a Model, Manager, or QuerySet. Created to make
23+
get_object_or_404 and get_list_or_404 more DRY.
24+
"""
25+
if isinstance(klass, QuerySet):
26+
return klass
27+
elif isinstance(klass, Manager):
28+
manager = klass
29+
else:
30+
manager = klass._default_manager
31+
return manager.all()
32+
1933
def get_object_or_404(klass, *args, **kwargs):
2034
"""
2135
Use get() to return an object, or raise a Http404 exception if the object
2236
does not exist.
2337
24-
klass may be a Model or Manager object. All other passed
38+
klass may be a Model, Manager, or QuerySet object. All other passed
2539
arguments and keyword arguments are used in the get() query.
2640
2741
Note: Like with get(), an AssertionError will be raised if more than one
2842
object is found.
2943
"""
30-
if isinstance(klass, Manager):
31-
manager = klass
32-
klass = manager.model
33-
else:
34-
manager = klass._default_manager
44+
queryset = _get_queryset(klass)
3545
try:
36-
return manager.get(*args, **kwargs)
37-
except klass.DoesNotExist:
38-
raise Http404('No %s matches the given query.' % klass._meta.object_name)
46+
return queryset.get(*args, **kwargs)
47+
except queryset.model.DoesNotExist:
48+
raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
3949

4050
def get_list_or_404(klass, *args, **kwargs):
4151
"""
4252
Use filter() to return a list of objects, or raise a Http404 exception if
43-
the list is empty.
53+
the list is emtpy.
4454
45-
klass may be a Model or Manager object. All other passed
55+
klass may be a Model, Manager, or QuerySet object. All other passed
4656
arguments and keyword arguments are used in the filter() query.
4757
"""
48-
if isinstance(klass, Manager):
49-
manager = klass
50-
else:
51-
manager = klass._default_manager
52-
obj_list = list(manager.filter(*args, **kwargs))
58+
queryset = _get_queryset(klass)
59+
obj_list = list(queryset.filter(*args, **kwargs))
5360
if not obj_list:
54-
raise Http404('No %s matches the given query.' % manager.model._meta.object_name)
61+
raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
5562
return obj_list

docs/db-api.txt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,8 +1891,8 @@ get_object_or_404()
18911891
One common idiom to use ``get()`` and raise ``Http404`` if the
18921892
object doesn't exist. This idiom is captured by ``get_object_or_404()``.
18931893
This function takes a Django model as its first argument and an
1894-
arbitrary number of keyword arguments, which it passes to the manager's
1895-
``get()`` function. It raises ``Http404`` if the object doesn't
1894+
arbitrary number of keyword arguments, which it passes to the default
1895+
manager's ``get()`` function. It raises ``Http404`` if the object doesn't
18961896
exist. For example::
18971897

18981898
# Get the Entry with a primary key of 3
@@ -1901,7 +1901,7 @@ exist. For example::
19011901
When you provide a model to this shortcut function, the default manager
19021902
is used to execute the underlying ``get()`` query. If you don't want to
19031903
use the default manager, or if you want to search a list of related objects,
1904-
you can provide ``get_object_or_404()`` with a manager object instead.
1904+
you can provide ``get_object_or_404()`` with a ``Manager`` object instead.
19051905
For example::
19061906

19071907
# Get the author of blog instance e with a name of 'Fred'
@@ -1911,6 +1911,14 @@ For example::
19111911
# entry with a primary key of 3
19121912
e = get_object_or_404(Entry.recent_entries, pk=3)
19131913

1914+
If you need to use a custom method that you added to a custom manager,
1915+
then you can provide ``get_object_or_404()`` with a ``QuerySet`` object.
1916+
For example::
1917+
1918+
# Use a QuerySet returned from a 'published' method of a custom manager
1919+
# in the search for an entry with primary key of 5
1920+
e = get_object_or_404(Entry.objects.published(), pk=5)
1921+
19141922
get_list_or_404()
19151923
-----------------
19161924

tests/modeltests/get_object_or_404/models.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
44
get_object_or_404 is a shortcut function to be used in view functions for
55
performing a get() lookup and raising a Http404 exception if a DoesNotExist
6-
exception was rasied during the get() call.
6+
exception was raised during the get() call.
77
88
get_list_or_404 is a shortcut function to be used in view functions for
99
performing a filter() lookup and raising a Http404 exception if a DoesNotExist
10-
exception was rasied during the filter() call.
10+
exception was raised during the filter() call.
1111
"""
1212

1313
from django.db import models
@@ -69,11 +69,28 @@ def __unicode__(self):
6969
>>> get_object_or_404(Article.by_a_sir, title="Run away!")
7070
<Article: Run away!>
7171
72+
# QuerySets can be used too.
73+
>>> get_object_or_404(Article.objects.all(), title__contains="Run")
74+
<Article: Run away!>
75+
76+
# Just as when using a get() lookup, you will get an error if more than one
77+
# object is returned.
78+
>>> get_object_or_404(Author.objects.all())
79+
Traceback (most recent call last):
80+
...
81+
AssertionError: get() returned more than one Author -- it returned ...! Lookup parameters were {}
82+
83+
# Using an EmptyQuerySet raises a Http404 error.
84+
>>> get_object_or_404(Article.objects.none(), title__contains="Run")
85+
Traceback (most recent call last):
86+
...
87+
Http404: No Article matches the given query.
88+
7289
# get_list_or_404 can be used to get lists of objects
7390
>>> get_list_or_404(a.article_set, title__icontains='Run')
7491
[<Article: Run away!>]
7592
76-
# Http404 is returned if the list is empty
93+
# Http404 is returned if the list is empty.
7794
>>> get_list_or_404(a.article_set, title__icontains='Shrubbery')
7895
Traceback (most recent call last):
7996
...
@@ -83,4 +100,8 @@ def __unicode__(self):
83100
>>> get_list_or_404(Article.by_a_sir, title__icontains="Run")
84101
[<Article: Run away!>]
85102
103+
# QuerySets can be used too.
104+
>>> get_list_or_404(Article.objects.all(), title__icontains="Run")
105+
[<Article: Run away!>]
106+
86107
"""}

0 commit comments

Comments
 (0)