Someday you're going to need to add custom data to your serializer output. Here's how to do it.
Currently, I'm using the model Serializer class to automatically handle 0:00 the serialization of my models. 0:03 I don't have to worry about setting each field explicitly 0:05 as Rest Framework takes care of that for me. 0:07 Thanks, Rest Framework. 0:10 But what if I wanted to add an average rating to the courses so 0:11 I could give an overall view of the quality of a course? 0:14 I'm going to use a pretty common scenario, one to five star ratings, and 0:18 half star increments. 0:21 I already have validation in place to make sure the ratings are between one and five. 0:22 So how would I go about adding this new feature? 0:26 Rest Framework has many different Serializer field types, 0:30 too many in fact to go over right now. 0:33 Of course, that means I put a link in the teacher's notes that you should check out. 0:34 The field type that I want to use is called a Serializer Method Field. 0:38 This field is a read only field that gets a value by calling a method on 0:42 the Serializer it's attached to. 0:45 You can use this to add pretty much any data you want to the serialized 0:47 representation of your object. 0:50 Time to figure this out in work spaces. 0:52 So I want to generate the average rating by using an aggregate over a query set. 0:55 And that means that I need to import the AVG resource thing from Django. 1:02 So from django.db.models import Avg, or average. 1:08 So now, I need to add a new field to my CourseSerializer. 1:14 And we've already got this field that we added. 1:18 And it's not really a new field, it's just kind of like include this thing. 1:20 Anyway, [LAUGH] so let's add a new one here which we'll call average_rating. 1:25 And this is gonna be serializers.SerializerMethodField(). 1:31 Sometimes that word is so horrible. 1:38 All right, so with that set up, 1:41 it's time to actually add the field into my fields couple. 1:43 So we'll come down here and we'll say, 'average_rating', all right. 1:46 And so now, I need to create the method that is on the serializer 1:52 that will come into this field, because this is a SerializerMethodField(). 1:55 It takes a method from the Serializer and uses it as a field. 2:00 All right, so down here, outside of class Meta, 2:04 I'm gonna make a new method and the name here is special. 2:08 Kinda like the validate one is or the clean one is on the form, whatever. 2:12 So you're gonna do get, underscore, and then the field name. 2:16 So my field name is average_rating, so get_average_rating. 2:20 And it takes self, 2:27 and then it also takes the object that is coming in that's being serialized. 2:28 So straightforward enough, I have the object and I'm just working here. 2:33 Okay, so average = obj.reviews.aggregate, 2:37 and aggregate that with Avg for the ;rating' field. 2:43 And then this, If you haven't played aggregate, A, 2:50 you should check out the Django ORMs course at the Django ORM course. 2:54 And second brief idea, aggregate takes all of these things, 2:59 applies this method to them, and sends back a dictionary of data. 3:03 And one of those keys will be 'rating__Avg' which is 3:08 the average of all those ratings. 3:12 Okay, cool. 3:15 So, if average is None: return 0. 3:16 So if there's no reviews, then we'll get back zero. 3:21 If it's not zero or if it's not none rather, 3:27 then we're going to round(average*2), 3:30 take out those spaces, and then we're gonna divide that by 2. 3:33 And this always looks so weird to me every 3:38 time I remember that this is what the formula is, but this works. 3:41 This way, you're always dealing with half amounts, 3:46 like you're always dealing with 1.0 or 1.5, or 2.0 or 2.5 or whatever. 3:49 You don't get like, 2.83. 3:55 And since I wanna do half stars or whole stars, this is the way to do it. 3:57 All right, so now, let's go check out these reviews. 4:01 Before I do that though, I'm gonna send another one through here. 4:08 I'm gonna say Craig, Craig gave this one. 4:11 And Craig just hates Python collections cuz he's just like, 4:14 dude, we don't need Python collections. 4:17 So he gave this one a 1. 4:20 No, he gave it a 2. 4:21 All right, let's send that in. 4:23 All right, and then let's say that Alena took this one. 4:25 And I think she would like this course so she gave it a 5. 4:31 And Andrew came through. 4:35 You all know Andrew, right? 4:40 And he gave it a 1 because that's the kind of person Andrew is. 4:42 All right, so now let's come over here to get, 4:45 and I wanna get courses. 4:50 And I wanna get course number 2, 4:53 because that's the one that I was putting all that stuff in. 4:55 So let's send that through. 4:59 So cool, so we have four reviews here and 5:02 we see that the average rating out of all four of those reviews is a 3. 5:05 Neat. 5:10 The round will round it up or 5:11 down depending on what we're getting with 0.5 or whatever, pretty cool. 5:13 This is a really neat way of doing your averages and of adding on extra fields. 5:19 And that's how to add extra data to model Serializer. 5:26 While the example I gave works, there is a flaw in this implementation. 5:29 Maybe you caught it. 5:33 Every time a course API view is requested, each course instance that's displayed 5:34 is going to call that method I created and generate an average. 5:38 Which means the database gets hit and some calculations has to be done. 5:41 That's not really ideal, is it? 5:44 This might not seem like a big deal 5:47 because there isn't a lot of data at this point. 5:48 Down the road though, I could be querying hundreds of thousands of records. 5:50 It'd probably be better, at least for this example, to add an average rating field to 5:54 the course model and store a calculated average. 5:58 When a new review is added by a user, 6:01 I could use Django's signals feature to a method similar to get average rating, 6:02 calculate the new average, and save it to the course. 6:06 Then the average rating is 6:09 just another field in the model that would get serialized. 6:10 No calculation to be done on the fly. 6:12 This is a great example of why it's important to understand the overhead 6:14 that even small changes like this can add. 6:17 Speaking of flying, I think that about does it for Django Rest Framework. 6:20 You can now go out and build APIs with all the power of Django. 6:24 I can't wait to see what sorts of sites and apps you build with this new power. 6:27 I'll see you soon. 6:30
You need to sign up for Treehouse in order to download course files.Sign up