Django fetch data on a single table with a filtered set of related objects
I intend to get all site based offers from model OfferSite
filtered by model OfferItem
for today.
When I select everything without filter on the second model, I get the desired result (only 2 sites with offerem_set),
In [23]: OfferSite.objects.all().select_related("offeritem")
Out[23]: [<OfferSite: OfferSite object>, <OfferSite: OfferSite object>]
But when I try to filter the second model I get a lot of objects, I think it returns an object OfferSite
for each OfferItem. I expected only two objects OfferSite
with offeritem_set
to retrieve all the filtered OfferItem
s
``
In [24]: OfferSite.objects.all().select_related("offeritem").filter(offeritem__offer_date=tod)
Out[24]: [<OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, <OfferSite: OfferSite object>, '...(remaining elements truncated)...']
Is there a Django ORM way to get the desired result?
My Models
class OfferSite(models.Model):
name = models.CharField(max_length=30)
domain_url = models.URLField()
class OfferItem(models.Model):
title = models.CharField(max_length=255)
link = models.CharField(max_length=750)
image = ImageField()
price_after_discount = models.CharField(max_length=100, blank=True, null=True)
price_before_discount = models.CharField(max_length=100, blank=True, null=True)
discount = models.CharField(max_length=100, blank=True, null=True)
offer_date = models.DateField(auto_now_add=True, default=datetime.date.today())
offer_from = models.DateTimeField(blank=True, null=True)
offer_to = models.DateTimeField(blank=True, null=True)
single_item = models.BooleanField(default=True)
site = models.ForeignKey(OfferSite)
archived = models.BooleanField(default=False)
likes = models.IntegerField(max_length=4, default=0)
unlikes = models.IntegerField(max_length=4, default=0)
abusive = models.IntegerField(max_length=3, default=0)
source to share
Others are looking for a solution just in case. This question answers it Why does django prefetch_related () only work with all () and not filter ()? ... The title of this question did not reflect the problem, so I skipped it.
Solution in my case:
OfferSite.objects.all().prefetch_related(Prefetch("offeritem_set", queryset=OfferItem.objects.filter(offer_date=tod), to_attr="offers"))
This only applies to Django 1.7 and up.
source to share