Question

I have a model called 'Projects'.

Projects can be featured. If they are, they will be displayed on the home page (Projects.filter(is_featured=True))

Each project contains several slides. These slides can be featured (Slide.is_featured=True), and contain an Image model which contains the actual image.

In my home page, I would like to display a slideshow in which each slide contains the project name, and the image contained in the featured slide.

I did that by adding a method called 'featured_slide()' in my Project Model, but now I realize that I've been hitting on the DB every time, and I would like to improve that by using the 'select_related' statement.

How can I do that?

Optimally, I would like to have a field like 'featured_slide' to represent the featured slide.

I was thinking of doing something along these lines:

Projects.filter(is_featured=True).annotate(featured_slide='slides__is_featured=True').select_related(slides__image)

I know it can't be that simple (slides__is_featured is not a database field), but you get the idea.

Was it helpful?

Solution

If you want a slideshow of only those Slides that themselves are featured as well as being related to a featured Projects:

class Project(...):
    name = models.CharField()
    is_featured = models.BooleanField()

class Slide(...):
    project = models.ForeignKey(Project)
    is_featured = models.BooleanField()
    image = models.ImageField()

to query the slides (using select_related to avoid unnecessary queries):

slides = Slide.select_related("project").filter(is_featured=True, project__is_featured=True)

and template:

<ul>
    {% for slide in slides %}
         <li><img src="{{ slide.image.url }} /><span class="caption">{{ slide.project.name }}</caption></li>
    {% endfor %}
</ul>

EDIT:

If you want to lookup the reverse relationship (i.e. get all the slides for a project), by default you can do the following:

project = Project.objects.get(...)
project_slides = project.slide_set.all()

You add _set to the model name. You can make this more intuitive by adding a related_name attribute to the relationship:

class Slide(...):
    project = models.ForeignKey(Project, related_name="slideshow_slides")

and now use:

project = Project.objects.get(...)
project.slideshow_slides.all()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top