JasonTS
JasonTS

Reputation: 2589

Django query if / else?

I'm building a website that displays photo albums. For that I have the following Models.

class Medium(models.Model):
    pass

class MediaSet(models.Model):
    media = models.ManyToManyField("Medium", related_name="sets", through="SetContent", through_fields=('set', 'medium'),)

class SetContent(models.Model):
    is_cover = models.BooleanField(default=None, null=True)
    set = models.ForeignKey("MediaSet", on_delete=models.CASCADE, related_name="set_content")
    medium = models.ForeignKey("Medium", on_delete=models.CASCADE, related_name="set_contents")

Every MediaSet(=Album) might have a cover. If it doesn't I will just use the first image in there.

Now I'm trying to optimize the DB by reducing queries. I'm working on the MediaSetListView which lists MediaSets. Is it possible at the Query level to annotate or Prefetch() a cover (one Medium) depending on whether is_cover exists or not?

In other words: Get a list of all mediasets and have every mediaset have a cover that is either the Medium marked as "is_cover" in SetContent or else the first Medium in SetContent.

Currently I have this logic in the model, but that leads to tons of queries which I don't want.

Thanks for your help.

Upvotes: 1

Views: 122

Answers (1)

Boketto
Boketto

Reputation: 885

What about adding the cover reference to the MediaSet class and using the property decorator? This would save you the extra column in the manytomany table, and I assume you will never have more than one cover per album, right? Then this relationship should be reflected at the MediaSet class in my opinion. Then you could eventually also spare the SetContent class by the way.

class MediaSet(models.Model):
    _cover = models.ForeignKey("Medium", blank=true, null=true, on_delete=models.SET_NULL)
    media = models.ManyToManyField("Medium", related_name="albums")
    
    @property
    def cover(self):
        if self._cover:
            return self._cover
        else:
            return self.media.first()  

    @cover.setter
    def cover(self, value):
        self._cover = value

Upvotes: 1

Related Questions