Django: Getting Started Transcripts
Chapter: Posting Data
Lecture: Writing a view that fills review forms

Login or purchase this course to watch this video and the rest of the course contents.
0:00 Time to write a view for the review. Let me open up views.py.
0:21 And I've started off with the usual header stuff. Note that I'm importing the models for books and reviews as well as that newly created
0:29 form for a review. Now the view signature. The review book view is behind the login wall. You don't want anonymous reviews.
0:44 And it takes an argument, the ID of the book, to review. The first thing it does is try to find the book and it does this using
0:52 the handy get object or 404 shortcut method that you've seen in previous chapters. On line 13, I check what HTTP method was used for this call.
1:13 Everything under the if statement is for post which is for the review submission.
1:19 The first thing I do here is try to see if there is a review object for this user.
1:24 You'll recall that the review object is unique per pair of users and books. The book in the query here is based on what was looked up
1:33 and the user is found in the request object. As this view is login required. You know that that will be a valid user.
1:41 If the review exists, then it is used on line 16 to populate a review form object.
1:48 The fields the user submitted in the post are combined with an instance of a review object to give you a form.
1:56 If the review doesn't exist, the query manager will throw a does not exist exception.
2:02 On line 18, that gets caught and in there the form is created with just the data from the post. By the time the code reaches line 20,
2:18 you've got an instance of a form object, that doesn't mean that data is good. The user might have submitted a rating of 47 out of 5.
2:27 The HTML will stop the user from doing that, but you can't assume that some nefarious person hasn't figured out your code and is sending
2:34 you arbitrary data. It's a nuisance, but you must always check the data on the server side.
2:40 Javascript or form validation in the browser is not sufficient as anyone can create a post and send it to your server.
2:48 The form object has a useful method called is valid. It checks for valid data within the form.
2:54 If the data is okay, for example the validation on the rating passes then you get inside of the if block.
3:01 Normally the forms save method constructs or updates a review object saving the data from the post into the object.
3:09 The extra commit equals false here prevents that from happening. Why would I want to stop that? Well if this is a brand new review for example,
3:20 line 18 ran then you have to specify the user and the book. Which were not included in the post.
3:28 If you'll recall the review form doesn't even have fields for that. There are two ways of dealing with this problem. The first is what I've done here.
3:37 It will create or update the object without saving to the database. And then I manually add the user and book on lines
3:44 22 and 23 then save the whole thing. Alternatively you can create a form that has the user and book information in it and
3:53 hide the fields from the user. The info will still get sent down to the browser and be in the form and then the browser will send it back.
4:01 I prefer not to do it this way because it means you then have to validate that the values of those fields correspond to the user's actual user ID.
4:08 So that's why I used this method. Finally once the review object has been saved the browser needs to show a result.
4:17 What better than to send them to the page where they can see their review. It's bad practice to hard code a
4:23 URL When adding the password reset link to the login page you used the URL template tag to look up a URL by name.
4:31 Did you think you could only do that for Django URLs? Of course not. You can name your own. I'll show you how to do that in a minute.
4:38 The redirect function is a shortcut that returns an http response object with a 302 status code and the URL being redirected to.
4:49 The arguments here to redirect tell it the name of a URL to look up and the arguments for that URL. In this case it will find the URL named book.
4:58 Okay that's the good case, but what if there's an error in the form? This new chunk of code is the bad case.
5:12 I'm still using the review form object based on the post data sent. But now I want to re render the review form page.
5:20 When the is valid method of the form object is called Django automatically annotates the form object with any error information.
5:28 This re rendered page will be able to show the user indicators of what they messed up. In our case, if the user was well behaved,
5:37 they won't be able to mess anything up because the only validation is the rating and if they're using the form that will be correct.
5:44 But you shouldn't assume anything about your users or their behavior. So that's the submission part.
5:50 This might feel a little backwards doing that first. But now let's see how to spit out the form, the get part.
6:10 You should only get to line 36 if the HTTP method was get post was handled in the previous if block. Actually that's a bit of a white lie.
6:20 You could also get here if the method was delete or something else. But this view isn't handling those cases at all.
6:27 So you can just treat anything but post as if it's a get. Unless you're writing a rest interface or something like that.
6:34 You can usually just stick to get and post and ignore everything else. Where was I? Right, So this code is for http get. Hence the comment on line. 35.
6:45 It's kind of similar to the post case in that the goal is the creation of a review form object.
6:51 This time you don't have a post to pre populate the form though. It will either get pre populated with an existing review like on line 38.
7:00 Or if there is no review for this user book pair, you'll get an empty form on line 40.
7:05 The rest is just your typical packet in a data context and call render sort of thing. Let's register this view as a URL.


Talk Python's Mastodon Michael Kennedy's Mastodon