Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django - Filtering in DetailView

I had a function based view that looked like this:

def account_details(request, acc_id):
    account = get_object_or_404(Account, pk=acc_id, person__user=request.user)
    # ...

Which shows you details of your account on success, and 404 if you don't have permissions to access the account or it doesn't exist.

I was trying to implement the same using a class based view (extending DetailView), and came up with this:

class AccountDetailView(DetailView):
    def get_object(self, queryset=None):
        obj = super(AccountDetailView, self).get_object(queryset)
        if obj.person.user != self.request.user:
            raise Http404()
        return obj

The urlconf:

url(r'^account_details/(?P<pk>[0-9a-f]{24})$',
    login_required(AccountDetailView.as_view(model=Account)),
    name='account_details'),

This attitude works, but introduces 2 extra queries, and looks wrong.

Is there a standard or a more elegant way to achieve the same result?

like image 264
yprez Avatar asked Feb 22 '12 21:02

yprez


People also ask

Can you filter a QuerySet?

Working with Filter Easily the most important method when working with Django models and the underlying QuerySets is the filter() method, which allows you to generate a QuerySet of objects that match a particular set of filtered parameters.

Can you filter by property Django?

Django-property-filter is an extension to django-filter and provides functionality to filter querysets by class properties. It does so by providing sub-classes for Filters and Filtersets to keep existing django-filter functionality. For more details and examples check the documentation.

What is the purpose of filter () method in Django?

The filter() method is used to filter you search, and allows you to return only the rows that matches the search term.


2 Answers

What arguments would you need to pass to get_queryset anyways? This should do it:

def get_queryset(self):
    qs = super(MyView, self).get_queryset()
    return qs.filter(person__user=self.request.user)
like image 169
Chris Pratt Avatar answered Sep 28 '22 01:09

Chris Pratt


If you are worried about the queries, you can use select_related to prefetch the user profiles in the queryset:

 def get_queryset(self)
     return Account.objects.select_related("person", "person__user").all()

 def get_object(self, queryset=None):
     try:
         return queryset.get(pk=self.kwargs['acc_id'], person__user=self.request.user)
     except Account.DoesNotExist:
         raise Http404

I have to say, it's sometimes difficult to get things to fit with class-based views

like image 31
Timmy O'Mahony Avatar answered Sep 27 '22 23:09

Timmy O'Mahony