字幕列表 影片播放 列印英文字幕 COLTON OGDEN: All right. Hello, world. This is CS50 on Twitch. My name is Colton Ogden. I'm joined today by-- KAREEM ZIDANE: Kareem Zidane. COLTON OGDEN: So apologies if you've been watching in the live chat. It took us a little bit to get online. We're having some difficulties with a brand new setup. But it looks so far to my eye that everything is currently Livestreaming and looks excellent. Let me go ahead and make sure I'm muting everything here on my laptop that the audio is coming from. So what are you here to talk with us about? You're a regular. You've been in a couple of times. We did like a Travis stream. We did some other stuff. KAREEM ZIDANE: Yup. I think this would be my third stream. Yes. COLTON OGDEN: Nice, you're a regular, a veteran at this point. KAREEM ZIDANE: Yeah, I guess so. COLTON OGDEN: What are you talking about today? KAREEM ZIDANE: We're going to talk a little bit about Flask today, which is a micro web framework. It's used. It's very popular. It's a Python framework. And it's used in a lot of web applications. COLTON OGDEN: Nice, nice. So a lot of people in the chat may have programmed in Python before, but maybe not necessarily in the context of web. KAREEM ZIDANE: Yeah. COLTON OGDEN: So this is kind of like a nice entry level sort of way to get into server side programming with Python would you say-- KAREEM ZIDANE: Yup. Yup. COLTON OGDEN: --as opposed to maybe like something like Django would be another technology that folks might have heard about. KAREEM ZIDANE: You might say that Django is similar in spirit. It's just, I guess, heavier. COLTON OGDEN: Yeah. KAREEM ZIDANE: But I'm not an expert in Django. But, I mean, yeah, it's pretty much the same thing. The job of a web framework in general is, you know, facilitating the process of actually developing a web app or a dynamic web app. COLTON OGDEN: Sure. And this would be server side as opposed to like maybe JavaScript, CSS, HTML, stuff that the web browser actually deals with. KAREEM ZIDANE: We're going to see a little bit of HTML and CSS as well. We're not going to see JavaScript, but you could use JavaScript if you wanted to. Yeah. I mean, I thought I'd make this as simple as possible and as focused as possible. So, yeah, we're going to be focused more on the server side of things today as well as some templating with Jinja. COLTON OGDEN: Cool. Awesome. I can't wait. KAREEM ZIDANE: Yeah. COLTON OGDEN: I'm very excited. We have a few new followers here in the stream, so I'm going to give some shout outs to them. So thank you very much to AFMM01, Negative_Nancy, baffoon9, ZombieRaccoon, [? COBOL ?] [? 2070, ?] [? Hussam ?] [? Farag, ?] and [? Igor ?] [? Voltaic. ?] Thank you so much for following today. KAREEM ZIDANE: Thank you. COLTON OGDEN: I'll transition to your laptop here so we can see what we're working with here today. Yeah. Why don't you get us started here? KAREEM ZIDANE: Cool. So I am inside of my container, yup. And I thought I would start by talking about a little bit of the concepts that were actually a little bit difficult for me to sort of grasp at first when I first started learning about with programming. And some of these concepts is, like, what's a server? What's a client? COLTON OGDEN: Sure, sure. KAREEM ZIDANE: Like how do they communicate with each other? And the basic idea is that a server is a piece of software that is just running, listening for web requests. At once it receives a web request, it parses it, processes it. And then if everything's OK, it responds with some responses we'll soon see. COLTON OGDEN: So some program on somebody's computer somewhere, it's listening for network traffic sort of like bits of data that are sent to it. It processes them and then sends back a response. KAREEM ZIDANE: Exactly, yes. So, yeah, exactly as explained. A client, on the other hand, might be something like a browser which actually initiates or makes a web request and expects a response back from the server and then, you know, does something with that response whether it's, for example, showing some web page and so on. And so we're going to actually see an example of this right now. So let's actually get started. So before we actually start, I just want to explain something about the protocol that's being used in this case. COLTON OGDEN: Sure. KAREEM ZIDANE: It's the HTTP protocol. And it's an example of an application protocol. COLTON OGDEN: OK. KAREEM ZIDANE: And we'll see what that means. But for two pieces of software to communicate with each other, they need to be speaking the same language, right? COLTON OGDEN: Right, yeah. I guess, yeah. KAREEM ZIDANE: Because, you know, if some server's listening for some network traffic or some requests, it expects to receive some data, right? COLTON OGDEN: Yeah. KAREEM ZIDANE: You know, if this data is arbitrary, it's not going to be easy for the server to sort of make sense of it, because it's not a human. COLTON OGDEN: If someone's speaking French and someone's speaking German-- KAREEM ZIDANE: Exactly. COLTON OGDEN: --it's highly unlikely they're going to understand each other if they don't know the other language. KAREEM ZIDANE: And so, yeah, there's an agreed upon language that they both speak. And this language is in the form of the protocol that is called HTTP. And just to be clear, this is not a programming language. COLTON OGDEN: Right. Right, just sort of a standardized way of sending-- basically just communication standard protocol like you said. KAREEM ZIDANE: Exactly. And let's actually see exactly an example of this right now. So I have just one file here called index HTML. And these are the contents. Let me zoom this in a little bit so we can see better. And these are actually the contents of my index HTML, just a simple HTML-- COLTON OGDEN: Right OK. KAREEM ZIDANE: --file. And then I'm going to start an HTTP server to serve this file for me. And then I'm going to make a request. And I'm going to see what I'm sending and what I'm getting back. COLTON OGDEN: OK. KAREEM ZIDANE: Right? COLTON OGDEN: Cool. So HTTP server, what kind of program is that? Does that comes stock on Linux? KAREEM ZIDANE: No, HTTP server is actually a node package. COLTON OGDEN: OK. KAREEM ZIDANE: You can install it. If you have node installed and NPM installed, you can install it using npm install -g http server. COLTON OGDEN: Ah, OK. KAREEM ZIDANE: And it doesn't have to be the HTTP server. It can be any other static web server. But this tool is also actually installed already on labs, and on the sandbox environment, and also on the CS50 IDE. COLTON OGDEN: Can people watching right now get access to one of those sandboxes and mess around with Flask themselves? KAREEM ZIDANE: Definitely. Yeah. If you go to sandbox.cs50.io, you can choose Flask from here. COLTON OGDEN: I plugged it in the chat, everybody, the sandbox.cs50.io link. If you want to mess around with Flask, but not actually have to install it on your physical machine, definitely check that out. Also, lethalshotgg, mdobra71, and [? mansonjai, ?] thank you very much for following. KAREEM ZIDANE: Yup. COLTON OGDEN: We'll have to come back to the chat in just a second. I think maybe once we've gotten started we can read up all the messages. We have a few. We a little bit of a backlog to catch up to. KAREEM ZIDANE: Yup. COLTON OGDEN: But, anyway, you were saying? So we have HTTP server. You set that up using the node package HTTP server. KAREEM ZIDANE: Yes. COLTON OGDEN: So now it's running on your machine. So it's kind of listening forever, right, for network traffic? KAREEM ZIDANE: Correct. Yeah. And for it to be listening, it has to be listening for on some port. COLTON OGDEN: Right. KAREEM ZIDANE: And you can you can think of-- like people often use an analogy for this I think. You know, different ports correspond to sort of different apartment numbers in a building somewhere. COLTON OGDEN: Sure. KAREEM ZIDANE: So different ports are used for different services. And by convention, you know, HTTP servers listen for it should be traffic on port 80, or HTTPS traffic on port 443, or SSH traffic on port 22, and so on. COLTON OGDEN: So Jerry makes pizzas in room 80. And if somebody wants a smoothie, they're going to go to Tom's apartment-- KAREEM ZIDANE: Exactly. COLTON OGDEN: --in room 81. Or I guess, what's the HTTPS? KAREEM ZIDANE: HTTPS 443? COLTON OGDEN: Yeah, they'd go to room 443 instead of room 80 I guess. KAREEM ZIDANE: Yeah, exactly. So, yes, you would be able to send some data to some port whether it's open or not. Maybe you'd get an error if it's not open. If it is open and some other server is listening on that port for different kind of traffic, it's maybe going to give you a bad response, or ignore you at all, or it does whatever it wants to do. COLTON OGDEN: Right. OK. So different ports are reserved for different purposes. KAREEM ZIDANE: Yes. And by default, here HTTP server actually listens on port 8080, as we can see, right? So we're expected to go to whatever IP address of our machine is, [? code ?] [INAUDIBLE] port. COLTON OGDEN: Right. And 127.0.0.1 is usually shorthand for my own computer-- KAREEM ZIDANE: Exactly. COLTON OGDEN: --local host. KAREEM ZIDANE: It's a loopback IP address. It's local host. Yes, it refers to your computer. COLTON OGDEN: Right. I'm actually not as familiar with 172.17.0.2. KAREEM ZIDANE: So it's a little bit complicated. There are multiple IP addresses, because the Docker container that I'm using has a different IP address. COLTON OGDEN: I see. OK. KAREEM ZIDANE: And so right now, it listens on all IP addresses that this container has, which is the local host IP address and the Docker container's IP address. COLTON OGDEN: I see, OK. That's pretty cool. So it makes it accessible from both your computer and Docker? KAREEM ZIDANE: Yes. Yes. COLTON OGDEN: Nice. KAREEM ZIDANE: Kind of. COLTON OGDEN: OK. So you have the server up right now. So it says hit control C to stop it. KAREEM ZIDANE: Yup. COLTON OGDEN: So it's just a regular program, a CLI program. And then now what you're trying to do is test actually getting a response from the server. KAREEM ZIDANE: Yeah. COLTON OGDEN: So that's where you're using Curl. KAREEM ZIDANE: Yeah. I'm just going to make a request to that server. And I'm expecting to get a response from the server. And I don't have to use Curl for this. You can use your web browser. I'm going to show how to do this in your web browser. COLTON OGDEN: Sure. KAREEM ZIDANE: But for now, just for the sake of simplicity, I'm just going to try Curl. And let me resize just a little bit. OK. So local host we said, and then :8080 COLTON OGDEN: OK. KAREEM ZIDANE: And then hit Enter. And if you notice up here, the server actually got something, right? COLTON OGDEN: Right, yeah. KAREEM ZIDANE: It appears to have gotten a-- COLTON OGDEN: Different colored text, too. KAREEM ZIDANE: Exactly. Yeah, get request forward slash, we'll explain what that means in a moment. Let's crawl back up here a little bit and see what our tool actually did. So the first thing that our tool did is open the connection to the server. COLTON OGDEN: Right. KAREEM ZIDANE: Right? And then-- COLTON OGDEN: Curl is kind of like a command line version of using a web browser to go to a you URL almost in a very limited sense? KAREEM ZIDANE: Yeah. Curl is, essentially, a tool that you can use to make-- COLTON OGDEN: Network request-- KAREEM ZIDANE: Requests, yeah. COLTON OGDEN: --generally speaking? KAREEM ZIDANE: Yeah. Let me actually highlight this so that we can see it better. So all of the greater than sign something, this is what is being or what has been sent already. COLTON OGDEN: OK. KAREEM ZIDANE: And everything that follows that's prefixed with a less than sign is actually the response that we got from the server. COLTON OGDEN: Oh, that's cool. OK. Cool. KAREEM ZIDANE: Right? COLTON OGDEN: You can see the direction of the traffic. KAREEM ZIDANE: Exactly. So I highlighted the request parse, so that it's easier for us to see hopefully. And after Curl made a connection to the server, it actually sent these lines that we're seeing right here. COLTON OGDEN: OK. KAREEM ZIDANE: So first line is, you know, get/http/1.1. COLTON OGDEN: OK. KAREEM ZIDANE: And what that means-- so there are different kinds of HTTP requests. COLTON OGDEN: OK. KAREEM ZIDANE: We're going to use a couple of them today, get and post. Get is generally used to sort of retrieve resources or retrieve information from a server. COLTON OGDEN: OK. KAREEM ZIDANE: And in this case, we-- COLTON OGDEN: We're getting some information from the server. KAREEM ZIDANE: Exactly, yes. Literally, yeah, getting some information from server. And in this case, by default, since we didn't specify any path after the 8080/, it's going to try to get index.html. COLTON OGDEN: OK. KAREEM ZIDANE: Right? Or the server is going to try to serve us index HTML by default. COLTON OGDEN: Right. KAREEM ZIDANE: So this says, hey, we're making a get request. And we're requesting the slash resource in this case. Right? COLTON OGDEN: OK. So it's like the route. It's kind of like the beginning of your hard drive almost, but in an abstract sense also related to websites that might have multiple URLs, like facebook.com/users/comments. But this would just be like facebook.com. KAREEM ZIDANE: You may think of it as a path in some structure on your computer. But it's not always the case that this is a path. It can be something arbitrary [? that's ?] mapped for something else behind the scenes. COLTON OGDEN: Yeah. Yeah, with the routing and stuff like that. KAREEM ZIDANE: Exactly, yes. And so the next bit is HTTP/1.1. And what this means is that Curl tries to inform the server that, hey, I'm speaking HTTP version 1.1 just to make sure that they both understand the same version HTTP in this case. COLTON OGDEN: Not a whole lot of versions of HTTP. It looks like they've had a fairly limited number of versions. KAREEM ZIDANE: That's fair, but for the future maybe, like if this changes. COLTON OGDEN: Yeah. Yeah. KAREEM ZIDANE: If some client, or Curl, or browser, or something else-- COLTON OGDEN: Aren't they coming out with HTTP/2? Isn't that a thing? KAREEM ZIDANE: I think it is. I don't know much about that. [INAUDIBLE] COLTON OGDEN: I thought I heard about that at some point, maybe not. KAREEM ZIDANE: Yeah. I don't know much about it unfortunately. I don't know about the differences. So maybe I should look this up after and see. But, anyway, the point is that this sort of tries to ensure that they're both speaking the same version of HTTP, because different versions can have different sort of, I don't know, system of actions, or statements, or sentences that they might not understand. COLTON OGDEN: Sure. KAREEM ZIDANE: And so this just tries to make sure that they're both speaking the same version. COLTON OGDEN: OK. KAREEM ZIDANE: The second line here host:local host 8080, and this is what's called a request header, right? It's additional data or additional metadata sent as part of the request. And it can be useful for some contexts. And the context here is that it's not always the case that you can just have one server running on one machine, on the same machine. In other words, you can have more than one server running on the same machine. COLTON OGDEN: Sure. KAREEM ZIDANE: And this just tries to make sure that, hey, I am looking for the server that's a local host for 8080 specifically. Because there could be another HTTP server listening on 8081 OR 8082 or whatever, right? COLTON OGDEN: Makes sense, yeah. KAREEM ZIDANE: OK. COLTON OGDEN: Like email servers, too. KAREEM ZIDANE: Email servers. COLTON OGDEN: HTTP servers. KAREEM ZIDANE: Usually, you look on port 25 I believe. COLTON OGDEN: Yeah. I think that's right. Yeah. KAREEM ZIDANE: But, yeah, so this tries to make it clear that, hey, I am requesting from this particular server. There's also the context of virtual server. And this is, you know, you can run more than one server on the same machine. COLTON OGDEN: Right. KAREEM ZIDANE: They're called virtual servers. COLTON OGDEN: Makes sense. KAREEM ZIDANE: Because there's also the physical server, the actual hardware server, the computer that it's running. COLTON OGDEN: Like vhosts to with PHP back in the day? KAREEM ZIDANE: Yeah. Exactly. I think the vhost and virtual servers mean the same thing actually. COLTON OGDEN: Yeah, I think they're the same thing. Yeah. KAREEM ZIDANE: The next line here is a user agent. And this is also other request header. And this is just Curl trying to let the server know that, hey, I'm Curl that's making this request, not Chrome, not Firefox, not Safari, not Opera. It's Curl version whatever, 761 whatever if that makes sense. COLTON OGDEN: Yeah. KAREEM ZIDANE: OK. Although, I mean, you can technically sort of change these headers if you want with some custom options if you want. So this doesn't guarantee that the entity or the software that's making the request is actually Curl. I can trick the server into thinking that what's making the [INAUDIBLE] is actually Chrome, or Firefox, or something. COLTON OGDEN: Kind of like how Verizon injected into like mobile traffic its, like, special headers-- KAREEM ZIDANE: Yeah. COLTON OGDEN: --which David talked about it in lecture I think at one point. KAREEM ZIDANE: I'm not sure about Verizon, but I know some internet providers do that as well, like inject some data in the headers sometimes. COLTON OGDEN: Which makes sense. And [INAUDIBLE] is actually asking, "are you guys doing a lecture on Django in the future?" And that's a good question. Maybe in the future. KAREEM ZIDANE: Yeah. COLTON OGDEN: Maybe some Django if people want some Django. [INAUDIBLE] is saying, "Who's teaching who-- the guy on the right asking all the questions." Yeah, I'm very curious about all that Kareem has to teach us today. All right. KAREEM ZIDANE: I'm sure we're all going to learn something today. COLTON OGDEN: Oh, yeah. I'm sure I'm going to learn a lot. So that was all of the request information. And so what's below that is the response information, right? KAREEM ZIDANE: There's actually one more header-- COLTON OGDEN: Oh, I see. KAREEM ZIDANE: --or request [INAUDIBLE]---- COLTON OGDEN: OK, right. KAREEM ZIDANE: --which is the except star slash star. And this means that, hey, in the response that you're sending, I'm expecting anything that you send back pretty much. So a server can send back HTML. It can send back, you know, JSON data. It can send back some other binary data. You know, we can specify, hey, I'm just expecting HTML. I'm just expecting JSON. And in this case, Curl is expecting pretty much anything. COLTON OGDEN: OK. Kind of acts like a filter almost a little bit? Will it get rid of MIME types that don't satisfy that pattern? KAREEM ZIDANE: So the server actually should handle this. The server should see this except header, like look into your header and see what you're asking for. And if the server is able to provide this kind of response, it should. Otherwise, it should provide you with some sort of error that indicates that I don't have this kind of resource available. COLTON OGDEN: Makes sense. OWLYone, ghostwake, dotmido, and vivek_chauhan, thank you very much for the following, appreciate it. KAREEM ZIDANE: Thank you. All right, so these are the defaults, request headers that Curl seems to be sending by default. There are a bunch of others if you want to look at the documentation. There are so many other requests headers that we can use. And the next part here is the response that we got back from the server. And so the first line says, HTTP/1.1. And this is just the server saying back that, hey, I speak the same HTTP version. COLTON OGDEN: So we know they're speaking the same language at this point. KAREEM ZIDANE: Exactly. COLTON OGDEN: They're both saying essentially same thing. KAREEM ZIDANE: Yes. The server also adds 200 OK in this case. And 200 is what's known as an HTTP status code. And it's just a numeric code that indicates the status of this request or response, whether it was successful or not. COLTON OGDEN: Everybody in the chat, the status code that you're most familiar with, go ahead and plug that. And we won't spoil it. But I'm sure many of the people in the chat have seen a HTTP status code of a particular variety many times on the web and have just not-- oh, actually, [? Barrack ?] said 503. That's true. 503's fairly common. It's not as common-- KAREEM ZIDANE: Yes. COLTON OGDEN: --as another very, very common one right now. KAREEM ZIDANE: Lots of people are mentioning it right now. COLTON OGDEN: Yeah, let everybody know this. KAREEM ZIDANE: It's not a secret really. It's 404. COLTON OGDEN: Yeah, there we go. 404. Someone says 401 though. Someone's got 401 a few times, 403 as well. [? Barrack, ?] OK, that was sarcasm. OK. I've definitely seen 503 a handful of times. But there we go, 418. That's the troll. I'm a teapot. It is a real one, but it's not a very common one. KAREEM ZIDANE: One of them was-- I think was it that one was an April's fool at some point I think? COLTON OGDEN: Yup, by the creators of a HTTP-- KAREEM ZIDANE: Yeah. COLTON OGDEN: --or the maintainers. And then [? Dement, ?] 301, yeah, that's actually a redirect [INAUDIBLE].. KAREEM ZIDANE: That's also-- COLTON OGDEN: Yeah. KAREEM ZIDANE: --fairly common as well, a redirect. I think that would be permanent redirection. COLTON OGDEN: Yeah. KAREEM ZIDANE: OK. So we have a bunch of others. People are very familiar with different HTTP status codes here. COLTON OGDEN: Yeah. KAREEM ZIDANE: So I'm not going to spend much time. COLTON OGDEN: You're preaching to the choir. KAREEM ZIDANE: Yeah, exactly. COLTON OGDEN: Everybody already knows everything you're talking about. [INAUDIBLE], Kareem. KAREEM ZIDANE: Yeah, I'm not going to [INAUDIBLE] end up. I guess there's not nothing to talk about. [LAUGHTER] OK. COLTON OGDEN: They're actually going to teach you Flask today. KAREEM ZIDANE: Yeah, I would actually be very interesting to learn more about this. OK. So it says 200 OK. Hey, your request was OK. Here's a response. It also sends a server response header. And what this actually says is, hey, you know, the kind of server that's running is actually this weird name, ecstatic. COLTON OGDEN: It's a very happy, ecstatic server. KAREEM ZIDANE: Yeah, 330. And actually for security reasons, some actual servers or some people choose to configure the servers to not send that particular header. COLTON OGDEN: [INAUDIBLE]. Because then they know if you have a particular version of a particular server that has a security vulnerability. KAREEM ZIDANE: Exactly. COLTON OGDEN: You've kind of expressed that to the world. KAREEM ZIDANE: Yeah, making the chances higher of someone, you know, exploiting that. The next header here is cache control. And this is a header that says the server is trying to say to the client, hey, you can cache this response for this many seconds, which is 3,600, which is like an hour. So the server is essentially saying, hey, don't ask me about the same thing within an hour, right? And this can be useful, of course, to sort of reduce traffic on our servers if browsers can cache this data. You know, a bunch of other headers-- last modified. Content length is the actually the size of the file that the server is sending back. COLTON OGDEN: In bytes, correct? KAREEM ZIDANE: In bytes, yes. Here's the MIME type that you talked about. COLTON OGDEN: Right. KAREEM ZIDANE: There's the content type header, which includes a MIME type. In this case, the type of data that we're sending back is text/html. COLTON OGDEN: Right. KAREEM ZIDANE: There are a bunch of others, too, if you want to check them out, and a couple other headers that we won't actually dive into, but you're free to read more on them or other headers online. And following that, following all the headers that we got, there's actually the data, which is the body of response. COLTON OGDEN: The stuff that we actually really care about. KAREEM ZIDANE: The stuff that we actually care about. COLTON OGDEN: Ultimately, yeah. KAREEM ZIDANE: So you can imagine like this is what actually happens when you try to make a request through the same server in your browser. It sends these requests headers. It gets back-- COLTON OGDEN: You don't get all of that stuff. KAREEM ZIDANE: Exactly. COLTON OGDEN: As the end user, you see that, but rendered in a visual format. KAREEM ZIDANE: Exactly. So the browser takes care of all that, parses all the headers, parses the body of the response, and then translates it into the sort of page that you see or whatever. COLTON OGDEN: Images and text and whatnot-- KAREEM ZIDANE: Yeah, whatever resource. COLTON OGDEN: --that you end up seeing ultimately. KAREEM ZIDANE: Exactly. That's exactly right. COLTON OGDEN: "Do you know when Professor David will do the next Livestream?" This is [? Oncu255. ?] And then [? In The ?] [? Ready ?] kindly said, "he'll be on Friday on the stream for the code review," which is correct. We are indeed having a code review. So anybody that's here in the chat that's not aware, if you go to bitly/cs50/codereview here, we're accepting source code on GitHub or Gist. And if you want us to review it on stream on Friday with David, David and myself, definitely go ahead and toss us your repos. And it's going to be a style slash design review. It's not going to be bug testing or anything like that. So don't, ideally, send us broken code. Send us working code. And this is more catered also towards beginner to intermediate programmers students who want just a little bit of help with their style, much in the same way that we do sort of CS50 Harvard students style grading. Ideally, don't send us CS50 pset repos, just so that we don't have to spoil solutions for students online. But send us all of your repos that are not CS50, ideally, pset related. And we will take a look at it. KAREEM ZIDANE: Yeah. That should be so much fun. COLTON OGDEN: Yeah, I'm excited. We have quite a few people that have already submitted. And you know, if it does well, we might do more than one episode. But this Friday will be our very first version of that sort of side series for this channel. So I'm very excited to take a look at that. KAREEM ZIDANE: Cool. All right, so I'm just quickly going to show the same thing in the browser. So if you visit local host, call 8080 in the browser, you should see if you open your developer tools by right clicking, and then Inspect, and then choosing the Networks tab, you should be able to see different information about the request and the response, pretty much the same information. Maybe Chrome includes a couple more request headers, a couple different values for them. But it should be essentially the same thing. COLTON OGDEN: Right, OK. KAREEM ZIDANE: And of course, on top of that, you get the page rendered as you expect, which [INAUDIBLE].. COLTON OGDEN: You get access to all the same information, just in a more user-friendly way [INAUDIBLE].. KAREEM ZIDANE: Yeah, exactly. Cool. All right, so now that we've demonstrated this, another thing that I want to talk about is the difference between a static website and a dynamic website. COLTON OGDEN: Sure. OK. KAREEM ZIDANE: And what do you think a static website is? COLTON OGDEN: A static website to me means a website that, if we go to that page as many times as we want, it's going to show us the exact same content every time. KAREEM ZIDANE: Exactly. I mean, also to add to that, if you go to that page or I go to that page, we should technically see the same content. It doesn't change-- COLTON OGDEN: Correct. KAREEM ZIDANE: --if the user changes. And technically, some websites could use JavaScript and some external APIs to change their contents maybe per user, maybe different use cases. So we're not going to worry about that for now. I think they would still be static websites since there is no back end that's handling something here. COLTON OGDEN: Right. KAREEM ZIDANE: A dynamic website, on the other hand-- so a static website, actually as an example, would be the documentation for our pset specifications, right? So if Colton goes to pset 0 specifications, he will see the same thing as I'm seeing right now. COLTON OGDEN: Yup. KAREEM ZIDANE: Right? A dynamic website, on the other hand, will be something like Facebook, or Twitter, or Reddit, whatever social network. COLTON OGDEN: Yeah. It changes every time you refresh. You have all your friends and their posts, all the comments, all the likes. The like number could change. KAREEM ZIDANE: Exactly. COLTON OGDEN: The profile pictures of your friends could change. KAREEM ZIDANE: Yeah. Different people see different things. You know, I see my name on the top right. You see your name on the top right. People who are not logged in see completely different things and so on. And so that's often referred to as a dynamic website. A dynamic website also has a back end that's up and running handling different requests as we'll have one today and demonstrate and go through something. All right, so let me get out of this and start with actually our first Flask related example. COLTON OGDEN: [? Dmsmtp ?] and saltyglowstick, thank you very much for the follows as well. KAREEM ZIDANE: Thank you. All right, so the first thing that we need to have to work with this is have Python installed. COLTON OGDEN: Sure. That's going to be important if we're programming in Python, anything in Python. KAREEM ZIDANE: I'm not going to provide instructions on that. But if you go to python.org or whatever the URL is, it should be-- COLTON OGDEN: I think it's by the node. KAREEM ZIDANE: --there for [INAUDIBLE]. COLTON OGDEN: I'll plug it. Everybody let me know if that's the correct link. And also, shout out to the regulars, [? Nawanda, ?] [? Bella, ?] [? Bavik, ?] [? Andre, ?] [? Whipstreak, ?] there were multiple other ones that we saw up above. We have some new ones [? Oncu, ?] [? Dement, ?] In The Ready, which we've mentioned before, [? mkloppenburg, ?] who left early unfortunately, but thanks for popping, [? Varani, ?] and then all of the other folks I've mentioned so far. Apologies if I did not catch your name, but thank you very much to all the people that are tuning in right now and have been tuning in so far. KAREEM ZIDANE: All right, so I have Python already installed. In this case, I have Python 3.7. I think Python 3 in general should work. And the first thing we need to do to install Flask is pip3 install flask, right? And of course, pip3 is not found, because I need to install pip3. COLTON OGDEN: Yup So pip3 is a package manager for Python, right? KAREEM ZIDANE: Correct, yes. It's a software that allows you to install a package, remove packages. COLTON OGDEN: And apt-get is kind of like that, but that's for use for Linux. KAREEM ZIDANE: For Ubuntu and [INAUDIBLE].. COLTON OGDEN: Oh, for Ubuntu Linux. Right, because fedora could be for-- KAREEM ZIDANE: It's also in a bunch of other distributions. COLTON OGDEN: [INAUDIBLE] or whatever. KAREEM ZIDANE: But Ubuntu, I guess, is the most popular one. So I'm right now installing [? pip3, ?] as you can see. COLTON OGDEN: It's a massive installation. KAREEM ZIDANE: Yeah. And hopefully, that should work this time, pip install flask. And all good. OK. So we now have Flask installed. To verify that, you can run Flask [INAUDIBLE] version. And it should output something. COLTON OGDEN: Outputs an error. KAREEM ZIDANE: OK, outputs an error. I mean, ideally, this wouldn't show up on your computer. But it's actually showing me what to do to fix this error here. So I'm just going to follow this instruction and try again maybe. Hopefully, it won't break this time. OK. COLTON OGDEN: Nice. KAREEM ZIDANE: So I just needed to export a couple of environment variables. It's showing me what to do here. So I did it, and it worked. This is what you should see when you run Flask [INAUDIBLE] version to verify that it was installed correctly. COLTON OGDEN: OK. KAREEM ZIDANE: All right, so I'm going to dive into the first example of the day. And the goal of this example is to sort of visit the same URL that we visited a few seconds ago, a few minutes ago, and sort of see simply hello as a response-- COLTON OGDEN: OK, sure. KAREEM ZIDANE: --so nothing fancy. And the way to do that would be, first of all, we need to import Flask with a capital F from flask, the lowercase. COLTON OGDEN: Yup. KAREEM ZIDANE: And we need to create an app, instantiate an app. And this app needs to be passed some string that sort of identifies that app. I mean, usually at the beginning, you shouldn't really worry too much about this. Most people just pass __name__. Yup. So don't worry about this for now. Just instantiate the app the way it is right now. And the next thing that we see here is an app.route/, forward slash. And what do you think? Do you know anything about the @ in Python? COLTON OGDEN: I know it's a decorator. So it's kind of like a higher order function in Python a little bit. That's kind of a generalization for it. Basically, [? wraps, ?] another function, does some information either before or after it and returns that function, that [? wrapped ?] function. KAREEM ZIDANE: Correct. So in Python, functions are what they call first class objects I think. COLTON OGDEN: First class objects, yeah. KAREEM ZIDANE: Yes. And so a function can be passed to another function as an argument, can be returned from another function as an argument. And a decorator simply is a function that takes another function as an argument or takes a function as an argument and returns a function. COLTON OGDEN: Yup, exactly. KAREEM ZIDANE: Right? So if you had to guess, what does this do in this case, what does this decorator do in this case? COLTON OGDEN: Well, in this case, it looks like it's making whatever the function below it does do some operation, some logic, when they get directed to the string that's passed into route. KAREEM ZIDANE: Correct. So Flask actually handles of ton of stuff for us for free. And as you mentioned, the way to apply a decorator to a function is using the @ decorator and then pass it any arguments that it needs. And then right after that, you should just define your function normally. And the way this works when this program runs, what's actually going to happen is that this function index is actually going to be passed as an argument to the decorator. And another function is to be returned. Presumably, that other function has some other logic that wraps around lots of complicated stuff that we hopefully don't want to go through. COLTON OGDEN: All the magic. KAREEM ZIDANE: Exactly. And part of the magic in this case is route handling as you mentioned. So in this case, if I receive a request on slash, right-- COLTON OGDEN: You probably have some global object, too, that manages all the routing. And then this adds that information to that global object or whatever could be defined the function. Yeah. KAREEM ZIDANE: Yeah. That would be my guess. So in this case, if I receive a request on slash, what should we do? We should return hello. COLTON OGDEN: Right. And the name of the function itself doesn't really matter. Because all Flask is really doing, I'm guessing, internally is keeping a reference to those function names and managing that on its own. KAREEM ZIDANE: Correct. COLTON OGDEN: It's saying, if the user goes to slash, call index, right? KAREEM ZIDANE: Correct. COLTON OGDEN: Because it's mapping it probably just having a direct reference to the function. Because, like you said, it's first class. So it just really needs to refer to its symbol, and it can call it. KAREEM ZIDANE: I can't remember exactly, but I believe the name of the function only matters if you use the URL underscore 4 functionality. COLTON OGDEN: I think yeah. I think so yeah. KAREEM ZIDANE: We're not going to be using that today. But just for now for simplicity, this name can be anything you want. It can be foo. It can be bar. It can be anything you want. What actually matters is the decorator that's before it. COLTON OGDEN: Correct. KAREEM ZIDANE: If you have a route [? on ?] slash, the following function is going to be run when you visit that route. COLTON OGDEN: Let's answer a couple of questions from the chat. So [INAUDIBLE] says, "why does mail from the SMTP library go into spam?" Do you happen to know offhand? KAREEM ZIDANE: I mean, I don't really know much about this. But usually sort of mail servers have some ways of verifying whether the party that has sent this email is actually legitimate or not. COLTON OGDEN: Sure. KAREEM ZIDANE: Like, for example, if you use your own web server, your own mail server, to send people some emails, other mail servers upon receiving this email don't really know who this server belongs to or whether it's malicious or not. So they usually filter it as spam by default. COLTON OGDEN: Make sense. I can imagine that happening, too, if you say that I'm sending email from some messages not actually what the from sender is. You know, if you say I'm sending this from coltonoscopy@gmail.com, which is my email address, but my Flask server isn't going from gmail.com, it's coming from some random server somewhere-- KAREEM ZIDANE: Exactly. COLTON OGDEN: --that's probably an indicator to Gmail or some other service that this is probably illegitimate. KAREEM ZIDANE: Yeah. As you mentioned, you can spoof email addresses, the phony email addresses, and make it seem like someone else is sending an email. But, you know, again, some web servers do have ways to handle this whether by filtering it as spam or showing you some icon that says this might be a malicious email. But, yeah, this should be possible. COLTON OGDEN: [? Dement0 ?] says, "first time joining your Livestream. The earlier ones you did-- watched on YouTube. This time decided to join the steam to say hi, Colton and Kareem." KAREEM ZIDANE: All right, hi there. COLTON OGDEN: Awesome. Thank you so much, [? Dement, ?] really appreciate it. Thanks for tuning in live, really appreciate it. [? Andre's ?] clarifying about the Debian Linux package manager apt-get in Ubuntu and other [INAUDIBLE] use it. [? Varani ?] says, "this looks very similar to Express.js." It's been a little while since I've used express actually. But I mean a lot of these sort of micro-- these frameworks, back end frameworks kind of look similar. The routing kind of looks very similar. KAREEM ZIDANE: Yeah. COLTON OGDEN: It's a common paradigm. And Laravel, I think, for its PHP framework, adopts a similar convention. KAREEM ZIDANE: Correct. COLTON OGDEN: "Which course do Harvard students do after CS50?" Generally, CS51 is the next go to. And that's that kind of an object-oriented functional programming course. And there's operating systems, and algorithms, data structures. A discrete math course that you took, the extension version of it, students will take something like that. Which course? What number was that? Do you remember? KAREEM ZIDANE: The discrete math course? COLTON OGDEN: Yeah. KAREEM ZIDANE: I think it was CS20 or something. COLTON OGDEN: Oh. Yeah, yeah. CS20. So yeah. KAREEM ZIDANE: Yeah. COLTON OGDEN: It doesn't necessarily go higher number than CS50, but, yeah, there's a bunch, whole bunch of different ones. "All the CS50 team is doing an amazing job to make these technologies easy to learn and follow thank you very much. Please keep doing what you do." Hey, that's a nice compliment. KAREEM ZIDANE: Yeah, thank you. COLTON OGDEN: Thank you very much, [? Dement, ?] really appreciate it. "I also need a CS50 hoodie and T-shirt," says [INAUDIBLE].. Yeah, well, if you teach CS50, you can have one of these awesome hoodies. But you got it to become a staff member. KAREEM ZIDANE: Yeah. COLTON OGDEN: "It's a dream learning from CS50." Also, protip, when spoofing an email, make sure you're not auto-appending your signature. Probably. KAREEM ZIDANE: OK. COLTON OGDEN: That's probably something you don't want to do. KAREEM ZIDANE: All right, so let's actually test this in action. So the way to run this would be by navigating to the folder where your [INAUDIBLE] in this case and then run Flask run, and then optionally, -p, and then the port number that you want to listen on. COLTON OGDEN: OK. KAREEM ZIDANE: By default, Flask listens on port 5,000. I prefer using 8080. There's no real difference here except that I have this exposed from my container. So I'm just going to listen on port 8080. And when you do this, Flask has a built-in server. It's actually from another framework. But it has a server that starts up and starts expecting information on this particular port. I think this is going to fail. Let me see why. COLTON OGDEN: Very optimistic of you. KAREEM ZIDANE: Yeah. I mean, I noticed something that I need to-- OK. Well, is that correct? Did we expect that? COLTON OGDEN: Oh, because that says hello. KAREEM ZIDANE: Yeah. COLTON OGDEN: And the message said, hello there in the web browser. KAREEM ZIDANE: It might be listening on some-- there has to be another server that's listening on this. Let's see. OK. That's weird. COLTON OGDEN: Well, weren't you just using the HTTP server in your Docker container? KAREEM ZIDANE: OK. Now, it works as expected. COLTON OGDEN: Oh, was a caching it? KAREEM ZIDANE: I think it was caching it, yes. COLTON OGDEN: Oh, OK. Interesting. KAREEM ZIDANE: All right, so this doesn't work, because I'm listening on IP address 127.0.0.1. And I'm inside the container. So it's a little bit confusing. For my host, 127.0.0.1 is the host itself, not the container. COLTON OGDEN: Right. KAREEM ZIDANE: So what I want to do is listen for actually all IP addresses inside of this container. Again, if you're running this on your host directly, if you're not using Docker, don't worry about this. You shouldn't need this argument. But I'm going to do this for now. And I get what I expect to get, which is hello. COLTON OGDEN: Nice, OK. KAREEM ZIDANE: All right, so very simple, very easy. Let's switch to the second example that we have today. And this example would essentially expect some piece of data that can be different from request to request. And then it returns a response that's different based on that piece of data. COLTON OGDEN: OK. KAREEM ZIDANE: So in this case, I'm expecting a name get parameter. As we mentioned earlier, we can send get requests, we can post requests. And we can parametrize these requests in the sense that we can include variables or parameters with different values each time. COLTON OGDEN: Right. KAREEM ZIDANE: Right? So in this case, I'm expecting a parameter called name with a name name, literally, and with a value presumably the name of the person who's making the request. COLTON OGDEN: OK. KAREEM ZIDANE: Right? So the way to make a request with a get parameter like this would be as follows. Let's just make sure the server's running first. So let's run the server on the same port. And now the way to do this would be to append a question mark to the end of your URL and then mention the name of the variable or the name of your parameter equals its value. So in this case, I'm going to say my name. COLTON OGDEN: The key value pairs? KAREEM ZIDANE: Exactly. So name of the parameter equals the value of the parameter, right? COLTON OGDEN: OK. KAREEM ZIDANE: And hit Enter. And I get hello, Kareem. COLTON OGDEN: Nice, works very splendidly. So if you did name equals nothing? KAREEM ZIDANE: [? Correct. ?] Well, that's a good point. If I don't include this parameter at all, that's a little buggy. COLTON OGDEN: Hello, [? none. ?] Nice. KAREEM ZIDANE: Right? COLTON OGDEN: OK. KAREEM ZIDANE: And that's because the default value of this parameter is none. COLTON OGDEN: Right. KAREEM ZIDANE: Or the default value that's requested are-- so get returns here is actually not for this parameter. COLTON OGDEN: What if you did hello equals, and then nothing after the equals? KAREEM ZIDANE: I think it would be the same thing. Would it be an empty string? COLTON OGDEN: Let's try it. KAREEM ZIDANE: It would be an empty string I think. COLTON OGDEN: Let's try it. KAREEM ZIDANE: So let me actually get this running somewhere else. COLTON OGDEN: And, also, thank you very much to [INAUDIBLE] and [INAUDIBLE].. I apologize if I butchered that. Thank you both very much for following. 8880. all right, let me see. Oh, I have to be in the same shell. OK. All right, I didn't think about this before this [? seam. ?] But, anyway, if we did name equals this, it's going to be [INAUDIBLE].. COLTON OGDEN: Nice. OK, so a different behavior. OK. KAREEM ZIDANE: Right? So this is a different value technically. COLTON OGDEN: Yeah. KAREEM ZIDANE: In the first case, in the case where the name is not present at all, the parameter is not present at all. And so the default value that get returns here is none. COLTON OGDEN: Correct. KAREEM ZIDANE: But in this case, actually the parameter is present. And there is a value for it. And this value is empty, right? So it just returns the empty string COLTON OGDEN: Nice. KAREEM ZIDANE: Right? COLTON OGDEN: OK. KAREEM ZIDANE: So there are ways where we can handle this. We're not going to worry too much about this right now. The second thing that I wanted to mention about this is that if I have more than one parameter, more than one key value pairs, they are separated with an ampersand. So if I have name equals Colton and email equals colton@cs50.harvard.edu, this is how this would be read. COLTON OGDEN: Right, OK. KAREEM ZIDANE: That's [INAUDIBLE]. COLTON OGDEN: And then you could get more than one variable inside your route just by grabbing the request.args.get email in this case. KAREEM ZIDANE: Correct. Yeah. So this is the way that we get the value of a get parameter called name, request.args.get name. And notice that we have to import request from Flask up here as well. COLTON OGDEN: Nice. OK. We have a couple questions in the chat, too. KAREEM ZIDANE: OK. COLTON OGDEN: [? Webstreak ?] is asking, "quick question, does there happen to be message input into the rendered template function," which you haven't gotten to yet. KAREEM ZIDANE: We haven't gone to that part yet. I don't know off the top of my head. I don't think I've used it before. But let's actually check the documentation. Let's see. So there is the render template function. I don't see a message parameter here. So I don't think it has one. COLTON OGDEN: Yeah. And I think in this case wouldn't you just pass in whatever variables you want and then have the templating thing sort of take care of? KAREEM ZIDANE: Yeah. COLTON OGDEN: And there's also flash messaging, which I think you can integrate into Jinja, can't you? KAREEM ZIDANE: We're actually going to demonstrate both of these today. COLTON OGDEN: OK. KAREEM ZIDANE: We're going to demonstrate passing data to a template and then flashing some messages. COLTON OGDEN: OK. KAREEM ZIDANE: So if you're curious, stay tuned. COLTON OGDEN: Cool, cool. Next question, "how would you pass data from the client side, e.g. a JPEG image, to Python Flask server and then return results?" KAREEM ZIDANE: OK. That's a different way of doing it. Usually, when the data is binary like this, it's the case that we make a POST request which is the same kind of request that we're going to talk about. And essentially, the data of this image or whatever file you're trying to upload is sort of encoded as part of the request when the browser makes that POST request. We're not going to demonstrate uploading files today. But it wouldn't be a part of the URL as is the case with get parameters here. COLTON OGDEN: OK. KAREEM ZIDANE: Right? It wouldn't be [INAUDIBLE]. COLTON OGDEN: Yeah, because that's part of the query stream, the get stuff. And that's also stuff that you can't really put into-- I mean, you can binary encode information and put that into a UTF encode information and put that into the URL. But that's not typically how you see especially large data. It's usually done through POST requests. KAREEM ZIDANE: Yeah, I think URLs also have a maximum length. COLTON OGDEN: Yeah, I would imagine. Yeah. KAREEM ZIDANE: So if you have a file that's big enough, though, even if you encoded it, it would be a problem to send as part of the URL. POST requests might be handy in this case. COLTON OGDEN: "Can we override routes," says [? Bavik ?] [? Knight. ?] KAREEM ZIDANE: Can we overwrite routes? In which sense? We can have multiple routes. I don't think we can have different functions for the same route, because at this point that would be confusing for Flask, which function do you want to run in this case. So I can't have another function with the same route here. COLTON OGDEN: And if you did, I would imagine it'd be the bottom one that would take over, that would take precedence. KAREEM ZIDANE: It could be. Because it would overriding it in this case. But in this case, it would be useless to have the first function [? in the first place. ?] COLTON OGDEN: It would. It would. It would. [? Frame ?] [? of ?] [? Ref ?] says, "just to clarify, is the request library part of Python or Flask?" KAREEM ZIDANE: Yes, the request module is part of Flask in this case. It's not a different, not a separate library or anything. I just installed Flask up to this point. All right, and the last thing that I wanted to mention before leaving this example is this notion over here. And this is actually part of the Python 3.6 syntax, which is a format string. Notice, we have an F here, right? And then this is the way I'm sort of injecting the value of the name variable into my response. COLTON OGDEN: The format string, one of my favorite Python 3.6 features. KAREEM ZIDANE: Yeah, indeed. COLTON OGDEN: Probably my favorite 3.6 feature. I don't remember what else 3.6 added that I thought was really great. KAREEM ZIDANE: It's really quite handy. We're going to see a fairly similar syntax when we go into templating, which I think starts the next example. COLTON OGDEN: Yeah. KAREEM ZIDANE: Right. Do we have any more questions so far? COLTON OGDEN: We do. So [? NACL ?] [? Eric ?] is asking, "is it possible to make an HTTP request from a GUI, like Postman, if your app is being hosted on a Docker container?" KAREEM ZIDANE: Yes. And we're not going to dive into details about how Docker works in this case. But, essentially, you can map ports from the Docker container into the host. And it would be like the client wouldn't really care where the app is hosted in this case. COLTON OGDEN: As far as where it could be a server somewhere else? KAREEM ZIDANE: Yeah, exactly. COLTON OGDEN: Just a virtual server? KAREEM ZIDANE: Exactly. COLTON OGDEN: And then [? Aldu ?] is asking, "is there a schedule somewhere of what you are going to cover in the upcoming streams?" We keep all of them as Facebook Events. But, yeah, in the near future, we are going to start integrating I think a schedule into Twitch itself. But you can go to facebook.com/cs50. And that's where we post all the events for all of our upcoming streams. We also post them to our Reddit and our Twitter account, facebook.com/cs50 and then reddit.com/r/cs50 if I'm not mistaken-- yeah, /r/cs50-- and then twitter.com/-- whoops. There we go. twitter.com/cs50, let me make sure that that is indeed accurate. But the simplest way to do it is just to go to Facebook for now, facebook.com-- I can't type-- /cs50. All of our [INAUDIBLE] are there. All right, cool. KAREEM ZIDANE: All right, that's great. So the next example that we're going to dive into involves some templating. Flask, by default, has as part of it a templating engine called Jinja. And we're going to explore a little bit of the syntax for Jinja today. So this following example is a little bit more complicated than the previous one. The first thing that we have here is our routes on slash that's handled by rendering a template apparently called index.html. COLTON OGDEN: And this is what Nate was referring to, Nate being [? whipstreet23 ?] when he asked about render template taking a message parameter. KAREEM ZIDANE: Correct. COLTON OGDEN: In this case, rendered template looks like a URL or an actual HTML page that we might have they we want to serve people, but also takes in some other information. KAREEM ZIDANE: Yeah. And let we actually clarify why templating would be useful in this case or in general. So if you have a website of some sort and you have a bunch of pages, every HTML page ideally should start by-- let's open a sample one here. It should start by something like doc type, html, you know, whoops, html, and then html closing tag. And then we have a head. And you'll have a body. And you'll have a bunch of other things inside of the head maybe and so on. And so it'd be really boring to sort of keep copying and pasting this into every page that you have. Another thing is that if you want to change something, if you want to add a script or if you want to add a link, a CSS somewhere, or rather in all of them, you'd have to copy and paste that into every page that you have. And so templating sort of solves this problem by essentially allowing you to have one base file that you sort of inherit from and sort of plug in certain parts as we'll see. COLTON OGDEN: It's kind of a common paradigm in, I think, software development in general-- KAREEM ZIDANE: Correct. COLTON OGDEN: --composable parts, inheritance, like these sort of concepts I think. We even use this in the game streams, for example. KAREEM ZIDANE: Yes. COLTON OGDEN: State machines, we did that with state machine example with a base state that other states can inherit from to get functions that they don't have to override themselves, right? They just copy the functions from other states. KAREEM ZIDANE: Yeah. I mean, inheritance in the context of object-oriented programming is a little bit different here. Because you can think of it the same way that you think of a pre-processor, a C preprocessor. It just literally, you know, pastes your stuff from the base file and then plugs into the stuff that's [INAUDIBLE].. COLTON OGDEN: Yeah, definitely a simpler implementation here, but yeah. KAREEM ZIDANE: All right, so by default, Flask expects all of our templates to be inside of the templates folder. So I'm going to go into that folder. And I'm going to open the base HTML file that I have. And it looks like this. It's called the layout.html. And it looks like this, has all the parts that we need for any HTML file in general, the doc type, the HTML, the head, the body, and so on. And it also has this sort of curly brace curly brace notation. And this is actually a Jinja specific syntax. This actually says, you know, if there is a keyword argument passed into render a template whose name is title, replace its value here, or plug in its value here. And so let me go back up here. And I'm not sure if that's-- can I make this a little bit smaller, so that we can see? Maybe put it up? COLTON OGDEN: Oh, yeah. We can probably mess with the chat and make it a little smaller. KAREEM ZIDANE: Yeah. COLTON OGDEN: We can do that. Whoa. Hey, there. KAREEM ZIDANE: All right. COLTON OGDEN: It's just briefly, make it small just briefly. KAREEM ZIDANE: So in the render template call here that I called, I passed in a keyword argument called title. And I passed in the value Homepage in this case. COLTON OGDEN: Right. KAREEM ZIDANE: So this essentially says that, hey, if there is a keyword argument called title passed to render template, replace its value here, or plug in its value at this very same location. And this location happens to be the title of our page in its case. COLTON OGDEN: So this is like the precursor to really getting us into a more dynamic sort of web content. KAREEM ZIDANE: Correct. Yes. And so as you can imagine, different calls to render a template, as you mentioned, can receive different values for the title parameter. COLTON OGDEN: Even if it takes in a name, hello Kareem versus hello Colton, that's technically a dynamic webpage. KAREEM ZIDANE: Correct. COLTON OGDEN: To answer a couple questions in the chat, too, also-- [? Giban3 ?] said, "I used to do the same thing with PHP, making a header and footer and then having the PHP call it in." Yeah, that's kind of what we're doing here. KAREEM ZIDANE: [INAUDIBLE] COLTON OGDEN: Well, I mean, it's an idea of what we're doing. Because it's sort of what we're leading to, right, having a header and a footer that we can inherit from template? KAREEM ZIDANE: Oh, yeah. Yeah, yeah. COLTON OGDEN: Yeah. KAREEM ZIDANE: Yeah. COLTON OGDEN: [INAUDIBLE] KAREEM ZIDANE: Yeah, you can pretty much do that as well. COLTON OGDEN: And then [? Andre ?] was saying, "templating is closer to generic programming." So templating in C++ is not the same thing as templating templates in Jinja or Flask. In this case, these are just kind of like pre-created documents that we inject variables into. Templating in Java or-- it's called generics in Java-- templating in C++, those are functions that can take very adic arguments of different types. And they get compiled into multiple different-- how do I want to describe this? They get compiled into multiple versions of the same function that can take multiple data types. And this is done at compile time. And then template meta programming is related to that, that same thing in C++ where you can, at compile time, basically generate a compute table or a lookup table for a series of functions and their outputs, and then get insane performance boost that way, especially in games programming where you're calling a function maybe hundreds of times or rather not hundreds of times a second-- well, I guess hundreds of the times a second. No, I guess you couldn't be doing hundreds of times in a second. Hundreds of times in a loop maybe over the course of a couple of frames or whatever, this is kind of where you'd use templating. But it's, yeah, completely separate I think from this domain, but the same name templating. Not-- KAREEM ZIDANE: Can be [INAUDIBLE]. COLTON OGDEN: --synonymous, but very, very different use cases, same word. And [? Belacures ?] is asking, "if we don't mention any methods in the route, will Flask answer only to a get request?" KAREEM ZIDANE: That is correct. And we're going to explore the methods parameter to the decorator here. But, yeah, if I just say app.routes/, this is expecting only get requests. COLTON OGDEN: OK. KAREEM ZIDANE: And so what this means, if I try to send another kind of request or if the browser tries to send another kind of request, the server is going to hopefully respond with some error code. In this case, I think it's 405, method not allowed or something. COLTON OGDEN: Makes sense. And lastly, [? Adam ?] [? Fighter ?] says, "templates in Jinja2 are like Python format strings on steroids." KAREEM ZIDANE: Yes, kind of. They're a little bit fancy, a little bit more complicated, because they involve some sort of logic in them that we'll see. COLTON OGDEN: True. KAREEM ZIDANE: But the idea is the same, that you have some base. And then it has some variables that you can sort of plug into, and it just becomes different. All right, the next interesting piece here, or snippet I should say, is the block some word end block in that very same syntax, so curly brace, %, block, name, %, and so on. And so what this does is actually says that, hey, the templates that are going to extend or inherit from this base can essentially define a block. And the contents of this block are going to be inserted here. So let's actually take a look at one of these templates. So let's take a look at index.html. And the first line in index.html is that it extends layout.html, the file that we just looked at. COLTON OGDEN: OK. KAREEM ZIDANE: Right? COLTON OGDEN: So it's going to inject the body block sort of into that-- layout.html is kind like a template that we're saying, we're going to put our own block, our own custom block, into this place holder for a block, right? So in this case, block body and then the actual layout defines body and then gets injected into it, right? KAREEM ZIDANE: Yup, exactly. COLTON OGDEN: Or index.html. KAREEM ZIDANE: In this case, everything from layout.html is going to be included in index.html. And the place where this line over here is going to be replaced with the contents of this-- COLTON OGDEN: Sure. KAREEM ZIDANE: --which is this line over there. COLTON OGDEN: It's pretty cool. We don't have to write all the HTML head, title, all that stuff-- KAREEM ZIDANE: Nope. COLTON OGDEN: --in index.html. We're only literally just writing what the body is that we care about. KAREEM ZIDANE: Yeah. And that's the beauty of templating. It makes this stuff really easy. COLTON OGDEN: "Completely unrelated," says [? Webstreak, ?] "how do you check if a text box in HTML is empty using JavaScript?" I pulled it up here, because I didn't recall offhand. But it looks like with JavaScript you can do it pretty easily just by checking if an element's value dot length is equal to zero. to see exactly. Oh, would it be document.get element by ID and then the input or whatever? I'm trying to find an actual robust thing here. Yeah. KAREEM ZIDANE: Definitely do google this stuff, though. It can be really handy when you run into a question like this. Don't block yourself. COLTON OGDEN: Yeah. Yeah. Like what I did was I typed into Google. I just basically typed in "check text box html empty." And using something like document.get element by ID or using jQuery. You might have seen the $ library using whatever selector for your text box. So if you get an ID of text box, you can check it by the ID by passing in the string with a hash symbol. And then you can basically check to see if value dot length on that is equal to zero. And that will mean that it has no characters typed into it, in which case it's empty. KAREEM ZIDANE: All right. OK. So let's actually take a look at how this looks. So let me run my server again. It's Flask, right? Flask, OK. So let me reload this page. And this is what I see. And just to be clear, let's get back to-- what is it-- Flask stream bash. And let me go into Flask stream. I think we're an app2. So this is what I have in my template at the bottom here, right? This is not really interesting. So let's-- yeah. OK. So this is what I have here, same thing. All right, so the idea of this-- COLTON OGDEN: Very sophisticated, by the way. KAREEM ZIDANE: Yeah, thanks. The idea of this simple web app is that it should allow us to sort of register users. COLTON OGDEN: OK. KAREEM ZIDANE: Right? Ideally, databases are used for this. We're not going to use a database today. Maybe in a future stream we can talk more about database. COLTON OGDEN: Sure. KAREEM ZIDANE: I believe David had a SQL streams sometimes? COLTON OGDEN: Yeah. We had like a SQL basics kind of stream where we just kind of talked about the syntax. And SQLite, I believe, is what we used. But doing something like Mongo or MySQL in the future would be pretty cool. KAREEM ZIDANE: Yeah. So in this case today, we're not really going to dive into any database stuff just to make it simple. And what we're going to use instead is a CSV file. And a CSV file is essentially a simple text file with comma separated values. So I can have a file called users.csv in this case. I can say that, hey, the first column is going to be the user name. The second column is going to be the password. And so I can have something like your username. Is that correct? Is that correct? COLTON OGDEN: Yeah, cogden. Yeah. KAREEM ZIDANE: OK. All right? And then your password is 123. COLTON OGDEN: Yup. My real password, too. KAREEM ZIDANE: Yes. COLTON OGDEN: There you go. You got it. KAREEM ZIDANE: And then another user name, and then another password, and so on. COLTON OGDEN: Oh, you and I use the same password. KAREEM ZIDANE: Yeah. That's a coincidence. COLTON OGDEN: It's probably not very secure. KAREEM ZIDANE: I should try this on your account sometime. All right, so the idea of registration in this case is that it would take some data from the user, and then it would essentially insert a row or a line into this Text file in this very same format. COLTON OGDEN: Yup. KAREEM ZIDANE: Right? COLTON OGDEN: Using a very simple database. KAREEM ZIDANE: Yes, correct. So let's actually look at this page here, Register. And in this page, it's another template called Register. And it has this very similar structure to the index.html page. It also extends layout.html. It also fills in the body block in this case. But this time, it fills it up with a form that's going to be submitted to register. And I believe you talked about this in your HTML stream, video forms? COLTON OGDEN: We talked about it very briefly. That was actually the last part before we kind of had to cut it short. KAREEM ZIDANE: Cool. COLTON OGDEN: We didn't really get into the nitty-gritty of it, but we talked about kind of like username, password, and then buttons and stuff like that. KAREEM ZIDANE: So, yeah. COLTON OGDEN: We really get into details of like POST and GET and all that. KAREEM ZIDANE: Essentially, we have a form here. And this form is going to be submitted to /register. And we're going to take a look at this code after this. This form is actually going to be submitted using the POST request method as opposed to GET. COLTON OGDEN: Yup. Completely different, right? KAREEM ZIDANE: Right. So, again, the main difference between including HTTP parameters or variables in a GET request versus a POST request is that, when you include HTTP parameters in a GET request, they appear as part of the URL. COLTON OGDEN: Right. KAREEM ZIDANE: But when you do that using a POST request, they're actually encoded as part of the request [INAUDIBLE].. COLTON OGDEN: So you probably don't want to put your password as a Get, you know? KAREEM ZIDANE: Correct. So form submissions, usually, that includes things like user names, and passwords, and files, and other stuff are not typically submitted using GET. COLTON OGDEN: Right. KAREEM ZIDANE: They're submitted using POST. But what's a common form that submitted using a GET request? COLTON OGDEN: A common form? I guess it would be, yeah, like a search I guess. KAREEM ZIDANE: Yeah. So Google, for example, this essentially is a form with one text field and, you know, a couple of buttons or whatever. And I can search for cats. And if we ignore all the stuff-- actually, you know what? Let's redo this. So I bet if you look at this whole URL, you're eventually going to find something like q=cats. And it shows the same thing essentially. COLTON OGDEN: Right. KAREEM ZIDANE: Right? So this is a form that's submitted using a GET request. COLTON OGDEN: GET request, right. Because we're not sort of including any really personal identifying information-- KAREEM ZIDANE: Correct. COLTON OGDEN: --that we need to keep secret. It's kind of all-- KAREEM ZIDANE: Exactly. And it's not just-- well, I guess it is the same thing. It is mainly because of the secrecy. But, also, I don't really want to clutter my history with all this different values of some sort of files that I have uploaded. Or, you know, I don't want to record my password to be in history permanently. COLTON OGDEN: Right. KAREEM ZIDANE: So that's kind of a bad thing to do. COLTON OGDEN: To [? Andre's ?] point, yeah, I mean, templating in this sense and templating and C++ are slightly similar in that there's some plug and play of things, like injection of, I guess-- in case the templates, you're placing some place holder with actual data. And you're doing the same thing with templates in C++. But in C++, you're doing it across multiple different potential use cases. And you're sort of creating a table of multiple things, whereas in Jinja you're just injecting it once, and then processing it, and then returning that one result, right? The purpose of sort of generic programming is to make it possible and more flexible to program with certain data types. And in templating, it's to basically save you from rewriting the same thing over and over again and to kind of just make whatever parts you want dynamic easy to change, right? [? Adam ?] [? Fighter's ?] asking, "can you talk a bit about AJAX async calls with Flask-- for example, typing a name into a text box and having it print instantly without refreshing the page?" KAREEM ZIDANE: I don't think we're going to cover this today unfortunately. But AJAX will be an interesting thing to discuss on a future stream as well. COLTON OGDEN: Yeah. KAREEM ZIDANE: But the idea is that if you have a back end written in Flask or whatever, as we saw in the first couple of examples, we can return essentially any kind of data. So we happen to have returned a string. But you return a string that's formatted as JSON and then parse this on the JavaScript side of things, and then use it as a JavaScript object. And this is how, you know, we can dive deep into REST APIs and such. COLTON OGDEN: Yeah. You'd need a REST API to be able to authenticate, get the information back from the server, and update the page unless you wanted to do it in pure JavaScript. But you still need the authentication to know that that user is actually a legitimate user and not just some random person typing their username. It's a fairly complicated. But, yeah, I think-- KAREEM ZIDANE: If we do have enough time, we can demonstrate a quick example on how that works. But I don't have it in the examples that I have pre-prepared. COLTON OGDEN: [? In ?] [? The ?] [? Ready ?] asked, "what's the difference between request.form name and request.form.get name? KAREEM ZIDANE: request.form name and request.form.get name? I mean, my guess-- I have to look at a documentation for this. I'm not sure if the parameters will be available on the request objects right away, like directly. I'm not sure if you would be able to access them this way. But if you are, it could be the case that GET allows you to specify this sort of default value, for example. So I have to look at the documentation for this one and see if that's accurate or not. COLTON OGDEN: "Can we do functionality for the password? Like when we try sudo, we can see only one bullet, so someone looking over can't guess the length of the password?" Like limit the number of characters that the password field reveals to us? KAREEM ZIDANE: Definitely, yes. I believe you can do this using a script maybe or using maybe something built-in attributes into HTML if there is such an attribute that exists. COLTON OGDEN: Yeah, there probably is. I haven't actually looked into it, but I would google "password limit number of characters, limit number of visible bullets" or whatever. And there's probably a ton of stack overflow snippets that you could copy and paste. Cool. KAREEM ZIDANE: All right, so do you have any more questions? COLTON OGDEN: No. I think we're all caught up. KAREEM ZIDANE: OK, cool. So this form, as you see here-- let's get rid of this-- has two text fields essentially. One of them is a plain text field and one of them a password field. And a Submit button, these are what I have here. And the idea is that when I submit this form the data from this form is going to be submitted to the /register route as we see here. And the parameter names in this case are going to correspond to the input element names here. So I'm going to have ideally a parameter called user name and a parameter called password here. All right, so let's actually try this out. So right now, let's actually verify that the file that I have is empty. It's completely empty, doesn't have any data in it. So if this works as expected, I'm going to sign up myself with some password. COLTON OGDEN: Probably not 1234. KAREEM ZIDANE: Exactly. And this is, of course, an internal server error. COLTON OGDEN: Oh, man, internal server error. KAREEM ZIDANE: Because something-- OK. User name zero is out of range. So let's look back in the code. And do some live debugging. It's really hard to see-- COLTON OGDEN: Oh, man. It's my favorite kind of debugging. KAREEM ZIDANE: Yeah. You know what? Let me do this. Let me make this vertical so that I can see it better hopefully. Flask stream bash, and then we're going to do some live debugging here, so pardon us. OK, app2. COLTON OGDEN: Some live debugging, AKA, stack overflow. KAREEM ZIDANE: Yeah. [INAUDIBLE] And what was the error on line 33? COLTON OGDEN: The list index out of range, row zero is equal to user name. So line 33, yeah. KAREEM ZIDANE: Oh, interesting. OK. I know why this is happening. I think, because I [? truncated ?] the file the wrong way. So the file is technically not empty. The file that we saw right here technically has a blank line. COLTON OGDEN: Right. KAREEM ZIDANE: Right? COLTON OGDEN: But it's not going to have rows that you can parse. KAREEM ZIDANE: Exactly. And so I think one way you can get around this is by doing this. So, now, it's empty. COLTON OGDEN: OK. KAREEM ZIDANE: Right? So let's try this again. Let me go back to Register. Let me do this again. OK. That worked. COLTON OGDEN: Nice, cool. KAREEM ZIDANE: It doesn't show anything useful. It shows me the Index page again. COLTON OGDEN: Right, yeah. KAREEM ZIDANE: But let's check the file one more time. Whoops, users-- COLTON OGDEN: Oh. Nice. KAREEM ZIDANE: There's my [INAUDIBLE]. There's my password. COLTON OGDEN: Spoiler alert, password 123. KAREEM ZIDANE: Exactly. That's something you should never do, actually. Never store passwords in plain text like this. COLTON OGDEN: Yeah, encrypt them. Yeah. KAREEM ZIDANE: Exactly. They are usually sort of encrypted, as you mentioned, or hashed, and then stored as a hash. So that if anyone gets access to this file or your database, ideally, they wouldn't know what this password is actually in plain text. But for simplicity today, we're not really going to talk about hashing. We're just going to store it has a plain password. And let's actually verify that this works by registering another user. And let's say, you know, [? Aaron, ?] for example, in this case and some password. And then, you know, verify this again. We have [INAUDIBLE]. COLTON OGDEN: Much more secure password than your password. KAREEM ZIDANE: Correct. COLTON OGDEN: It's still pretty easy to brute force though. KAREEM ZIDANE: Correct. All right-- so kind of interesting. What can we do with this, though? Like, what can we do next? COLTON OGDEN: Oh, man. Could go a whole kinds of different directions. KAREEM ZIDANE: Exactly. So, now, I'm keeping track of some user data. I should ideally allow them to log in or, you know, hopefully show them that they are logged in or not. And that's what we're going to do next. And so let me go into it app3. And this is going to be a bit more complicated than the previous example, of course. It builds on top of it. And we're going to talk about it one part of the time. So the first thing that we need to do is actually run the server here. So Flask, OK-- OK. So I'm using a library here called the Flask-Session. We're going to talk about the sessions soon. But I'm using a library called Flask-Session to keep track of, you know, if the user's logged in or not. And this library actually needs to be installed separately. And so to do this, I'm going to do like I did last time with Flask, but in this case pip3 install flask-Session like this. And it should hopefully install without any problems. OK. I think this is done. COLTON OGDEN: [INAUDIBLE] your terminology is just so small now. KAREEM ZIDANE: Yeah, somewhere I can see anyway. OK. All right, so now I'm running the servers, no problems, which is good. It looks a little bit different. The layout file is pretty much the same. There's a couple of things that are different that I'm going to show. Index file is mostly also the same, except that-- let's actually look at it. So tabf templates index.html-- so it extends index.html like the previous one, except that it has some sort of logic here. First of all, it checks. If there is a user name, then show hello and that user name and then show a log-out link, right? Otherwise, show hello there and show a log-in link or a register link. And this is what I'm seeing right here, because I'm not logged in. Makes sense? COLTON OGDEN: Yeah. KAREEM ZIDANE: OK. So let me try to register myself, because this is a different application. We don't have the same file here. So let's do this. And hopefully, it won't show the 500 again. Because it might be the same file. OK, good. So now when I click Register, what actually happens is that it shows me back that, hey, hello user name, KZidane, my user name, and then a log-out link, right? And if you look at the file again, we'll find the row that corresponds to my user. So what actually happened here? So when the form data was submitted to register, what actually happened is that-- let's ignore this first part for a second. We should've covered this in a previous example, actually, but I forgot to do that. So let's actually talk about it here. So the first thing that happens is that if we get a get request, what's going to happen is I'm going to render the register template with the title register, right? And this does something as simple as rendering the registration form that we saw, right? Otherwise , which means if you get a POST request, we are going to try to get the user name from the form. We're going to try to give the password from the form. And then we're going to ensure that these actually have some value in them, right? They're not either missing or have an empty value like it did before. And if that's the case, we're going to abort with HTTP status code for 400. COLTON OGDEN: Right? So that's not a not found error. This is a different error in this case. KAREEM ZIDANE: Correct. So 400 is actually a bad method or a bad request error-- COLTON OGDEN: OK. KAREEM ZIDANE: --and some useful description to show the user. COLTON OGDEN: Which means we didn't give it the right information, the POST request was missing some piece of information correct and then we're going to ideally the user gets the row that corresponds to this user name, right? And if there's no such row, that users-- actually, so it gets the row that corresponds with this user name. And if such row exists, that means that we have this user name from before. So we can't re-register it again. And in this case, we return another 400 with a different descriptive message hopefully. And then after that, if all our checks passed, we start by inserting a row into the user's file that essentially consists of the user name and password. COLTON OGDEN: OK. Got it. KAREEM ZIDANE: All right. COLTON OGDEN: Makes sense. I think we have a couple things in the chat here as well KAREEM ZIDANE: OK. COLTON OGDEN: Yeah, no. [? Andre ?] was clarifying about C++ templates. Yeah. I think I mean I think that the terminology is fairly similar. But, again, I think the difference between things like templates in C++ versus Flask is that C++ is creating an entire lookup table of functions, whereas Flask, its goal is to distribute just one bit of information that gets rendered to you. But, yeah, in the same sense that you're injecting sort of place holder values and then generating some block based on that, yes, the terminology is similar. "Are we going to cover Django," says [? JL97. ?] Not today. Maybe in a future stream we might cover Django, but today is just on Flask. And saltyglowstick was saying, they did some research on why app is equal to Flask__name. And it was saying the __name variable provides the name of the package. And then Flask uses this value to find out what the location of the package is on disk, so it can locate other files in the same directory. KAREEM ZIDANE: That is correct. I mean, we're not really going to care about this right now, because we're not trying to find files by location relative to this package name or relative to the module name that we're using right now. But that is a correct explanation I think. COLTON OGDEN: "I really like these examples. Where can I find them?" And then [? Bela ?] actually linked to your-- this is correct, right, kzidane/flask-stream? KAREEM ZIDANE: Yup, that is correct. COLTON OGDEN: That's today's code. Yeah. So if you want to follow along with all these examples, follow the link that's actually hidden right now. Oh, Kareem is going to plug it right here in the chat. KAREEM ZIDANE: ://github.com/kzidane/flask-stream. COLTON OGDEN: Nice. KAREEM ZIDANE: All right. COLTON OGDEN: So check that out, clone that. It will be good. And then lastly, "is there a session on deploying using Docker? He should cover it in a different class, Docker session." And then, actually, yeah, we did. David and I did a very brief Docker tutorial, not very brief I should say. KAREEM ZIDANE: But I think he's asking about deploying [INAUDIBLE] applications using Docker. COLTON OGDEN: Oh, I see. Yeah. KAREEM ZIDANE: So containerizing [INAUDIBLE] applications maybe [INAUDIBLE]? COLTON OGDEN: I don't think we covered that, but, yeah, maybe in the future. Something like that. KAREEM ZIDANE: Yeah. Maybe we could demonstrate that using Heroku or Elastic Beanstalk or something. COLTON OGDEN: Yeah, that could be useful to some people I think certainly. KAREEM ZIDANE: All right, so this part that I just explained in the register function is exactly the same as the previous example, which I forgot to explain. The extra part is actually remembering that the user is logged in or not, which didn't happen the previous example. COLTON OGDEN: OK. KAREEM ZIDANE: And for this, we're going to use something called a session. COLTON OGDEN: Right. KAREEM ZIDANE: And so the way a server remembers whether some user is logged in or not is by sort of giving them a unique identifier when they log in. COLTON OGDEN: Right. KAREEM ZIDANE: Right? So in the response, it gives them a unique identifier, a cookie, right? And then when the browser tries to make another request to the same server, by default, it tries to send that cookie. COLTON OGDEN: OK. KAREEM ZIDANE: Right? And so the server gets that cookie again, gets that identifier again, and knows that, hey, this belongs to this user. And so it retrieves all the information about them and shows that they are logged in in this case and greets them with their user name. And so the way to initialize a Flask [INAUDIBLE] session is really simple. So from Flask, we should import session, as we see here. Right? And then the package that we were using is actually Flask-Session, right? And then we're going to import Session with a capital S here. And then we're going to instantiate this Session class that we imported and then pass it app. And so this is the way we initialize the session in this case or Flask [INAUDIBLE] using sessions in this case. There's also a couple of session configurations in this case. I'm using my file system as opposed to-- so I'm not storing, essentially, the data on the client side or on the user's computers or the user's devices. I'm storing the data actually on my server on my file system and distributing some kind of unique identifier that sort of references this data. And I just don't want my session to be permanent. I don't want them to last forever in this case. COLTON OGDEN: Also, thank you for-- I don't know if I'm pronouncing this correctly-- [? Frefa ?] or [? Fr3Thou, ?] Treet_top and codekip, thank you very much. KAREEM ZIDANE: And so a session essentially ends up being a simple Python dictionary, right? And so to insert a value in that dictionary, we just use the bracket notation. In this case, we're inserting a key called user name with a value user name. But, ideally, you can remember pretty much anything here. You can remember their ID instead if we have such thing. Unfortunately, we don't use an ID here. But, ideally, that's the thing that's remembered, a numeric number that identifies a user, right? After remembering that the user is logged in after they register, we just redirect them back to index. And when they go to index, this is what's going to happen, right? Let's actually take a look first at the index function. And the index renders the index template, passes in the title, like last time, and then passes in a user name from the session. COLTON OGDEN: Right. KAREEM ZIDANE: So if there's a user name in the session, this is going to be the value of this keyword argument. Otherwise, it's going to be none, right? And this is what it checks for. If the user name exists, show this specific greeting. Otherwise, show the log-in or register message. Cool? COLTON OGDEN: Makes sense, makes sense-- lot of session import worries in there, three different ones. KAREEM ZIDANE: Yes. COLTON OGDEN: It's pretty funny. KAREEM ZIDANE: All right. COLTON OGDEN: [? Jiban ?] was asking, "are you going to cover the security issues of sessions?" KAREEM ZIDANE: Am I going to cover the security issues of sessions? Not really. I believe [? Theodore ?] mentioned once on one of the streams, I mean, probably the most common security issue with session is called session hijacking. And this happens by means of stealing someone's cookies and using them. COLTON OGDEN: Using them to authenticate the server. KAREEM ZIDANE: And so you appear to that server as that person, but you're not. COLTON OGDEN: Makes sense. KAREEM ZIDANE: So we're not really going to go into much more details about this. But this is the basic idea of hijacking. COLTON OGDEN: If anybody wants to try and steal Kareem's cookies-- KAREEM ZIDANE: Yeah, feel free to. All right, so the log-out function, which happens here when we visit the /logout, just clears the session, so forgets that the user is logged in and, therefore, logging them out. COLTON OGDEN: OK. KAREEM ZIDANE: Right? So it's as simple as that and then redirects back to the Index page. Show I click this link, I should see the message that appeared if no one is logged in again. COLTON OGDEN: Correct. KAREEM ZIDANE: All right. COLTON OGDEN: [INAUDIBLE] says, "thank you very much for the follow-up." And then [? Andre ?] was making a joke. "Stealing someone's cookies? What are they, monsters?" Because Cookie Monster. KAREEM ZIDANE: Yeah, well. COLTON OGDEN: "Can you use JS frameworks with Flask" says [INAUDIBLE]?? KAREEM ZIDANE: In what sense? I mean, I know Flask probably has a JavaScript framework that sort of wraps some functionality in like the URL for something. I haven't used them much. But, yeah, I'm not going to use any today unfortunately. COLTON OGDEN: If they're referring to maybe using Flask and JavaScript together just in the normal sense, then you can use JavaScript with any back end framework? KAREEM ZIDANE: They're just run in different contexts. COLTON OGDEN: Yeah. KAREEM ZIDANE: So the Python code that you have is actually a run on the server side, but the JavaScript code is actually run on the client side or inside of your browser or something. COLTON OGDEN: Right. KAREEM ZIDANE: But, yes, I mean, if you're referring to any JavaScript framework or any JavaScript code in general, there should be no problem using that with a Flask application in this case. COLTON OGDEN: People are saying that, recently, there was the cookie session hijacking with Facebook, [INAUDIBLE] brought that up. And then some other folks were mentioning that as well. KAREEM ZIDANE: Yeah. I mean, some of these issues happen from time to time. And you should definitely be careful about that. The stream is not, unfortunately, on security. So we're not going to dive too deep into it. COLTON OGDEN: Yeah. KAREEM ZIDANE: But it's definitely an interesting thing to look into and see how you can protect yourself like from exploiting yourself to such attacks. COLTON OGDEN: And Bagelcrush, thank you very much for following as well. KAREEM ZIDANE: Thank you. COLTON OGDEN: Cool. KAREEM ZIDANE: All right, so let's take a brief look at the get user function that we referred to earlier. And this is just a helper function that essentially opens the CSV files, reads in the rows. And if it found the user name in one of these rows, it returns that row. And that's it. And so you could get fancy with CSV files and use like a sorted dictionary or DictReader or DictWriter and sort of refer to these by row user name or row password if you want. I'm not going to do that here. Again, typically, CSV files are not used for this kind of use case. We're just using them for simplicity. So I'm just going to go with numeric indices in this case. COLTON OGDEN: xyZed92 and ml_newb, thank you very much for following. KAREEM ZIDANE: Cool. All right, so now that we have a web application that allows us to register or log in or log out, what should we do next? COLTON OGDEN: Well, then you'll see separate information when they're logged in, right? Are we showing their name so far? KAREEM ZIDANE: Are we showing their name so far? Yes. COLTON OGDEN: OK. KAREEM ZIDANE: This should be like when they log in. I forgot my password. It's 123, I guess? COLTON OGDEN: Hard password to-- OK. So that's working. KAREEM ZIDANE: Yeah. They should see yours once they log in. COLTON OGDEN: So I guess maybe some other-- so I guess whatever the goal is of this application, which was-- KAREEM ZIDANE: Right. We're probably not going to transition to app4, which is I think the last example in this stream. But I just wanted to mention quickly that-- let's see. I think we talked about all of these except log-in. Log-in, essentially, is the same as register, except that it actually gets submitted to the /login route. And the button is called the Log-in instead of Register, of course. And if we look at the log-in function or the function that handles this /login route, it's also pretty much the same as register as well. If you receive a GET request, it would render the log-in template. Otherwise, we get the user name and password from the form and validate them doing some sort of validation, check that we have a record of a user, and check that actually their password matches in this case. And then if everything is OK, we just remember them in the session and redirect them back to index. COLTON OGDEN: Cool, sounds good. KAREEM ZIDANE: Otherwise, be sent a 403, which is unauthorized. COLTON OGDEN: What is it, invalid user name and password? KAREEM ZIDANE: Yeah. COLTON OGDEN: Unauthorized? KAREEM ZIDANE: Yeah. I'm trying to remember the control. COLTON OGDEN: Unauthorized makes sense. That sounds like something that they would write. KAREEM ZIDANE: So this is another HTTP status code that we can send in case the user is trying to do something that they're not authorized to do right in other words. COLTON OGDEN: Right. [INAUDIBLE] was saying, "use bcrypt for your passwords." KAREEM ZIDANE: Yes. You could use any hashing. I'm not familiar with bcrypt. But you could use any sort of hashing libraries. And I think by Python has actually built-in hashing mechanisms. COLTON OGDEN: Yeah. KAREEM ZIDANE: So you can pretty much do that. I just didn't want to complicate things, to try to focus more on Flask side of things. COLTON OGDEN: Oh, it's forbidden is what 403 is. KAREEM ZIDANE: Forbidden, yes. Not unauthorized, it's forbidden. Thank you. COLTON OGDEN: [? JL97, ?] "how would you prevent against CSRF forms?" KAREEM ZIDANE: OK. So people are trying to drag this into-- COLTON OGDEN: Cross-Site request Forgery, I believe that's what that short for. KAREEM ZIDANE: Yes. COLTON OGDEN: Flask has a module for that, doesn't it? Or like a built-in feature for that, CSRF? KAREEM ZIDANE: I think some browsers-- OK. So there are different ways to protect against these kinds of attacks. I think some browsers have some built-in mechanisms of sort of preventing some JavaScript from some other origin or domain to be executed on your domain. COLTON OGDEN: Yeah. KAREEM ZIDANE: so I'm not sure if this is a different kind of attack or not, but some web apps sort of include a unique token in the form to be submitted that's valid for a specific duration or something. So they use that as well. Does Flask have something built-in to [INAUDIBLE]?? COLTON OGDEN: Yeah. It looks like there's a Flask WTF, interestingly enough. KAREEM ZIDANE: What The Form. COLTON OGDEN: Yeah, What The Form-- which has a .CSRF. And you can import CSRF protect. And then you have to instantiate that. You have to wrap your app around that basically just how you do a session. KAREEM ZIDANE: Yeah. Yeah. I mean, I have to look into this more honestly. But I believe it injects some kind of hidden sort of input with some unique value that it then verifies, so that no one can sort of submit this form-- COLTON OGDEN: Yeah. KAREEM ZIDANE: [INAUDIBLE] were. COLTON OGDEN: Yeah, you do. You use a hidden form that has the token injected into it by the server. KAREEM ZIDANE: Yeah. COLTON OGDEN: "You guys should give an included security session." KAREEM ZIDANE: Yeah. Definitely, yeah. That would be a cool idea for a security stream. COLTON OGDEN: David's like an expert on security. So I sort of feel like he'd be great to do a security stream. I'm not that great at security, one day maybe. KAREEM ZIDANE: Yeah. COLTON OGDEN: I'll ask him if he wants to do like a basic security stream, because that'd be pretty fun. KAREEM ZIDANE: All right, so the last example that we have today is app4. And app4 essentially builds on top of app3, but also adds-- let me actually run Flask here like last time and then show app here. So it's mostly the same as the pie from app3, except that, first of all, it adds the flash message. So let me actually show this, because this might be useful to show. So if I go back into my app3 folder and I run Flask again-- and let's suppose I'm logged in already. If I visit register with a lowercase-- OK, so I added this functionality to app3 as well. COLTON OGDEN: It looks beautiful. KAREEM ZIDANE: So this message shows up here. You can't actually register a user. Or we chose that you can't register a user if you're logged in already. So you must log out first. COLTON OGDEN: So this is a flash message that you're just included? KAREEM ZIDANE: This is a flash message that, you know, it appears as an ordered list item. And the way this is implemented is-- COLTON OGDEN: It's a list in case you want multiple flash messages? Is that why you shows a list? KAREEM ZIDANE: Correct, yes. COLTON OGDEN: OK. KAREEM ZIDANE: Yeah. You can flash multiple messages. And they would, in this case, show as a list. [INAUDIBLE] COLTON OGDEN: I love that unstyled HTML. It's gorgeous. KAREEM ZIDANE: Yeah. I hear you're going to do a steam on CSS soon. COLTON OGDEN: Yeah, tomorrow. KAREEM ZIDANE: So maybe you should do that. COLTON OGDEN: We're going to do a basic CSS stream tomorrow at 1:00 PM. So tune in for that if you're curious about a little bit of CSS. KAREEM ZIDANE: Yeah. As you can see, my apps are really, really ugly. So I'm going to watch your stream. COLTON OGDEN: Mine are, too. Don't worry. I'm not very good at CSS, but I know the basics. So we'll have a nice lovely stream on it tomorrow. We'll talk about just some of the basic stuff. KAREEM ZIDANE: We have a little bit of CSS in app4. We're not going to dive deep into that. We're going to leave it to you. But the idea of flash messages is here. So in the register routes, if there's a user name already in the session, so if there's a user logged in, I'm just going to call flash. And flash is imported from Flask as well. COLTON OGDEN: OK. KAREEM ZIDANE: Right? And then I'm going to pass it some string here-- in this case, this string has a piece of HTML-- and redirect back to index, right? And so the effect of that is that this flash message is going to show up in my Index page or any page in this case because I've actually added this logics and layouts. And much like we have if statements with Jinja-- COLTON OGDEN: Right. KAREEM ZIDANE: --we also have for loops logic-- COLTON OGDEN: Iteration. KAREEM ZIDANE: --in this case. So if you read the Flask documentation, you'll find the snippet of code that tells you how to consume your flash messages. And in this case, you get the get_flashed_messages. And you check if there are messages. You just loop over them. So this syntax for a for loop in Jinja is fairly similar to the syntax of a for loop in Python. COLTON OGDEN: Yeah, it looks pretty much like they took Python and, with a couple of exceptions, they put it between percent brackets. KAREEM ZIDANE: Correct. And there's no column here. Like, the indentation-- excuse me-- doesn't really matter. So in this case, we have to have an end for, end if in case of an if statement. So these are [INAUDIBLE]. COLTON OGDEN: I like how it has context managers, too, though, the with. KAREEM ZIDANE: Yeah. COLTON OGDEN: That's pretty cool. KAREEM ZIDANE: Yeah. It's really fancy. So, yeah I'm essentially in looping through all these messages using a loop in Jinja and then displaying or rendering each message, passing it to a Jinja filter safe. COLTON OGDEN: Right. KAREEM ZIDANE: Because I know my message actually include special characters, include HTML. COLTON OGDEN: So HTML escapes. KAREEM ZIDANE: Correct. COLTON OGDEN: OK. Nice. KAREEM ZIDANE: So this actually says that, hey, trust this message. I know what I'm doing. This has HTML in it. Otherwise, it would actually show the literal HTML. COLTON OGDEN: Oh, I see. OK. Yeah, makes sense. KAREEM ZIDANE: Yeah. It would really escape this and show the angle brackets. COLTON OGDEN: So it's actually not escaping it. It's actually giving it as raw. KAREEM ZIDANE: Yes. COLTON OGDEN: OK. That makes sense. KAREEM ZIDANE: Correct. All right, so in app4, which is this file right here, we have the same registration log-in, the same log-in, log-out. And the thing that we added-- and let's actually run the [? app4 ?] [? surf ?] application. So if I reload this, I actually-- OK. I saw a bug here, but never mind. So we see-- and this is sort of a spoiler-- no posts yet. COLTON OGDEN: Font's different there, too, it looks like. So you got a little bit of styling there. I like it. KAREEM ZIDANE: Yeah. Yes. COLTON OGDEN: Oh, did you include Bootstrap? Is that what that is? KAREEM ZIDANE: I don't not. COLTON OGDEN: Oh, OK. KAREEM ZIDANE: I just included a couple of style properties and values. COLTON OGDEN: Got ya. A little bit of fancy hand-written CSS, you know? KAREEM ZIDANE: So let me register you, or register me really, because I'm going to post on my behalf, right? COLTON OGDEN: What's on your mind? KAREEM ZIDANE: So once I'm registered in, I have this form that looks familiar to that of other social media websites. And the idea is that I will be able to, hey, post something. You know, I was on Colton's stream today. COLTON OGDEN: That's right-- or I'm hungry today. KAREEM ZIDANE: Or I'm hungry. And post it. COLTON OGDEN: Or both. KAREEM ZIDANE: And it would show up like this. COLTON OGDEN: Oh, nice. I like that. I like that. Now, is this all client side at this point? KAREEM ZIDANE: Not really. COLTON OGDEN: Are you storing these? KAREEM ZIDANE: I'm redirecting, but it's really fast that it didn't like take a long time loading? COLTON OGDEN: No, but I mean are you storing these posts in a database? KAREEM ZIDANE: I am. Well, I'm not storing them in a database. I'm storing them in the CSV file like we did. COLTON OGDEN: Oh, OK. KAREEM ZIDANE: But, ideally, yes. You would be storing them in a database. COLTON OGDEN: Interesting. Is in a separate database from the registrants? KAREEM ZIDANE: That is correct. And so much like you would have a separate table for posts than users, I have a separate file here called post to CSV that essentially includes the content of the post-- COLTON OGDEN: The user name and the timestamp. KAREEM ZIDANE: --the author of the post, and the timestamp. Yes. COLTON OGDEN: OK. KAREEM ZIDANE: And then if we take a look at the user, it's exactly in the same format as before, nothing different, nothing fancy. COLTON OGDEN: So does your logic then iterate over the table of posts and just all the ones that have the same user name? It'll just output them? KAREEM ZIDANE: That is correct. So let's actually see what happens when we see the Index page. So when we go to the Index page, what happens is that we render the index.html template. We pass in the title as usual. We pass in the user name as usual. And then we pass this extra thing called get_post or posts, keyword argument. And the value of that is get_posts. So let's take a look at get_posts. Right here, we're opening the post CSV files. We're reading all of it. And we're sort of returning, liking massaging this data and returning it as a list in Python. So we take the first cell in each row and pass it as the value of the content key, second cell author key, and third cell is the date time, right? Otherwise, if there are no posts, we just return an empty array or empty list. COLTON OGDEN: Cool, makes sense. KAREEM ZIDANE: OK. COLTON OGDEN: I can see it as being very performance heavy if you had like 10 million posts. KAREEM ZIDANE: Definitely. And this is why-- COLTON OGDEN: This is why you need a database-- KAREEM ZIDANE: This is why you need a database. COLTON OGDEN: --with indexing. KAREEM ZIDANE: And even if you have a database, this is why you should limit whatever you're showing to the users. COLTON OGDEN: Yeah, like 10 at a time. KAREEM ZIDANE: Facebook doesn't show you billions and billions of posts once you [INAUDIBLE]. COLTON OGDEN: It feels like it. KAREEM ZIDANE: Well, yes. But it actually asynchronously loads more posts as you scroll down or whatever. So let's actually take a look at the index.html template. And if you go to that one, the content has the few things that are different in this case. Let me indent this correctly, so that we can see better. Well, I don't think it would matter. So it chose something similar to before when you're logged in, hello user name if you're logged in and then hello [INAUDIBLE] link. But there's also this form right here that's submitted to /posts. COLTON OGDEN: Right, that's the text area. KAREEM ZIDANE: Correct-- using the POST request method. And there's the text area where we type our post here. And there's a placeholder. COLTON OGDEN: It's an amazing placeholder message as well. KAREEM ZIDANE: Yeah, well, thank you. It didn't come from scratch. COLTON OGDEN: Very enthusiastic. KAREEM ZIDANE: Yes. And so there's a Submit button with post on it, right? And so what happens when you submit a form like this? The first thing that happens is that we get the content of the post. And we make sure that there is a user already logged in, because we don't want to allow arbitrary people, like anonymous people, on the internet to post something. So we get the author of the post. And we validate that. We see if there is no post or, if the post is empty, show that this is a better request. If there is no author or if there is no one logged in, show forbidden, 403, with some descriptive messages here. And then like we did with registering users, we just open the CSV file. We insert a row in this case. The content of this row is the content of the post plus the author, the user who's logged in, and then the current time and date. COLTON OGDEN: Cool. KAREEM ZIDANE: And that's how we store this, right? And so this is, I think, all what I have for today. We can demonstrate this more. We can have, you know, it was good. COLTON OGDEN: In case anybody was curious. KAREEM ZIDANE: If I reload this page, it should-- COLTON OGDEN: Nice. KAREEM ZIDANE: --technically show the same thing. COLTON OGDEN: It loads it all at the beginning. That's cool. KAREEM ZIDANE: And so this is the first step on creating another social network. COLTON OGDEN: Yes. It'll be the next Facebook-- KAREEM ZIDANE: Yes. COLTON OGDEN: --the next, you know, sort of usurper of Facebook. KAREEM ZIDANE: So, yeah, I hope that was useful for a quick introduction to Flask today. COLTON OGDEN: Yeah, that was awesome. Thank you so much. We'll catch up with all the chat here. KAREEM ZIDANE: Thank you. COLTON OGDEN: Then we'll close it up. People are saying they're waiting for the CSS stream. "Should I learn Flask or Django," says [INAUDIBLE] or [INAUDIBLE].. KAREEM ZIDANE: Django, I think, is a bit more difficult to use or get started with than Flask at least for me. So if you don't need Django, if you don't have a specific use case that you need Django for, probably start with Flask-- easier, simpler, quicker. COLTON OGDEN: [? Frame ?] [? of ?] [? Ref, ?] "where can I keep track of upcoming sessions? Go to facebook.com/cs50, which I'll type here in the chat. KAREEM ZIDANE: Whoops, that's slash-- COLTON OGDEN: Whoops. And if you go to this URL, you can see all the events and videos that we have coming up. But I'm also going to work on getting a schedule integrated into the Twitch site as well. So thank you for the question. "Are you going to talk about Bootstrap tomorrow," says [? Bavik. ?] Not Bootstrap tomorrow, no. Tomorrow is just going to be raw CSS and pretty simple ultimately. If you're already familiar with CSS, it's probably going to be old hat for you. It will open us up to be able to do more a advanced CSS stream in the future. But, no, it's going to be pretty basic. No Bootstrap. Bootstrap we'll have as a separate stream. "I get intimidated by CS-only tags on CodePen and some crazy 3D animation using a ton of CSS," says [? NACL ?] [? Eric. ?] Well, I hate to disappoint you, [? Eric. ?] But tomorrow we are not going to be doing 3D animation in CSS. I wish I was that skillful, but unfortunately I am not. But, you know, maybe in the future if I find somebody here that's just amazing at CSS, we can have a follow-on stream which does some of that crazy stuff. KAREEM ZIDANE: Can you be amazing at CSS? COLTON OGDEN: Me? KAREEM ZIDANE: Anyone? COLTON OGDEN: Oh, can you? Oh, yeah. The people on CodePen that do this stuff, I'd say they're probably amazing at CSS. KAREEM ZIDANE: Wow, OK. COLTON OGDEN: "Flash versus Django, everyone says I should learn Django for fast development. What are your thoughts on that?" Kind of the same question as before, right? KAREEM ZIDANE: Yeah. COLTON OGDEN: Yeah. I could see Django being fast if you're really familiar with it and you ship all the time with it and you have a workflow. But I think if you're in brand new to that ecosystem, it's probably more time to get started with Django than Flask. Because Django is just so much bigger, so much more robust. There's a higher learning curve, same with Rails, for example, being a pretty large framework. "Does Flask code appear on the browser page source," says [? olegasemi1376? ?] KAREEM ZIDANE: That's a great question. No, it doesn't. So this is actually something that we should have explained. When you call render template on the server side, what it actually does is that it loads your template. It sort of processes it, so it resolves the extends whatever with the actual base HTML file that we have. It plugs in all the necessary values that we plugged in using our code. And at the end, it produces a big HTML file with everything processed and resolved. And what we end up seeing is actually the things that we care about here. So there is no Jinja syntax here. There is no Python specific syntax here. All of it is actually the code that we [INAUDIBLE].. COLTON OGDEN: It serves it just like a regular HTML page. It looks like it was completely hand-written-- KAREEM ZIDANE: Yes. COLTON OGDEN: --by somebody. KAREEM ZIDANE: So this is often referred to our server-side rendering. There's also client-side rendering, which is you can do something like this similar with a front end framework like React or-- did we cover React? COLTON OGDEN: Brian covered React, some basics of React, yeah. KAREEM ZIDANE: Brian covered it, yeah. So you can maybe look at Brian's stream for a React tutorial and see how you can do client-side rendering as well. COLTON OGDEN: "I'm eager for two sessions, one on databases and two on Heroku slash Docker deployment," says [INAUDIBLE].. Yeah. That's be cool. KAREEM ZIDANE: Yeah. COLTON OGDEN: "People are saying that the hardest thing about making APIs is designing your data. Somebody else mentioned it was a headache deploying my Flask app on Heroku and connecting the database." So that'd be cool to talk about. KAREEM ZIDANE: Yeah. Yeah. We should probably talk about this in the future stream. It would be interesting. Of course, you can do this without Docker at all. Or you can do it with Docker and sort of make a couple of things easier for yourself since the environments are going to be the same. But, yeah, that would be something interesting to look into. COLTON OGDEN: And then, "the hardest thing about making APIs is designing your data." Again, yeah, that'd be interesting to have an API stream. Brian did an APIs and ORMs lecture for CS50 Beyond. So maybe we'll get him in here for APIs conversation. KAREEM ZIDANE: Yeah. COLTON OGDEN: And thank you very much from [INAUDIBLE] and [INAUDIBLE] and also [? Scout969 ?] for the follows, much appreciated. KAREEM ZIDANE: Thank you, all. COLTON OGDEN: Ba, ba, ba, let's make sure we're all caught up. "Thanks Kareem the Dream and Colton. There we go. We almost got through the stream without it. We almost did it. No, we got it. We got it in there. KAREEM ZIDANE: Yeah, thank you for watching this. COLTON OGDEN: "On forms, should the content type [INAUDIBLE] type equals be set?" says [? Jiban3. ?] Encoding type, I'm guessing, that's short for. KAREEM ZIDANE: I believe so. Yes, I think forms have a default encoding type. But long story short, you can sort of submit the data using different formats. I think the default formats, I can't even remember the names, like duh, duh, duh, data slash something. And this is the sort of key value pair format. So if you have an input field with a user name and the value foo, it will be submitted as literally user name equals foo. But there are other for encoding formats like JSON, for example, where it would be submitted as a key for the JSON object. And the value would be the foo in this case. COLTON OGDEN: Got ya. And [? Andre ?] says, "yes CSV file-based Facebook is the next big thing. I'm sure it'll be very performant." KAREEM ZIDANE: Wow. COLTON OGDEN: [? Kiefa ?] is asking, "how do you implement up-voting for posts and comments? What's the logic look like?" KAREEM ZIDANE: That's a great question. This will be another piece of data that you would have to keep track of. Ideally, you don't really want to reload the page, though, when someone up-votes your post. So this will be ideally done using an AJAX request. And so the idea of an AJAX request is that you would be sending a request using JavaScript from your browser without actually reloading the page. And the server would receive this request, process it as usual, and then maybe change something in your database or CSV files in this case. So you would have to keep track of some counter. And every time you receive a request for this particular post with an ID, you just up this counter by one or down it by one if you're down-voting. COLTON OGDEN: "Awesome stream," says [? Bela. ?] "Thank you, Kareem and Colton." Thanks, [? Bela ?] for tuning in, much appreciated. KAREEM ZIDANE: Thank you so much. COLTON OGDEN: "Thank you for the stream," says [? Bavik, ?] much appreciated for your attendance. "How would someone go about connecting React or another front end framework to Flask? Will it interfere with the default Jinja templating?" KAREEM ZIDANE: Yes. That's a great question. And I actually looked into this briefly before. And I don't think there is an ideal way to do this. Like, it's certainly possible. It's just going to give you headaches. Because as you mentioned, the syntax for Jinja is going to be problematic with syntax for React. And so ideally, that's why frameworks like React are typically used with, I think, a node back end. COLTON OGDEN: Node back end with an API, so you don't have to worry about templating. KAREEM ZIDANE: So you could use an Express or something. COLTON OGDEN: Yeah. KAREEM ZIDANE: They usually contain something putting-- I guess you could disable that, or you could sort of try to get around it somehow. COLTON OGDEN: Yeah. KAREEM ZIDANE: But you're right, that's a good point. COLTON OGDEN: [? Hela ?] from Belgium says, ""[INAUDIBLE] was wondering what Linux distro Kareem is using." KAREEM ZIDANE: I'm using Ubuntu 18.10, which is the latest version of Ubuntu. Yeah, so it's been working well so far. COLTON OGDEN: Cool, looks great. I think that's all the questions. If anybody has any last questions, that would be awesome. [? Kiefa ?] [INAUDIBLE] from Nairobi, awesome, thank you so much. "Great session. Thank you for answering our questions. See you tomorrow," says [? Kiefa. ?] Yup. See you tomorrow for some CSS. KAREEM ZIDANE: Thank you so much. COLTON OGDEN: Yeah. We'll stick around for just a couple more minutes in case anybody has any last questions. And then otherwise, we will bid you adieu and see you tomorrow. Or at least I will see you tomorrow for some CSS. And then the day after, we will review your source code live on Twitch, so that'll be a lot of fun. KAREEM ZIDANE: Yeah. That's exciting. COLTON OGDEN: We got to get you in here again for another stream, too. KAREEM ZIDANE: Hopefully, yes. COLTON OGDEN: And as always, many of you have been contributing your ideas fantastically. So keep doing that. We want to hear all of your ideas for future streams, so we can keep producing some awesome content. So any topics, anything you want us to build, anything you want us to talk about, that would be nice. [? JL ?] asking, "where did you submit the code?" So do you want to plug your repo in there one more time? KAREEM ZIDANE: No, I think he's asking about the code review thing. COLTON OGDEN: Oh, right, right, right, right. So that is at bitly/cs50twitchcodereview. And then [? Frame ?] [? of ?] [? Ref ?] included the longer you URL that Bitly actually maps to. But you can go to either of those. And there will be a form asking you for your GitHub repo or a Gist link, so that we can look at it, make sure that it's ideally not a CS50 pset so that we don't spoil the solution for anybody online. Also, it's more catered again towards beginner or intermediate programmers. It's not meant for bug testing. So if you have any bugs, we won't be debugging your code live on stream. But we will answer any style questions you might have. We will be looking at the style, critiquing it, critiquing the design, making sure that it's well-implemented, well-formatted. And regardless of your experience level, you know, submit it. But, again, it's more catered towards folks that don't necessarily know maybe how best to style, or design, or code yet and are just kind of beginning. "Gist is adding extra spaces in the code, anyway to solve it" says [INAUDIBLE]? KAREEM ZIDANE: If you're using GitHub, when you were creating a Gist, it allows you to choose the number of spaces to use for indentation. COLTON OGDEN: Sure. KAREEM ZIDANE: So if you're using two, whatever, make sure to choose that. COLTON OGDEN: Yeah. And if you're copying and pasting in the middle of your code base, that might also be screwing up the spacing a little bit. So you can copy it to another file and Shift Tab it back to where it's flush with the left side. Ideally, the snippet should have some context. So maybe just include the whole function or the whole body. But you know, either way send us what you have. And if we can work with it, we'll give it our best shot. [INAUDIBLE], "thank you as always. You are wonderful." Thanks so much, [INAUDIBLE],, much appreciated. But I think that's it. I think we're all caught up. So thanks to everybody who tuned in live today. This was Flask. Thanks to Kareem for this wonderful stream. KAREEM ZIDANE: Yeah, thank you for having me. COLTON OGDEN: We built a very simple social network of sorts, more like a blog at this point it looks like. KAREEM ZIDANE: Yeah, correct. COLTON OGDEN: But, yeah, no, it was awesome. So we got to cover Flask. KAREEM ZIDANE: Thank you so much. COLTON OGDEN: If you were looking to get into back end programming with Python, this is a good starting point. Tomorrow join us for front end, more front end stuff. So last week, we did HTML or two weeks ago we did HTML. This week we're going to do CSS. Tomorrow we're going to do CSS, Cascading Style Sheets, the basics. Again, I'm not an expert. I'm not going to wow you with my amazing CSS skills, because I don't have amazing CSS skills. But I will get you on the right track if you are an aspiring web developer. So thanks so much everybody once again. This was CS50 on Twitch with Kareem and Flask. I will see you all tomorrow. Bye-bye.
B1 中級 FLASK BASICS (SERVER-SIDE PYTHON) - CS50 on Twitch, EP.31 (FLASK BASICS (SERVER-SIDE PYTHON) - CS50 on Twitch, EP. 31) 6 0 林宜悉 發佈於 2021 年 01 月 14 日 更多分享 分享 收藏 回報 影片單字