简体   繁体   中英

Django: how to join and annotate multiple sql tables?

I'm building a sample django app and I can't aggregate properly some sql results.

Consider these 3 models:

Movie model

class Movie(models.Model):
    source_id = models.CharField(max_length=100, primary_key=True)
    title = models.CharField(max_length=200, validators=[MinLengthValidator(1)])

Rating model

class Rating(models.Model):
    movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
    rating = models.PositiveIntegerField()
    username = models.CharField(max_length=100, validators=[MinLengthValidator(1)])

Comment model

class Comment(models.Model):
    movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
    username = models.CharField(max_length=100, validators=[MinLengthValidator(1)])
    body = models.TextField()

Then consider the following mysql tables:

movie

+-----------+-----------+
| source_id |   title   |
+-----------+-----------+
| 15sdfsd4  | Spiderman |
+-----------+-----------+

rating

+----+--------+----------+----------+
| id | rating | username | movie_id |
+----+--------+----------+----------+
|  1 |      4 | jack     | 15sdfsd4 |
|  2 |      3 | mick     | 15sdfsd4 |
+----+--------+----------+----------+

comment

+----+----------+--------------------+----------+
| id | username |        body        | movie_id |
+----+----------+--------------------+----------+
|  1 | charles  | I loved this movie | 15sdfsd4 |
|  2 | mick     | Nice sound fx      | 15sdfsd4 |
+----+----------+--------------------+----------+

I would like to query for a list of movie ids and get a summary of the avg rating and the nr of comments.

I tried something like

ids = ['15sdfsd4','54fdf5d']
m = Movie.objects.filter(source_id__in=ids).annotate(Avg('rating'), Count('comment'))

I would expect a comment count of 2 and an avg rating of 3.5 for the movie with id 15sdfsd4 . Instead I get a comment count of 4 and an avg rating of 1.5 which I can't make much sense of...

Do you have any suggestion? Thanks

There are two thing that are wrong with following solution

  • You are not specifying column to average on ( rating_rating )
  • Django combining multiple annotations bug and thread

Considering count aggregate has distinct and average with duplicates is same this would probably work

 m = Movie.objects.filter(source_id__in=ids).annotate(
     Avg('rating__rating'), 
     Count('comment',distinct=True)
 )

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM