1
00:00:05,260 --> 00:00:06,480
Welcome back everyone.

2
00:00:06,490 --> 00:00:09,470
Now that we've created our models for users and blog posts.

3
00:00:09,670 --> 00:00:13,630
Let's start by filling out our templates and views for users.

4
00:00:13,630 --> 00:00:18,820
The first thing you do to tackle on users is to actually create the forms that users are going to use

5
00:00:19,120 --> 00:00:21,320
to both log in and register.

6
00:00:21,340 --> 00:00:24,710
Then we'll also create a form for updating user information.

7
00:00:24,940 --> 00:00:27,520
Let's get started by heading over to our project.

8
00:00:27,550 --> 00:00:30,880
All right here we are at the models up-I file that we just created.

9
00:00:30,880 --> 00:00:35,200
Remember we created a user class as well as a blog post class.

10
00:00:35,200 --> 00:00:38,690
Let's get started by setting up the user component of our website.

11
00:00:38,800 --> 00:00:44,950
So we're going to come to our users directory and remember we already created a forms that PI file underneath

12
00:00:44,980 --> 00:00:50,050
the users directory and Ismaili where we're going to be filling out during this lecture.

13
00:00:50,050 --> 00:00:54,060
After this we can begin set up views and templates for users.

14
00:00:54,070 --> 00:01:02,270
The first thing going to do is start by saying from flask WTS import a flask form.

15
00:01:02,270 --> 00:01:05,520
Remember we use this flask form to create our form classes.

16
00:01:06,430 --> 00:01:14,190
Then after that we're all safe from W.T. forms import and the field we'll be using is a String Field

17
00:01:15,860 --> 00:01:19,930
a password field and a submit field.

18
00:01:19,990 --> 00:01:29,890
Then we're also going to have some validators say from W. T.F. forms the validators import data required

19
00:01:30,820 --> 00:01:37,780
e-mail an equal to so data required we'll make sure that that actual input box in the form is filled

20
00:01:37,780 --> 00:01:38,260
out.

21
00:01:38,420 --> 00:01:43,870
Email make sure it's a legitimate email so it has an at symbol hands and a dot com or the org that sort

22
00:01:43,870 --> 00:01:49,210
of thing and then equal to will be using to confirm the user's password.

23
00:01:49,330 --> 00:01:52,090
Then we also may want to raise validation errors.

24
00:01:52,090 --> 00:02:04,630
So if you want to do that we'll say from W-2 forms import a validation error then we'll say from flask

25
00:02:05,140 --> 00:02:12,400
underscored WITF dot file import file field and file allowed.

26
00:02:12,400 --> 00:02:19,900
So a file field file allowed are going to let us have the user actually up the AP N-G or JPEG file in

27
00:02:19,900 --> 00:02:23,990
order to have their profile picture displayed.

28
00:02:23,990 --> 00:02:26,920
OK so those are form based imports.

29
00:02:26,930 --> 00:02:35,840
We also have some user based imports will add in from flask underscore loggin import current user and

30
00:02:35,840 --> 00:02:41,580
then from puppy company blog thought models in poor user.

31
00:02:42,080 --> 00:02:42,590
OK.

32
00:02:42,770 --> 00:02:44,830
So a bunch of imports here.

33
00:02:44,840 --> 00:02:48,830
These first five lines those are for things related to forms.

34
00:02:48,890 --> 00:02:53,660
These second ones right here eight those are going to be things related to users.

35
00:02:53,720 --> 00:02:58,900
So let's start off with the simplest form that's going to be a lock in a form.

36
00:02:58,960 --> 00:03:04,430
So let me collapse this guy and let's imagine the users already registered now they just want to log

37
00:03:04,430 --> 00:03:11,080
in will create a log and form that can fill out and will inherit from flask form and all they need to

38
00:03:11,080 --> 00:03:15,440
provide when they're logging in is their e-mail their password and then hit submit.

39
00:03:15,460 --> 00:03:23,940
So here will say e-mail is equal to a string field and will have the label be e-mailed and then the

40
00:03:23,940 --> 00:03:29,960
validators we're going to say remember you passed it as a list will say data required.

41
00:03:29,970 --> 00:03:31,450
Open close parentheses.

42
00:03:31,530 --> 00:03:35,770
They actually are required to provide e-mail and will say e-mail.

43
00:03:35,790 --> 00:03:43,530
That means their input must also be a standard e-mail address then all say password.

44
00:03:43,530 --> 00:03:46,870
So they're going to provide a password that will be the password field.

45
00:03:47,340 --> 00:03:53,930
Well it's called the label password and then the validators here is just going to be data required.

46
00:03:53,990 --> 00:03:56,420
So they must provide a password as well.

47
00:03:56,460 --> 00:04:00,130
And remember we're not actually going to save that user's password.

48
00:04:00,260 --> 00:04:03,990
We're just hashing it and then comparing it to the hash version we save.

49
00:04:04,070 --> 00:04:09,410
So the actual streaming text we don't save we only save the hash version and then finally after password

50
00:04:09,410 --> 00:04:11,320
they're gonna be able to submit this.

51
00:04:11,480 --> 00:04:15,640
So we'll say submit field and here we can just say something like.

52
00:04:15,650 --> 00:04:18,340
Log in for that particular button.

53
00:04:18,410 --> 00:04:18,710
OK.

54
00:04:18,710 --> 00:04:21,400
So that's our log in form after that.

55
00:04:21,500 --> 00:04:31,370
Let's go ahead and create our registration form so we'll say registration form flask form and so we're

56
00:04:31,380 --> 00:04:35,400
going to look a little similar We're going to have a couple of other things here like checking the e-mail

57
00:04:35,640 --> 00:04:37,770
and checking the user name provided.

58
00:04:37,770 --> 00:04:43,530
So we'll say e-mail and sex are going to be the exact same thing as above.

59
00:04:43,530 --> 00:04:44,080
So we'll see.

60
00:04:44,070 --> 00:04:52,490
E-mail go ahead and copy that paste that in and then we'll also have a similar thing for username so

61
00:04:52,490 --> 00:04:55,160
we'll say user name is equal to.

62
00:04:55,440 --> 00:05:00,880
And then I'm just going to copy and paste the string field here and I'm going to do a couple of adjustments.

63
00:05:00,900 --> 00:05:03,590
One doesn't need to be an email since it's a user name.

64
00:05:03,870 --> 00:05:06,040
And second I don't want the label to be email.

65
00:05:06,360 --> 00:05:09,480
I want it to be user name.

66
00:05:09,650 --> 00:05:10,000
OK.

67
00:05:10,160 --> 00:05:14,780
So we have the e-mail that they registered with the user name they're registered with and then the password

68
00:05:14,780 --> 00:05:16,010
they're going to register with.

69
00:05:16,280 --> 00:05:24,490
And we're going to say copy password field and then stick that in and we want them to confirm their

70
00:05:24,490 --> 00:05:29,220
password because we don't want the users to actually mess up their password input.

71
00:05:29,530 --> 00:05:34,740
So to create another field here called Pass underscore confirm.

72
00:05:35,050 --> 00:05:40,780
And that's also going to be a password field except here are the labels going to be confirm password

73
00:05:42,660 --> 00:05:48,980
and then the validators is going to be data required.

74
00:05:48,980 --> 00:05:55,250
The next thing I want to do is actually link past confirm to password to make sure these to match and

75
00:05:55,250 --> 00:06:04,500
the way we do that is in the validators for the password we're going to passen equal to and then say

76
00:06:04,950 --> 00:06:08,090
pass underscore confirm.

77
00:06:08,140 --> 00:06:10,230
Notice how I do that as a string here.

78
00:06:10,350 --> 00:06:16,650
So that basically says that your first password here has to be equal to the pass confirm attribute there.

79
00:06:16,710 --> 00:06:18,510
OK so that's the equal to.

80
00:06:18,510 --> 00:06:21,320
Remember we're still past that into the list of validators.

81
00:06:21,480 --> 00:06:25,200
And if you want you can also pass on a message to this display in case they mess that up.

82
00:06:25,380 --> 00:06:34,740
So I can say something like a message is equal to passwords must match.

83
00:06:34,840 --> 00:06:35,820
We'll save that.

84
00:06:36,040 --> 00:06:36,390
OK.

85
00:06:36,400 --> 00:06:40,360
So we have the basic attributes email username password pass confirm.

86
00:06:40,630 --> 00:06:45,910
And then we want to do is check the email and the username and make sure someone already hasn't taken

87
00:06:45,910 --> 00:06:49,990
the e-mail or username because remember right now they're registering.

88
00:06:50,170 --> 00:06:52,500
So add two methods here.

89
00:06:52,570 --> 00:06:55,200
One is going to be called check email.

90
00:06:55,390 --> 00:07:05,110
They'll say self and then they'll take in field and we're going to do is say if user.

91
00:07:05,280 --> 00:07:11,270
So again this user right here that's what we imported from puppie company model or excuse me the puppy

92
00:07:11,310 --> 00:07:15,570
company blog that models so that models that py file the Hazar user model.

93
00:07:15,570 --> 00:07:16,900
That's what I'm importing here.

94
00:07:17,100 --> 00:07:18,210
So I'm saying OK.

95
00:07:18,290 --> 00:07:31,860
That model if I were to queery it and say filter by email equal to field data and then say the first

96
00:07:34,320 --> 00:07:40,830
I'll raise an error or something I say raise a validation error and then I can have a message display

97
00:07:40,830 --> 00:07:46,080
here and say your email has been registered.

98
00:07:47,050 --> 00:07:48,150
Already.

99
00:07:48,730 --> 00:07:57,070
So all this does is when someone is registering and their email if we actually query our users and then

100
00:07:57,100 --> 00:08:03,280
filter it by making sure that email is the field data and we grab the very first one if that happens

101
00:08:03,280 --> 00:08:08,890
to exist meaning it's not returning a nun then that e-mails already been registered and we're going

102
00:08:08,890 --> 00:08:10,890
to do a very similar thing for the username.

103
00:08:10,930 --> 00:08:17,860
So similar in fact they can just copy this and paste it here and a set of check email we're just going

104
00:08:17,860 --> 00:08:27,160
to say check username self-field user query and then instead of email here we're going to say by user

105
00:08:27,180 --> 00:08:35,780
name equal to field data first and then here will say your user name has been registered already.

106
00:08:36,100 --> 00:08:36,740
OK.

107
00:08:37,000 --> 00:08:42,460
So here we're checking for e-mail making sure it's unique across our users as well as a user name making

108
00:08:42,460 --> 00:08:44,390
sure that's unique across our users.

109
00:08:44,440 --> 00:08:50,980
If we don't do that then we'll have difficulties assigning blog posts to a particular email or a particular

110
00:08:50,980 --> 00:08:54,970
user that will cause some possibility of errors there.

111
00:08:54,970 --> 00:08:55,410
All right.

112
00:08:55,720 --> 00:09:01,960
So after that we want to do is add in the ability to update the user form and when they up a user form

113
00:09:02,100 --> 00:09:07,230
will add in the ability for them to actually have their own profile picture.

114
00:09:07,240 --> 00:09:16,740
So let's continue we're going to create one last class here called up the user form and it's going to

115
00:09:16,740 --> 00:09:21,110
take in a flask form and here will say e-mail.

116
00:09:21,130 --> 00:09:24,810
And in fact we're going to copy basically what we had in the registration.

117
00:09:25,060 --> 00:09:29,150
So they'll be able to provide an e-mail and a user name.

118
00:09:29,470 --> 00:09:33,320
So we're going to copy that person in here.

119
00:09:33,320 --> 00:09:37,230
So when they want to update their e-mail or update their user name that's possible for them.

120
00:09:37,520 --> 00:09:41,440
And then we're also going to add in is the ability to update their picture.

121
00:09:41,650 --> 00:09:44,530
So the picture is going to be a default picture.

122
00:09:44,560 --> 00:09:50,350
And if you take a look back at the models that Pif file notice again the profile image is actually just

123
00:09:50,410 --> 00:09:54,040
a default profile image that we're going to supply it later on.

124
00:09:54,310 --> 00:10:00,040
So if we come back the forms up high if we go to the update page we want them to be able to update.

125
00:10:00,580 --> 00:10:10,030
So we're going to say a file field and we'll say up the profile picture and here we're going to have

126
00:10:10,030 --> 00:10:15,640
the validators we're going to put a list in here and we can call file allowed.

127
00:10:16,210 --> 00:10:20,030
And this is where you can actually pasan a list of files here.

128
00:10:20,030 --> 00:10:25,300
So my use of validators itself is a list and then files allowed.

129
00:10:25,300 --> 00:10:28,620
Or excuse me file allowed as a parameter.

130
00:10:28,630 --> 00:10:31,320
The very first thing it takes in is the list itself.

131
00:10:31,330 --> 00:10:36,760
So then we're going to say JP for JPAC and Angie.

132
00:10:36,940 --> 00:10:40,620
So that way they can't upload an excel file or some other type of file.

133
00:10:40,700 --> 00:10:45,470
We're going to say it has to end in a jpeg or a PMG in order for you to upload it.

134
00:10:45,740 --> 00:10:46,160
OK.

135
00:10:46,360 --> 00:10:51,580
So that's going to be this picture is just a file field and then we'll allow them to submit.

136
00:10:51,800 --> 00:11:00,940
So will say submit is equal to a submit field and then we'll say update let's make sure we actually

137
00:11:00,940 --> 00:11:02,780
added a submit for registration.

138
00:11:02,960 --> 00:11:03,760
And I think we did.

139
00:11:03,760 --> 00:11:05,320
So let's put that in as well.

140
00:11:05,680 --> 00:11:10,290
We'll say after they've confirmed their password they can submit.

141
00:11:10,300 --> 00:11:19,070
So say submit is equal to a submit field and Ill just say let's register OK.

142
00:11:19,070 --> 00:11:19,830
Save that.

143
00:11:20,010 --> 00:11:23,300
So they're able to submit and they're able to update.

144
00:11:23,370 --> 00:11:27,510
Now what we want to do is make sure that if they're updating their e-mail and user name that they don't

145
00:11:27,570 --> 00:11:30,830
XLE update it to something that also already exists.

146
00:11:30,840 --> 00:11:35,010
So that means we're going to do the same checks here for check email and check username.

147
00:11:35,010 --> 00:11:39,890
Not only do we do that on registration but we also do that if they want to update their information.

148
00:11:39,960 --> 00:11:42,180
So we just copy and paste those as well.

149
00:11:42,330 --> 00:11:43,260
Save that.

150
00:11:43,590 --> 00:11:44,050
OK.

151
00:11:44,220 --> 00:11:46,020
So that's it for the forms.

152
00:11:46,020 --> 00:11:50,450
What I want to show you now is how we're actually going to be handling images and to do that.

153
00:11:50,520 --> 00:11:56,910
We're going to be creating a picture handler that PI script which is going to use the P L library or

154
00:11:56,910 --> 00:12:01,740
pill library which you can get with Pipp install pillow which should already be in your requirements

155
00:12:01,740 --> 00:12:05,850
a text file but that allows us to actually handle images with Python.

156
00:12:06,060 --> 00:12:08,960
So what I'm going to do is expand this.

157
00:12:09,030 --> 00:12:13,440
Remember we're creating the users that's going to hold everything related to users.

158
00:12:13,440 --> 00:12:21,420
Right now we have in forms and views I'm going to create a new file here and call it picture underscore

159
00:12:22,100 --> 00:12:25,020
händler dot pi.

160
00:12:25,020 --> 00:12:31,650
So again this is the picture underscore handler that PI file and it's underneath users.

161
00:12:31,650 --> 00:12:36,240
So if you go to users forward slash you should be able to find that file we just created.

162
00:12:36,510 --> 00:12:42,780
And this is going to be the file that essentially allows us to upload pictures so that we're going to

163
00:12:42,840 --> 00:12:49,920
import os for the operating system and we'll save from p i l in poor image.

164
00:12:49,950 --> 00:12:54,210
And if you get an error later on when you're trying to run it says Paille not found.

165
00:12:54,210 --> 00:12:59,610
Make sure you actually install it with a pip install the case you haven't already then will save from

166
00:12:59,610 --> 00:13:00,620
flask.

167
00:13:00,630 --> 00:13:03,010
Import your URL for.

168
00:13:03,300 --> 00:13:07,770
And we're also going to import current app something we haven't seen before and we're going to create

169
00:13:07,770 --> 00:13:16,440
a function here that allows a user to actually add a profile pic sorgen say add profile pic and we're

170
00:13:16,440 --> 00:13:23,380
going to have a picture upload that's passed Paston as well as a username that's passed in.

171
00:13:23,580 --> 00:13:25,660
So we're going to grab the file name.

172
00:13:25,740 --> 00:13:28,150
We're going to say filename is equal to.

173
00:13:28,460 --> 00:13:33,750
And that pic upload one of the features is going to have the actual name of the file.

174
00:13:33,900 --> 00:13:38,890
So when you grab a file on your computer it may be like your picture that jpeg.

175
00:13:39,030 --> 00:13:42,570
When you upload it that your picture name is the filename.

176
00:13:42,570 --> 00:13:44,120
So we have the file name there.

177
00:13:45,130 --> 00:13:47,690
And what I want to do is now grab the extension type.

178
00:13:47,710 --> 00:13:59,530
So what I'm going to do is say that the extension type is equal to filename split on the dots and then

179
00:13:59,530 --> 00:14:01,510
grab that last item.

180
00:14:01,510 --> 00:14:03,400
So what does this actually mean.

181
00:14:03,400 --> 00:14:09,390
Well let's imagine this you're going to be uploading something that looks like this my picture.

182
00:14:09,400 --> 00:14:10,700
Da Jay peg.

183
00:14:10,870 --> 00:14:13,240
So this is what saved right now as a file name.

184
00:14:13,240 --> 00:14:14,440
That's just a string.

185
00:14:14,530 --> 00:14:20,830
We're going to end up splitting on that dot and then grabbing that last string which in this case is

186
00:14:20,830 --> 00:14:22,550
just jpeg.

187
00:14:22,600 --> 00:14:27,940
So that way I know if it's a jpeg or TNG which will be important when we want to actually check the

188
00:14:27,940 --> 00:14:29,680
file types later on.

189
00:14:30,910 --> 00:14:32,500
So I have the extension type.

190
00:14:32,710 --> 00:14:35,980
So then the actual storage file name.

191
00:14:36,010 --> 00:14:42,310
I'm going to be using is I'm going to convert the user name to a string just in case it's not already

192
00:14:43,030 --> 00:14:49,180
and then I'm going to concatenate it with a dot and then concatenate it with the extension type that

193
00:14:49,180 --> 00:14:50,420
was provided.

194
00:14:50,500 --> 00:14:56,050
So that means that if someone upload something called My picture that they pay We're going to be saving

195
00:14:56,050 --> 00:15:04,390
it as that person's user name dot Jay peg or dot P and G whatever the extension type happens to be essentially

196
00:15:04,390 --> 00:15:11,130
converting their upload into a unique user name that jpeg or thought PAGG file.

197
00:15:11,140 --> 00:15:15,860
Now if you don't like actually storing people's usernames you think that's kind of a security issue.

198
00:15:15,910 --> 00:15:18,650
You can go ahead and just give them some sort of random hash.

199
00:15:18,710 --> 00:15:23,390
But we want to make sure we don't have any conflicts with our actual jpeg or PNB files.

200
00:15:23,500 --> 00:15:26,960
Otherwise people would have the same profile image.

201
00:15:27,170 --> 00:15:32,620
And now we're almost done once we have the storage file name we're just going to create a file path

202
00:15:32,620 --> 00:15:40,600
to save it to will see a file path is equal to OS path join and then say grab the current applications

203
00:15:40,690 --> 00:15:53,650
root path and then we're going to join it with static forward slash profile underscore pick's and then

204
00:15:53,680 --> 00:15:57,400
Khama the storage file name.

205
00:15:57,470 --> 00:16:02,210
So what that does is it basically says OK grab the root path of your current application.

206
00:16:02,210 --> 00:16:07,490
In my case that would be like puppy company blogger class examples and then look for static profile

207
00:16:07,490 --> 00:16:07,850
pics.

208
00:16:07,850 --> 00:16:10,300
Remember we have a static folder here.

209
00:16:10,400 --> 00:16:16,210
We're going to go ahead and create a new folder here that corresponds to the profile underscore pick's

210
00:16:16,220 --> 00:16:18,320
folder we just created underneath static.

211
00:16:18,320 --> 00:16:22,130
I now have profile pics and then it's going to store the storage file name.

212
00:16:22,130 --> 00:16:24,110
So that's the entire file path.

213
00:16:24,860 --> 00:16:28,880
And then we want to do is make sure everything's the same size.

214
00:16:28,970 --> 00:16:34,730
So I'm going to say output size is equal to I'll say 200 by 200 pixels you can feel free to play around

215
00:16:34,790 --> 00:16:35,650
that size.

216
00:16:35,930 --> 00:16:38,170
And then I'll take the pick.

217
00:16:39,060 --> 00:16:42,470
Say image opened the picture up blue.

218
00:16:42,520 --> 00:16:45,920
So that was the pic upload that the user provide in.

219
00:16:46,150 --> 00:16:49,470
I'll say pick thumbnail.

220
00:16:49,940 --> 00:16:55,240
So thumbnail is just a specialized method that allows you to kind of squeeze it into whatever pixel

221
00:16:55,240 --> 00:16:56,220
size you want.

222
00:16:56,260 --> 00:17:01,190
So in that case I'll squeeze it into this output size and then I will say this.

223
00:17:01,240 --> 00:17:10,370
So say pick save file path and then I'm going to return the storage file name.

224
00:17:10,400 --> 00:17:10,830
All right.

225
00:17:11,060 --> 00:17:16,370
So we're going to be using this entire function later on in our views that we're going to be dealing

226
00:17:16,370 --> 00:17:17,920
with in the very next lecture.

227
00:17:17,960 --> 00:17:20,930
But let's go ahead and go over everything we've done so far.

228
00:17:21,290 --> 00:17:24,850
And let's zoom out so we can kind of get the main idea here.

229
00:17:24,950 --> 00:17:25,630
OK.

230
00:17:25,640 --> 00:17:28,050
So we'll first start off with the forms.

231
00:17:28,060 --> 00:17:33,350
Nothing too complicated here essentially just a bunch of imports and then we created a log in form e-mail

232
00:17:33,350 --> 00:17:39,290
password a registration form to special things going on here the password and past confirm as well as

233
00:17:39,290 --> 00:17:42,190
checking user names and e-mails to make sure they're unique.

234
00:17:42,200 --> 00:17:44,010
And there have been already registered.

235
00:17:44,180 --> 00:17:49,480
And then we have this update user form where we have e-mail user name the ability to up the picture.

236
00:17:49,580 --> 00:17:53,630
We check for which files are allowed and then we also want to check their email and username if they

237
00:17:53,630 --> 00:17:55,680
decide to update those as well.

238
00:17:55,700 --> 00:18:01,640
Now in order to make the pictures and have that work in conjunction with both of the user form and the

239
00:18:01,640 --> 00:18:05,990
views that we're going to be creating later we have to create this picture handler function right here

240
00:18:06,260 --> 00:18:07,570
and we haven't used this yet.

241
00:18:07,580 --> 00:18:09,490
We haven't used ad profile pic.

242
00:18:09,500 --> 00:18:13,130
We're going to be using it when we actually create the views for the user.

243
00:18:13,130 --> 00:18:17,810
All this does is basically take that picture upload from the user as well as that current user name

244
00:18:18,110 --> 00:18:25,370
and then assigns that new file a file name sets it to a thumbnail size and then saves it and returns

245
00:18:25,370 --> 00:18:27,920
back the actual storage file name.

246
00:18:28,270 --> 00:18:28,780
OK.

247
00:18:29,600 --> 00:18:31,060
So that's it for this lecture.

248
00:18:31,070 --> 00:18:36,060
Coming up next we're going to continue our building out of users by building out the views for them.

249
00:18:36,290 --> 00:18:37,340
We'll see you at the next lecture.
