1
00:00:00,950 --> 00:00:06,140
Hey, welcome to this new lecture, and this should be the last lecture of this section.

2
00:00:06,710 --> 00:00:13,730
Now, this is a bonus lecture in that in this lecture, we're not going to work on our web applications,

3
00:00:13,730 --> 00:00:15,530
so we're not going to improve it further.

4
00:00:15,980 --> 00:00:23,180
So this is not related to the application that we built, but it is related to Web applications and

5
00:00:23,180 --> 00:00:25,490
we're talking about Flask web applications.

6
00:00:25,860 --> 00:00:33,020
And what I wanted to do is I wanted you to learn how to have a visitor, a user of your Web application

7
00:00:33,020 --> 00:00:37,480
to upload and download files from your Web app.

8
00:00:37,970 --> 00:00:39,930
And that's what I'm going to do in this lecture.

9
00:00:40,310 --> 00:00:47,600
I'll show you how to quickly add an input where the user can submit a file and then how to handle that

10
00:00:47,600 --> 00:00:54,260
file in Flask and also how to let the user download a byproduct of that file.

11
00:00:54,890 --> 00:00:56,930
So uploading, processing and downloading.

12
00:00:57,310 --> 00:01:04,400
And I've got to sample files in here, as you can see in green, and they are colored in green, because

13
00:01:04,400 --> 00:01:12,290
here we got this git repository and these files haven't been uploaded to Heroku and Atom is smart enough

14
00:01:12,290 --> 00:01:13,540
to let you know about that.

15
00:01:14,600 --> 00:01:20,040
So I'm going to use this text file, and csv file to upload them to our Web App and then download them.

16
00:01:20,900 --> 00:01:29,790
So first of all, you need to modify your index.html file.
At the moment

17
00:01:30,260 --> 00:01:31,280
what we've got,

18
00:01:33,620 --> 00:01:38,540
so let me run this virtual scripts, activate

19
00:01:41,680 --> 00:01:42,640
python app.py.

20
00:01:42,800 --> 00:01:43,370
That's fine.

21
00:01:44,690 --> 00:01:52,520
And then go to the browser, reload control R, and yeah what I'm going to do now is instead of having this

22
00:01:52,520 --> 00:01:56,230
text input, I'm going to have a file input there, which is quite easy.

23
00:01:59,030 --> 00:02:07,040
I'm just going to delete one of the inputs and this one here, and yeah inputs.

24
00:02:07,040 --> 00:02:13,040
We don't need the title, neither a placeholder and this time we don't have an email type.

25
00:02:13,040 --> 00:02:16,780
We have a file type. Name?

26
00:02:16,790 --> 00:02:20,690
Let's call it file required.

27
00:02:21,400 --> 00:02:24,980
That doesn't matter much. You need to pass here

28
00:02:25,970 --> 00:02:27,290
an encryption type.

29
00:02:27,920 --> 00:02:32,490
Which should be multipart/form-data just like that.

30
00:02:33,290 --> 00:02:37,160
So that is necessary to be able to handle this file in flask.

31
00:02:38,120 --> 00:02:47,240
If I save this now and go to the Webpage, oh, we've got this Choose file input there, which will

32
00:02:47,240 --> 00:02:48,890
allow us to pass

33
00:02:51,630 --> 00:02:58,140
a file input, so like that, however, for now, if we press submits, we're going to get an error

34
00:02:58,140 --> 00:03:03,320
probably and that underlies we want to handle this file in Flask now, in Python.

35
00:03:03,350 --> 00:03:04,710
So we want to read that file.

36
00:03:05,700 --> 00:03:08,400
So let's go back to our app.py

37
00:03:08,400 --> 00:03:09,790
file.

38
00:03:09,930 --> 00:03:10,080
Yep.

39
00:03:11,700 --> 00:03:16,170
And here again, we're talking about post requests.

40
00:03:16,170 --> 00:03:19,280
So the user is sending data to our Web application.

41
00:03:20,250 --> 00:03:21,830
So, yeah, this should be fine.

42
00:03:22,290 --> 00:03:24,180
The name of the function is success.

43
00:03:24,390 --> 00:03:26,120
And here we are.

44
00:03:26,150 --> 00:03:27,720
We're using the URL for success.

45
00:03:28,470 --> 00:03:29,400
That's perfect.

46
00:03:29,800 --> 00:03:37,350
And you know, what we want to change here is instead of requesting the form, you want to request files here,

47
00:03:37,350 --> 00:03:46,410
and then in here, you need to pass the name of inputs from your HTML template.

48
00:03:46,650 --> 00:03:50,640
So this here, a file here and file there.

49
00:03:51,370 --> 00:03:52,540
Uh, that's good.

50
00:03:53,040 --> 00:03:53,850
We don't need this.

51
00:03:54,810 --> 00:03:59,850
I'm just using my Web application for the sake of having a ready made structure.

52
00:03:59,850 --> 00:04:01,410
So I'm just making use of the structure.

53
00:04:01,410 --> 00:04:07,490
I'm not interested on databases or whatever, so I'm just going to clean this.

54
00:04:07,520 --> 00:04:07,970
Hmm.

55
00:04:08,340 --> 00:04:11,640
We don't need this database code.

56
00:04:13,620 --> 00:04:15,870
Just delete that and.

57
00:04:17,420 --> 00:04:23,760
The return should be here and maybe changes to file instead of email.

58
00:04:24,560 --> 00:04:31,400
I know what we're doing is we check if the request is a post request, and then we get the file

59
00:04:31,400 --> 00:04:39,440
and we store it in this file variable and then we render the template success.html.

60
00:04:41,390 --> 00:04:47,930
So if request is post, we render that template and let's keep it simple and remove these other lines

61
00:04:47,930 --> 00:04:48,320
in there.

62
00:04:48,890 --> 00:04:57,740
So I'm just going to render a success.html and maybe I want to show you what this file is.

63
00:04:57,740 --> 00:05:04,970
So print(file )and also print the file type, print(type(file)).

64
00:05:07,430 --> 00:05:11,450
And I'm going to the Web application, reload once.

65
00:05:11,450 --> 00:05:16,670
It's working, choose a file sample.txt, submit.

66
00:05:19,660 --> 00:05:23,950
We seem to have gotten an error there, it says, to fix this error

67
00:05:23,980 --> 00:05:29,170
you should provide encryption type multipart. Yeah, but we did provide that.

68
00:05:29,650 --> 00:05:34,440
Let me go and double-check the index.html form. Oh, no!

69
00:05:35,560 --> 00:05:42,010
I seem to have passed this in here. Sorry, this should be passed in the form.

70
00:05:44,920 --> 00:05:45,810
So just there.

71
00:05:47,050 --> 00:05:48,880
And let me try out again.

72
00:05:52,390 --> 00:06:01,920
Reload, choose a file, and sample.txt submmit and the success page will surrender successfully.

73
00:06:01,930 --> 00:06:05,900
But let's check our terminal, what it says.

74
00:06:05,930 --> 00:06:08,620
We've got this, and we printed out file.

75
00:06:10,800 --> 00:06:18,090
And this is what we got so: FileStorage: 'Sample.csv' and it says that the application that handles

76
00:06:18,090 --> 00:06:18,700
those files.

77
00:06:19,290 --> 00:06:26,790
Now, we also got this file type and we see that this is a special file storage type.

78
00:06:27,330 --> 00:06:30,030
So it's not a simple file object.

79
00:06:30,640 --> 00:06:34,240
However, you can handle that as a python object, actually.

80
00:06:35,220 --> 00:06:45,150
And what I mean by that is, you know, if you go to your script again and if you want now, you can

81
00:06:45,150 --> 00:06:54,180
apply a file that read method to the file and let's do that in a variable and then print out

82
00:06:57,270 --> 00:06:57,810
the variable.

83
00:06:59,400 --> 00:07:01,920
And let's go to our Web application again.

84
00:07:02,400 --> 00:07:03,150
Success.

85
00:07:03,550 --> 00:07:04,030
Hmm.

86
00:07:04,590 --> 00:07:06,120
Choose file.

87
00:07:06,120 --> 00:07:16,820
Sample.txt, submit, yeah, successes is rendered again, and this time you see this is a text of the csv file.

88
00:07:17,160 --> 00:07:20,070
So we've got some data in there.

89
00:07:20,070 --> 00:07:24,660
It starts from here: address, area, beds, fullbaths, halfbaths, locality.

90
00:07:24,930 --> 00:07:25,200
Yeah.

91
00:07:25,200 --> 00:07:32,690
So this is basically the data that we got from the Web scrapping project, and that's about reading

92
00:07:33,450 --> 00:07:33,860
now.

93
00:07:33,870 --> 00:07:37,650
Now let's see how we go about writing to our file.

94
00:07:38,670 --> 00:07:43,830
Well, to do that, you'd have to save the file in your directory first.

95
00:07:44,820 --> 00:07:47,790
So let's delete those.

96
00:07:49,650 --> 00:07:57,220
To save your file, you have a save method available to you, to this false storage object, and then

97
00:07:57,270 --> 00:07:59,400
in brackets, you'd say (file), again

98
00:07:59,400 --> 00:08:04,030
you point to your file object and then to the file name methods.

99
00:08:04,680 --> 00:08:11,700
Yeah, so there what this returns the file name of the file that the user submits through

100
00:08:11,700 --> 00:08:16,440
the form, and then Flask will save a file using this file name.

101
00:08:17,650 --> 00:08:25,410
And you can also add something there, uh, let's say another string upload it and then plus the other

102
00:08:25,410 --> 00:08:27,660
string so this is a string,

103
00:08:27,660 --> 00:08:31,020
and this is also a string and we can concatenate them.

104
00:08:31,980 --> 00:08:39,060
So I'll try this again here and choose file again.

105
00:08:39,060 --> 00:08:40,350
Sample.csv.

106
00:08:40,680 --> 00:08:41,330
Submit.

107
00:08:42,750 --> 00:08:48,990
Now, let's see in the directory now we've got this uploaded sample.csv.

108
00:08:52,200 --> 00:08:54,690
And this is the same as sample.csv.

109
00:08:56,910 --> 00:09:02,310
So that's basically how you let the user upload a file to your directory.

110
00:09:04,870 --> 00:09:14,410
Now, something you should know is that it's not safe to use this expression, you want to apply another

111
00:09:14,410 --> 00:09:24,760
method here always, which is secure, full name, and then inside the brackets, you enter this expression.

112
00:09:26,560 --> 00:09:32,950
And what this method will do is it basically secures the file name of the file

113
00:09:32,950 --> 00:09:39,070
that is entered by the user, because, you know, sometimes some users may be hackers.

114
00:09:39,550 --> 00:09:45,780
They might it may send some files that have some sneaky file names, such as, let's say, you know,

115
00:09:45,790 --> 00:09:46,510
something like

116
00:09:49,720 --> 00:09:50,470
that.

117
00:09:51,530 --> 00:10:00,580
So, which will point to your server route, and then they may enter some Bash files that can

118
00:10:00,580 --> 00:10:05,240
do something on your Linux, so on Heroku, if you upload that to Heroku.

119
00:10:06,130 --> 00:10:11,530
And this method secure filename makes sure that this kind of slashes are ignored basically.

120
00:10:11,530 --> 00:10:16,720
So always use that. This is a method.

121
00:10:16,720 --> 00:10:17,950
So we have to import that.

122
00:10:18,250 --> 00:10:21,870
And you do that:

123
00:10:22,150 --> 00:10:27,310
From werkzeug import secure_filename.

124
00:10:33,430 --> 00:10:39,680
You should have this library installed already because this is installed with Flask automatically.

125
00:10:41,140 --> 00:10:45,820
I'll quickly check to make sure that the change I made is correct.

126
00:10:46,540 --> 00:10:57,950
Delete that and try to execute that again from here.
Choose file. Sample.csv. Submit.

127
00:10:58,730 --> 00:11:01,510
And, yeah, let's see it in here, upload it.

128
00:11:01,900 --> 00:11:02,330
Sample.csv again.

129
00:11:02,340 --> 00:11:06,340
Let's see as we again, here it is, great.

130
00:11:06,760 --> 00:11:18,800
And now, once you have that file, you can simply go ahead and open that with ("uploaded" + file.filename).

131
00:11:18,820 --> 00:11:28,450
In write mode as, let's say f, and then f.write.

132
00:11:29,530 --> 00:11:37,590
Or let me open this in apend mode, so that I add another line in there. "This was added later".

133
00:11:38,860 --> 00:11:39,280
Yeah.

134
00:11:39,640 --> 00:11:40,810
That should work.

135
00:11:42,340 --> 00:11:48,350
So let me try this out. Choose file. Sample.csv.

136
00:11:48,350 --> 00:11:55,080
Submit and let's go and check, uploaded.

137
00:11:55,150 --> 00:11:55,690
Sample.csv.

138
00:11:56,560 --> 00:11:56,920
Yeah.

139
00:11:57,040 --> 00:12:03,670
Here is my line and yeah that's how you get files from the visitor, from the user.

140
00:12:04,120 --> 00:12:06,880
And also this is how you can modify them.

141
00:12:07,270 --> 00:12:11,820
Now let's see how you allow the user to download your files.

142
00:12:13,930 --> 00:12:21,340
Well, what I'm going to do is, you know, instead of the success page I want, I'm going to render is

143
00:12:21,550 --> 00:12:29,440
I'm going to render a download button down here, which underlines that I still want to render the index of

144
00:12:29,440 --> 00:12:34,390
the HTML page, but I want to insert this download button in the page.

145
00:12:34,780 --> 00:12:35,800
So how do we do that?

146
00:12:39,330 --> 00:12:50,220
Well, we go here and we say render index.html, but then then we want to render, to create a variable and say

147
00:12:50,220 --> 00:12:58,620
that would be equal to download.html, good and then you go to templates, create new file.

148
00:12:58,950 --> 00:12:59,250
Call it

149
00:12:59,250 --> 00:13:03,990
downloads, download.html.

150
00:13:05,800 --> 00:13:10,380
And here you want to write something like this.
For the sake of keeping

151
00:13:10,380 --> 00:13:14,200
the video short, I pasted something that I wrote earlier.

152
00:13:14,700 --> 00:13:22,370
Yeah, this is an HTML page with a normal text in there and we have a division here.

153
00:13:23,580 --> 00:13:26,940
And then we've got this HTML button in here.

154
00:13:29,910 --> 00:13:32,610
Where the user presses that download button,

155
00:13:33,420 --> 00:13:35,570
this python function will be executed.

156
00:13:35,580 --> 00:13:38,940
So a function named download, which we haven't created yet.

157
00:13:40,620 --> 00:13:42,480
And so that function we will write

158
00:13:42,480 --> 00:13:46,260
the code, the Python code that downloads files.

159
00:13:47,520 --> 00:13:52,740
So at this point, you know, if you if you refresh this, you didn't get the download button right

160
00:13:52,740 --> 00:14:01,170
away because you haven't yet told your indexed e-mail page about you or your download button.

161
00:14:02,480 --> 00:14:14,310
So to do that, you want to insert here under form, you want to insert a jinja placeholder,

162
00:14:14,400 --> 00:14:22,140
jinja2 placeholder where you want to say {%include btn%} for the variable that you created in the Flask

163
00:14:22,860 --> 00:14:23,460
function.

164
00:14:24,150 --> 00:14:30,800
Now, if you save this and go to your webapp, reload, you'll get an error.

165
00:14:31,380 --> 00:14:36,870
And what it says is "TRied to select from an empty list of templates".

166
00:14:39,910 --> 00:14:43,510
So why is Python not being able to find a template?

167
00:14:43,930 --> 00:14:53,980
Well, the reason to that is if you go here, when we reload the webpage, what we're visiting is the

168
00:14:53,980 --> 00:15:00,120
index.html, so this URL and this function is executed.

169
00:15:00,760 --> 00:15:04,050
That function is trying to render the index.html page.

170
00:15:04,390 --> 00:15:14,320
But when you go and here, the index.html page cannot find these empty templates of the 'btn' variable

171
00:15:15,640 --> 00:15:23,650
because the 'btn' variable is not being passed in here but is being passed in this one here, in this render

172
00:15:23,740 --> 00:15:27,110
template function of the success.html page actually.

173
00:15:27,580 --> 00:15:36,160
So you should figure out a way to ignore this 'btn' variable when the user is visiting the index

174
00:15:36,610 --> 00:15:38,770
webpage, the homepage of your website.

175
00:15:40,060 --> 00:15:42,010
And the way to do that is very easy.

176
00:15:42,790 --> 00:15:46,130
You just say 'ignore missing'.

177
00:15:46,850 --> 00:15:56,860
And then you go in here, reload, and the page reloads perfectly, and you can see that the buttom is not

178
00:15:56,860 --> 00:16:01,750
displayed now because you need to display that after the user presses submit.

179
00:16:02,020 --> 00:16:11,050
So when the user presses submit, the success function is executed and the render, and the indexed.html

180
00:16:11,200 --> 00:16:15,610
template is rendered again together with a download.html button.

181
00:16:17,940 --> 00:16:23,020
So the trick here is to include this 'ignored missing'. I didn't include this right away.

182
00:16:23,040 --> 00:16:25,050
I wanted you to understand what this does.

183
00:16:25,530 --> 00:16:27,240
So I hope this is clear now.

184
00:16:27,240 --> 00:16:36,180
And yeah, let me try out the Webpage, choose file, sample.csv, submit.

185
00:16:39,060 --> 00:16:45,770
Yeah, we got an error: 'Could not build url for endpoint "download". Did you mean index instead?'

186
00:16:45,780 --> 00:16:49,230
So what's happening here is, you know what?

187
00:16:49,230 --> 00:16:51,690
When Flask is rendering this template,

188
00:16:52,020 --> 00:17:00,990
it tries to access the download function, but we haven't such a function in the f file.

189
00:17:00,990 --> 00:17:02,910
We need such a function to write the downloading code.

190
00:17:03,210 --> 00:17:14,900
So let's get past this error for now by creating just a dummy function. @app.route ("/download").

191
00:17:16,740 --> 00:17:19,920
And define function with download,

192
00:17:23,730 --> 00:17:24,860
and just pass.

193
00:17:24,870 --> 00:17:35,300
So don't do anything for now just to trick Flask that we actually have a download function, choose

194
00:17:35,340 --> 00:17:46,050
file and sample.txt, submit, download, and here is the sample.html template, which is actually a simple

195
00:17:46,050 --> 00:17:46,610
button.

196
00:17:47,670 --> 00:17:57,450
Now when the user presses download, the download function will be executed, which is this one here.

197
00:17:58,830 --> 00:18:08,820
And now we're ready to write here the downloading code, and that would be send_file and we need to import that

198
00:18:09,240 --> 00:18:10,710
request, send_file.

199
00:18:10,710 --> 00:18:15,090
So that's a method that sends a file to the user via the browser.

200
00:18:15,420 --> 00:18:21,090
And then down here you want to send this string.

201
00:18:23,580 --> 00:18:25,830
So just pass that there.

202
00:18:26,520 --> 00:18:27,300
And

203
00:18:31,800 --> 00:18:37,620
you also need to parse this parameter, which is a file name that you want to give to your file, to

204
00:18:37,620 --> 00:18:39,720
the file that will be sent to the user, actually.

205
00:18:40,590 --> 00:18:45,930
So is basically the same file, but with another name, let's say yourfile.csv.

206
00:18:48,000 --> 00:18:53,390
And finally, you may want to pass as_attachment=True.

207
00:18:53,610 --> 00:18:59,250
So the user actually downloads that file instead of trying to open that in the browser.

208
00:19:01,450 --> 00:19:03,410
And that should do it.

209
00:19:03,790 --> 00:19:06,610
So I'm going to go ahead and try this now.

210
00:19:09,730 --> 00:19:10,710
Choose file.

211
00:19:12,660 --> 00:19:16,860
Sample.txt, submit, download.

212
00:19:18,590 --> 00:19:26,380
Name 'file' is not defined. Yeah, actually name 'file' is not defined because we are inside a function

213
00:19:26,380 --> 00:19:32,060
here and if you look here, file was defined inside another function.

214
00:19:32,830 --> 00:19:37,080
So we're talking about local variables, local variable here, local variable there.

215
00:19:37,750 --> 00:19:40,930
And to get past this problem actually is very easy.

216
00:19:41,380 --> 00:19:50,380
Inside the success function, you want to create a global variable, so you're declaring a global variable.

217
00:19:50,710 --> 00:19:58,180
Now file can be accessed throughout the Python script, and that includes this function.

218
00:19:59,050 --> 00:20:00,310
So let me try this again.

219
00:20:06,960 --> 00:20:08,880
Sample.csv, submit.

220
00:20:10,430 --> 00:20:13,640
Download successful.

221
00:20:15,150 --> 00:20:22,230
So the file name is yourfile.cvs. Yeah, this is a data, so the user submitted a file

222
00:20:22,230 --> 00:20:29,940
that contained only these records, but then what you did is you added this line, saved that file

223
00:20:29,940 --> 00:20:35,280
in your system, in your directory, and then you sent that file back to the user.

224
00:20:36,980 --> 00:20:40,550
And that's what I wanted to show you in this lecture.

225
00:20:40,990 --> 00:20:46,420
I hope you find this useful and actually you're going to need this for the project in this course.

226
00:20:46,750 --> 00:20:48,990
Please get ready for that! In the next session

227
00:20:48,990 --> 00:20:51,970
you're going to get this kind of project.

228
00:20:52,450 --> 00:20:55,270
Hope you enjoy this and I'll talk to you later.

229
00:20:55,480 --> 00:20:56,170
Thanks a lot.

