Suppose I have the following models
class Award(models.Model):
user = models.ForeignKey(User)
class AwardReceived(models.Model):
award = models.ForeignKey(award)
date = models.DateField()
units = models.IntegerField()
class AwardUsed(models.Model):
award = models.ForeignKey(award)
date = models.DateField()
units = models.IntegerField()
Now, suppose I want to get the number of awards for all users and the number of awards used for all users (ie, a queryset containing both). I prefer to do it one query for each calculation - when I combined it in my code I had some unexpected results. Also for some of my queries it won't be possible to do it one query, since the query will get too complex - I'm calculating 8 fields. This is how I solved it so far:
def get_summary(query_date)
summary = (Award.objects.filter(awardreceived__date__lte=query_date))
.annotate(awarded=Sum('awardissuedactivity__units_awarded')))
awards_used = (Award.objects.filter(awardused__date__lte=query_date)
.annotate(used=Sum('awardused__date__lte__units')))
award_used_dict = {}
for award in awards_used:
award_used_dict[award] = award.used
for award in summary:
award.used = award_used_dict.get(award, 0)
return summary
I'm sure there must be a way to solve this without the dictionary approach? For instance, something like this: awards_used.get(award=award)
, but this causes a db lookup every loop.
Or some other fancy way to join the querysets?
Note this is a simplified example and I know for this example the DB structure can be improved, I'm just trying to illustrate my question.
SOLUTION 1
Just try to concatenate your queryset using |
final_q = q1 | q2
In your example
final_q = summary | awards_used
UPDATED:
| does not works using calculated attributes, so, we can select our queryset first and then mapping our extra attributes
summary = Award.objects.filter(awardreceived__date__lte=query_date)
awards_used = Award.objects.filter(awardused__date__lte=query_date)
final_q = summary | awards_used
final_q = final_q.annotate(used=Sum('awardused__date__lte__units')).annotate(awarded=Sum('awardissuedactivity__units_awarded'))
SOLUTION 2
Using chain built-in function
from itertools import chain
final_list = list(chain(summary, awards_used))
There is an issue with this approach, you won't get a queryset, you will get a list containing instances.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.