Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Django Class-based Views Customizing Class-based Views Mixins

Jay Norris
Jay Norris
14,824 Points

Documentation for Django Braces

I'm having an issue with Django Braces, specifically the PrefetchRelatedMixin. If found the documentation below, but I'm wondering if there is deeper information about the Mixins?

http://django-braces.readthedocs.io/en/latest/other.html#prefetchrelatedmixin

3 Answers

Kenneth Love
STAFF
Kenneth Love
Treehouse Guest Teacher

Ah, yeah, this is a slight misunderstanding of how pretch_related works. Let's see if I can explain it.

When you have a Household record, it has 1+ Person records attached to it through a ForeignKey on the Person record, right? So when you do Household.person_set.all(), Django has to do another query to get all of those related Person records. prefetch_related can't eliminate this query. Nothing really can unless you wrote custom SQL for it and no one wants to do that.

What prefetch_related does for you, though, is it consolidates the queries into the view instead of doing one in the view and then one in the template. What you have now in your CBV should be executing two queries but it doesn't add anything to the context (the variables available to the template). You'd still use the Person records through dot notation from the Household object.

{% for person in household.person_set.all %}
     {{ person.gender }}
{% endfor %}
Jay Norris
Jay Norris
14,824 Points

It worked! I thought I had a good grasp of prefetch_related, but the way you explained it there made it crystal clear. Thank you for taking the time to explain that point to me. Thanks for all of the Python education you provide. I can't get enough of it. And thanks for making Django Braces!

Kenneth Love
Kenneth Love
Treehouse Guest Teacher

Awesome, glad you got it sorted and understand it better! (and you're very welcome for both the courses and django-braces).

Kenneth Love
STAFF
Kenneth Love
Treehouse Guest Teacher

What's your issue and what are you wanting to know?

Jay Norris
Jay Norris
14,824 Points

I've pip installed Django Braces and imported to views (see views.py below). I'm trying to convert a function based view which is based on your course_detail view from "Django ORM". The view works great, but I wanted to play with these mixins. My Household -> Person relationship is like your Course -> Quiz relationship from the ORM course. The template 'household_detail.html' shows up just fine with the Household data, but not the person_set. Django Debug Toolbar shows a query for the person_set:

SELECT ••• FROM "quotes_person" WHERE "quotes_person"."household_id" IN (57) ORDER BY "quotes_person"."birthdate" ASC

but DjDT doesn't show a person_set coming through to the template in the context like it does with the function.

I'm using Django 1.9.7.

models.py

class Household(models.Model):
    last_name = models.CharField(max_length=50)
    email = models.EmailField(max_length=120)
    phone = models.CharField(max_length=30, blank=True)

class Person(models.Model): 
    gender = models.CharField(max_length=8, choices=GENDERS, default='')
    birthdate = models.DateField(max_length=25)
    household = models.ForeignKey(Household)
#views.py (showing only relevant imports)
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User
from django.views.generic import ListView, DetailView
from braces.views import PrefetchRelatedMixin

#*********
Old function based view - works correctly
#*********
@login_required
def household_detail(request, pk):
    household = get_object_or_404(models.Household, pk=pk)
    persons = sorted(chain(household.person_set.all()),
                    key=lambda person: person.birthdate,
                    reverse = False)
    return render(request, 'quotes/household_detail.html', {
            'household': household,
            'persons': persons
        })

#************
New class based view
#************
class HouseholdDetailView(LoginRequiredMixin, PrefetchRelatedMixin, DetailView):
    model = models.Household
    prefetch_related = [u"person_set"]
#url
url(r'household/(?P<pk>\d+)/$', views.HouseholdDetailView.as_view(), name='household'),
<!-- household_detail.html -->

<h2>{{ household.last_name }}</h2>
  <dd>Phone: {{ household.phone }}</dd>
  <dd>Email: {{ household.email }}</dd>

  {% for person in person_set %}
    <dd>{{ person.gender }}</dd>
    <dd>DOB: {{ person.birthdate|date:"m/d/Y" }}</dd>
  {% endfor %}

Sorry for the long post. I wanted to make sure I included everything. I love all of your courses and challenges. I've probably taken all of them! Thanks for putting together Django Braces. I can't wait to fully grok the Django classes!