아래에 임의로 하나의 영화에 여러 유저가 점수(score)를 매겼다.
mysql> select * from rates;
+----+-------+---------+---------+
| id | score | film_id | user_id |
+----+-------+---------+---------+
| 1 | 3.0 | 1 | 1 |
| 2 | 4.0 | 1 | 2 |
| 3 | 5.0 | 1 | 3 |
+----+-------+---------+---------+
3 rows in set (0.00 sec)
sum
을 이용하여 기본적으로 점수의 총합을 구할 수는 있다.
In [9]: sum([rate.score for rate in Rate.objects.all()])
Out[9]: Decimal('12.0')
파이썬으로 갖고 올 때만 가상의 임시 필드를 생성한다.
즉, 임의로 속성을 만든다.
아래는 score
라는 속성이 없다.
In [16]: film = Film.objects.get(id=1)
In [17]: dir(film)
Out[17]:
['DoesNotExist',
'MultipleObjectsReturned',
...
'save',
'save_base',
'serializable_value',
]
In [18]: from django.db.models import Sum, Avg
하지만 annotate
를 통해 새로 score
를 만들었다.
In [20]: film = Film.objects.annotate(score=Sum('rate')).get(id=1)
In [21]: dir(film)
Out[21]:
['DoesNotExist',
'MultipleObjectsReturned',
...
'save_base',
'score',
'serializable_value',
...
]
헷갈리니 다시 total_score
로 바꾸어 보자.
In [22]: film = Film.objects.annotate(total_score=Sum('rate')).get(id=1)
In [23]: dir(film)
Out[23]:
['DoesNotExist',
'MultipleObjectsReturned',
...
'save_base',
'serializable_value',
'total_score',
'unique_error_message',
'validate_unique',
'watchlist_set'
In [26]: film = Film.objects.annotate(total_score=Sum('rate')).get(id=1)
In [27]: film.total_score
Out[27]: Decimal('6')
rate
로만 접근을 하여 기본 값인 id
의 총합이 생성 되었다.
In [28]: film = Film.objects.annotate(total_score=Sum('rate__score')).get(id=1)
In [29]: film.total_score
Out[29]: Decimal('12.0')
__
를 통하여 rate
의 score
에 대한 Sum
값을 구하였다.
In [32]: film = Film.objects.annotate(average_score=Avg('rate__score')).get(id=1)
In [33]: film.average_score
Out[33]: Decimal('4.00000')
In [34]: film = Film.objects.annotate(average_score=Avg('rate__score')).all()
In [35]: film[0].average_score
Out[35]: Decimal('4.00000')
In [36]: film[1].average_score
필드가 아닌 값 하나만 갖고 온다 → 평점이라 해도, 값 하나만 갖고 온다
In [40]: Film.objects.aggregate(average_score=Avg('rate__score'))
Out[40]: {'average_score': Decimal('4.00000')}
In [41]: Film.objects.filter(id=1).aggregate(average_score=Avg('rate__score'))
Out[41]: {'average_score': Decimal('4.00000')}
In [42]: Film.objects.filter(id=2).aggregate(average_score=Avg('rate__score'))
Out[42]: {'average_score': None}
mysql> select * from rates;
+----+-------+---------+---------+
| id | score | film_id | user_id |
+----+-------+---------+---------+
| 1 | 3.0 | 1 | 1 |
| 2 | 4.0 | 1 | 2 |
| 3 | 5.0 | 1 | 2 |
+----+-------+---------+---------+
3 rows in set (0.00 sec)
실수로 값을 잘못 넣어 user_id
번인 유저가 film_id
에 대하여 2번 점수를 매겼다.
In [10]: a = Rate.objects.get(id=3)
In [11]: a.user_id=3
In [12]: a.save()
수정 완료!
mysql> select * from rates;
+----+-------+---------+---------+
| id | score | film_id | user_id |
+----+-------+---------+---------+
| 1 | 3.0 | 1 | 1 |
| 2 | 4.0 | 1 | 2 |
| 3 | 5.0 | 1 | 3 |
+----+-------+---------+---------+
3 rows in set (0.00 sec)