Opened 5 years ago

Closed 5 years ago

Last modified 21 months ago

#14150 closed Uncategorized (wontfix)

[patch] a get_objects_or_404 ?

Reported by: wumzi Owned by: nobody
Component: Core (Other) Version: master
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 5 years ago.
the SVN Diff (change on django.contrib.shortcuts + documentation on shorcuts)
shortcuts.txt (7.6 KB) - added by wumzi 5 years ago.
The new Shortcuts documentation
__init__.py (4.1 KB) - added by wumzi 5 years ago.
The new python file for shortcuts

Download all attachments as: .zip

Change History (13)

Changed 5 years ago by wumzi

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

Changed 5 years ago by wumzi

The new Shortcuts documentation

Changed 5 years ago by wumzi

The new python file for shortcuts

comment:1 Changed 5 years ago by lrekucki

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

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 Changed 5 years ago by wumzi

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 Changed 5 years ago by lrekucki

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 Changed 5 years ago by lrekucki

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

comment:5 Changed 3 years ago by jacob

  • milestone 1.3 deleted

Milestone 1.3 deleted

comment:6 Changed 21 months ago by meshy

  • Easy pickings unset
  • Severity set to Normal
  • Type set to 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 Changed 21 months ago by Tim Graham <timograham@…>

In e161e4ff1176acb1b3636e3f93280055185d3d78:

Clarified get_list_or_404 docs, refs #14150.

comment:8 Changed 21 months ago by Tim Graham <timograham@…>

In 7e6c0387b32669babba91dca6538609330eb5e26:

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

Backport of e161e4ff11 from master

comment:9 Changed 21 months ago by timo

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

comment:10 Changed 21 months ago by meshy

Nice one, thank-you :)

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