Opened 14 years ago

Closed 14 years ago

Last modified 11 years ago

#14150 closed Uncategorized (wontfix)

[patch] a get_objects_or_404 ?

Reported by: wumzi Owned by: nobody
Component: Core (Other) Version: dev
Severity: Normal Keywords: get_list_or_404 get_objects_or_404, shortcuts, django.shortcuts
Cc: Triage Stage: Unreviewed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I got a issue with django.shortcuts.get_list_or_404: Because, it returns the set of objects as a list, I couldn't run some .order_by(field) as I usually do with querysets, so I made a patch on django.shortcuts. I created a get_objects_or_404, which returns a queryset, and I modified get_list_or_404, which now simply converts the get_objects_or_404 queryset into a list.


Here's my code:

def get_objects_or_404(klass, *args, **kwargs):
    """
    Get a set of filtered objects

    Uses filter() to return objects, or raise a Http404 exception if
    no objects matches.

    klass may be a Model, Manager, or QuerySet object. All other passed
    arguments and keyword arguments are used in the filter() query.
    """
    queryset = _get_queryset(klass)
    objects = queryset.filter(*args, **kwargs)
    if not objects:
        raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
    return objects

def get_list_or_404(klass, *args, **kwargs):
    """
    Get a list of filtered objects

    Uses get_object_or_404 to get a set of objects, which will raise a Http404 exception if
    no objects matches, then returns that set as a list.

    klass may be a Model, Manager, or QuerySet object. All other passed
    arguments and keyword arguments are used in the filter() query
    with get_objects_or_404.
    """
    return list(get_objects_or_404(klass, *args, **kwargs))

I also write a little documentation.

``get_objects_or_404``
===================

.. function:: get_objects_or_404(klass, *args, **kwargs)

   Returns the result of :meth:`~django.db.models.QuerySet.filter()` on a
   given model manager, raising ``django.http.Http404`` if no objects matched.

Required arguments
------------------

``klass``
    A ``Model``, ``Manager`` or ``QuerySet`` instance from which to get the
    object.

``**kwargs``
    Lookup parameters, which should be in the format accepted by ``get()`` and
    ``filter()``.

Example
-------

The following example gets all published objects from ``MyModel``::

    from django.shortcuts import get_objects_or_404

    def my_view(request):
        my_objects = get_objects_or_404(MyModel, published=True)

This example is equivalent to::

    from django.http import Http404

    def my_view(request):
        my_objects = MyModel.objects.filter(published=True)
        if not my_objects:
            raise Http404

Because get_objects_or_404 returns a queryset, it's possible to continue
editing it:

    from django.shortcuts import get_objects_or_404

    def my_view(request):
        my_objects = get_objects_or_404(MyModel, published=True).order_by('pub_date')

Attachments (3)

get_objects_or_404.diff (3.3 KB ) - added by wumzi 14 years ago.
the SVN Diff (change on django.contrib.shortcuts + documentation on shorcuts)
shortcuts.txt (7.6 KB ) - added by wumzi 14 years ago.
The new Shortcuts documentation
__init__.py (4.1 KB ) - added by wumzi 14 years ago.
The new python file for shortcuts

Download all attachments as: .zip

Change History (13)

by wumzi, 14 years ago

Attachment: get_objects_or_404.diff added

the SVN Diff (change on django.contrib.shortcuts + documentation on shorcuts)

by wumzi, 14 years ago

Attachment: shortcuts.txt added

The new Shortcuts documentation

by wumzi, 14 years ago

Attachment: __init__.py added

The new python file for shortcuts

comment:1 by Łukasz Rekucki, 14 years ago

Is there any reason why can't you apply order_by() to queryset before passing it to get_list_or_404(), like this:

    my_objects = get_list_or_404(MyModel.objects.order_by('pub_date'), published=True)

Doing it the way you propose:

    my_objects = MyModel.objects.filter(published=True)
    if not my_objects:
        raise Http404
    my_objects = list(my_objects.order_by('pub_date'))

Will make 2 database queries, instead of 1.

comment:2 by wumzi, 14 years ago

I've already thought to your solution.
But if I sort then filter, it will take more ressources than if I filter then sort, because there'll be more items to sort, isn't it ?

Is it really a new database query to sort objects ?

comment:3 by Łukasz Rekucki, 14 years ago

I'm going to close this as won't fix. First because the problem I noted before, secondly because it's easy to add the get_objects_or_404 to your project's utils/helpers package if you really need it.

Anwsering your last question: No, it doesn't matter if you first add a filter() and then an order_by(), it will produce the same query and it's up to DB how to execute that query efficiently. You can read more on how QuerySets work and when they are executed in the docs: http://docs.djangoproject.com/en/dev/topics/db/queries/ , http://docs.djangoproject.com/en/dev/ref/models/querysets/#when-querysets-are-evaluated

comment:4 by Łukasz Rekucki, 14 years ago

Resolution: wontfix
Status: newclosed

comment:5 by Jacob, 13 years ago

milestone: 1.3

Milestone 1.3 deleted

comment:6 by Charlie Denton, 11 years ago

Easy pickings: unset
Severity: Normal
Type: Uncategorized
UI/UX: unset

It is worth noting that this confusion is a result of unclear documentation:

Returns the result of filter() on a given model manager, raising Http404 if the resulting list is empty.

This implies that the result is a queryset because that is what you would get back from filter.

Should I open a new ticket, or is this the correct place to address the issue?

comment:7 by Tim Graham <timograham@…>, 11 years ago

In e161e4ff1176acb1b3636e3f93280055185d3d78:

Clarified get_list_or_404 docs, refs #14150.

comment:8 by Tim Graham <timograham@…>, 11 years ago

In 7e6c0387b32669babba91dca6538609330eb5e26:

[1.5.x] Clarified get_list_or_404 docs, refs #14150.

Backport of e161e4ff11 from master

comment:9 by Tim Graham, 11 years ago

@meshy, I added some clarification in the above commits.

comment:10 by Charlie Denton, 11 years ago

Nice one, thank-you :)

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