1

Example model:

class A(models.Model):
    id = models.CharField(max_length=255, primary_key=True, default=make_uuid, editable=False)
    b = models.IntegerField()

Goal:
I need to get list which would contain id, b and same_b_total.

e.g. following quetyset returns:

a = list(models.Cell.objects.all().values("b").annotate(same_b_total=Count("b")))
print(a)  # [{"b": 1, "same_b_total": 5}, {"b": 2, "same_b_total": 3}]

When I add id into .values("b", "id") it return list with followind data

[{'b': 1, 'id': '<some uuid>', 'same_b_total': 1}, {'b': 1, 'id': '<some uuid2>', 'same_b_total': 1}, {'b': 2, 'id': '<some uuid3>', 'same_b_total': 1}, ...]

How to change query to receive correct same_b_total for each record? Like:

[{'b': 1, 'id': '<some uuid>', 'same_b_total': 5}, {'b': 1, 'id': '<some uuid2>', 'same_b_total': 5}, {'b': 2, 'id': '<some uuid3>', 'same_b_total': 3}, ...]

Table example:
id(uuid)| b

uuid-1 | 1
uuid-2 | 1
uuid-3 | 2
uuid-4 | 1
uuid-5 | 1
uuid-6 | 1
uuid-7 | 2
uuid-8 | 2

3
  • how b and same_b_total is related? Can you give us some real example scenario? Commented Apr 8, 2020 at 17:01
  • @ArakkalAbu added table example. same_b_total reflect total count of same b. There is 5 b with value = 1 and 3 b with value = 2 Commented Apr 8, 2020 at 17:20
  • So, how do you expect the output to be? Commented Apr 8, 2020 at 17:22

1 Answer 1

2

Explanation

Using the combination of OuterRef and Subquery is what you are looking for. For a specific integer value for the field of b you need to get the count of all existing rows. By replacing the specific integer value with OuterRef('b') the result will convert to a subquery. (instead of normal queryset)

Note that sub is a subquery and does not exist on its own.

sub = A.objects.filter(b=OuterRef('b')).values('b').annotate(same_b_count=Count('id'))

We need to inject sub into another query. Getting some help from Django docs about combination of Subquery and Outerref results in:

A.objects.annotate(same_b_count=Subquery(sub.values('same_b_count'))).values('id', 'b', 'same_b_count')

Conclusion

Combining two snippets from explanation:

sub = A.objects.filter(b=OuterRef('b')).values('b').annotate(same_b_count=Count('id'))
A.objects.annotate(same_b_count=Subquery(sub.values('same_b_count'))).values('id', 'b', 'same_b_count')

will result in the output of:

<QuerySet [{'id': 1, 'b': 1, 'same_b_count': 3}, {'id': 2, 'b': 1, 'same_b_count': 3}, {'id': 3, 'b': 1, 'same_b_count': 3}, {'id': 4, 'b': 3, 'same_b_count': 1}, {'id': 5, 'b': 4, 'same_b_count': 2}, {'id': 6, 'b': 4, 'same_b_count': 2}, {'id': 7, 'b': 6, 'same_b_count': 1}]>
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.