Reputation: 15816
I have this very simple models: a Clip
can have many AdBase
and an AdBase
can have many Clip
's.
class AdBase(models.Model):
title = models.CharField(max_length=200, default=None, null=True,
blank=False)
class Clip(models.Model):
ads = models.ManyToManyField(AdBase, related_name='clips',
through='ClipAd')
class ClipAd(models.Model):
clip = models.ForeignKey(Clip, on_delete=models.CASCADE,
blank=False, null=False)
ad = models.ForeignKey(AdBase, on_delete=models.CASCADE,
blank=False, null=False)
position = models.IntegerField(default=0, blank=False, null=False)
I want in the class Clip
, a query which returns all its clips ordered by their position
.
I've come up with this:
class Clip(models.Model):
ads = models.ManyToManyField(AdBase, related_name='clips',
through='ClipAd')
def ads_by_position(self):
# there might be a simpler query than this:
return [a.ad
for a in ClipAd.objects.filter(clip=self).order_by('position')]
But I'm sure there's a simpler syntax using the ads
property of my class Clip
but I didn't find one.
Any idea (or is this the only solution)?
Upvotes: 0
Views: 51
Reputation: 2210
You can use prefetch_related for this purpose. It will also decrease your DB load a lot. Also, using custom managers worths a look.
class ClipManager(models.Manager):
def get_with_adds():
return Clip.objects.filter().prefetch_related("ads")
class AdBase(models.Model):
title = models.CharField(max_length=200, default="")
class Clip(models.Model):
ads = models.ManyToManyField(AdBase, related_name='clips',
through='ClipAd')
objects = ClipManager()
class ClipAd(models.Model):
clip = models.ForeignKey(Clip, on_delete=models.CASCADE)
ad = models.ForeignKey(AdBase, on_delete=models.CASCADE)
position = models.IntegerField(default=0)
clips_with_adds = Clip.objects.get_with_adds()
Upvotes: 2
Reputation: 7739
You can access related many to many items directly:
def ads_by_position(self):
return self.ads.all().order_by('position')
Upvotes: 0