Skip to content

Instantly share code, notes, and snippets.

@jim-clark
Last active February 2, 2024 21:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jim-clark/cc4e38a93a8a6036bfeac3899c7a49e1 to your computer and use it in GitHub Desktop.
Save jim-clark/cc4e38a93a8a6036bfeac3899c7a49e1 to your computer and use it in GitHub Desktop.

Django Class-Based View Customization Tips

ListView Filtering Example

class CatList(ListView):
  model = Cat
  
  # Only return the cats for the logged in user
  def get_queryset(self):
    # Note how the logged in user is being accessed
    return Cat.objects.filter(user=self.request.user)

👀 The request object is accessible via self.request in all overridden methods.

Passing Additional Data to a Template

class CatList(ListView):
  model = Cat
  
  def get_context_data(self, **kwargs):
    # Call the base implementation first to get the context dict
    context = super().get_context_data(**kwargs)
    # Pass the 'sort' query param (or empty string if not existing) sent in the request
    context['sort'] = self.request.GET.get('sort', '')
    return context

Access the pk URL Parameter in Any Method

All CBVs can access the pk URL parameter using self.kwargs['pk'] in any method being overridden.

Override success_url in a DeleteView

If the following syntax is not flexible enough:

class DeleteFeeding(DeleteView):
  model = Feeding
  # This syntax allows for dynamic interpolation of 
  # the attributes on the deleted object!
  success_url = '/cats/{cat_id}'

you can also override the get_success_url method:

class DeleteReview(DeleteView):
  model = Review

  def get_success_url(self):
    # Assuming the review belongs to a recipe
    return f"/recipes/{self.object.recipe.id}"

👀 Note that the object being accessed in a DetailView, DeleteView, CreateView or UpdateView is accessed via self.object.

Assign the Logged in User in a CreateView

class CatCreate(CreateView):
  model = Cat
  fields = ['name', 'breed', 'description', 'age']
  success_url = '/cats'

  def form_valid(self, form):
    # form.instance is the new, but unsaved object 
    form.instance.user = self.request.user
    # Let CreateView's form_valid method do its thing
    return super().form_valid(form)

Check "ownership" of an object

class CatDelete(LoginRequiredMixin, DeleteView):
  model = Cat
  success_url = '/cats'

  def dispatch(self, request, *args, **kwargs):
    cat = self.get_object()
    if cat.user != request.user:
      # Not owner - do redirect instead of letting DeleteView do its job
      return redirect('index')
    return super().dispatch(request, *args, **kwargs)

Implementing Sorting via Query Params

Query parameters (key=value pairs after the ? in the url) do not impact routing - continue to use the "List/Index" functionality.

Example:

SORT BY: <a href="{% url cats_list %}?sort=name">Name</a> | <a href="{% url cats_list %}?sort=breed">Breed</a>

Access query params in the view function on the request.GET QueryDict:

# sort will be 'name', 'breed', or None
sort = request.GET.get('sort')

If there's a query param, use order_by to sort the QuerySet:

if sort:
  cats = Cat.objects.order_by(sort)
else:
  cats = Cat.objects.all()
  # Or maybe provide a default...
  # cats = Cat.objects.order_by('name')

If using a ListView, override the get_queryset() method:

class CatList(ListView):
  model = Cat
  
  def get_queryset(self):
    sort = self.request.GET.get('sort', '')
    if sort:
      return Cat.objects.order_by(sort)
    else:
      return Cat.objects.all()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment