Transcripts
1. Introduction: hi and welcome to from zero to flask. My name is Jorge Escobar and having building professional python applications for the last 10 years and now want to teach you from scratch how to build flask applications using the techniques used in real world tech companies. Flask is my favorite Python Web framework. Ah, framework is a set of libraries and tools to make Web development easier and more efficient as it tackles all the functionality required by the majority of the applications. And let's who focus on the creative parts. At the end of the course, you will have built a python flask based that a vase driven personal blogger application using the techniques I will show you. You will also have to develop a brand new feature using the concepts you learned in the course. The course starts from the Basic Flats concepts and slowly builds into areas like database fundamentals. Building the or in models, templates, image processing and secure formed the sign. There are many flats, courses and tutorials out there, but this is the only course to take the professional approach I use in all my courses. So if you're ready to start your journey from scratch to become a professional Web developer, come join me. See you in the course
2. Roadmap and Requirements: In this course, you will learn the fundamentals off flask. How to isolate your dependencies using virtual environments. Then we'll go over routing templates, sessions and database migrations with a simple page counter application. We will then build a block publication with author registration, logging, post block articles adding photos, pagination and editing, and the leading posts in every step of the way. We will be writing unit tests for each of the block features, just like professional developers to. So what do you need to properly learn this course? First, you need to have a basic understanding off the Python language. I have an excellent course for that called from Zero to Python. But if you know the Python language basics, that'll be enough. Second, set up a development environment. We have two options in this course. You can install Python in my sequel locally in your computer, or you can follow the course using an online development platform where you can code in the cloud from wherever you are. And third, you need to be passionate about learning the professional way how to become a software developer. I'm sure you have seen some online tutorials or even taking some programming courses. However, I warn you, most of the material out there is not updated or teaches the most advanced concepts and uses a lot of point and click tools and easy concepts. If you want to learn the easy way. This is not the course for you. But if you want to learn and suffer a little bit at the beginning but come out on the other end with solid knowledge, then you have found the right course.
3. Your Python Flask Development Environment: like I mentioned earlier, we have two options to set up our python flask development environment. The first is to install flask locally in your computer. That means you have administrator access and canning stole packages. The second is to use an online python development environment. Here you will sign up to a cloud based service where you can code from anywhere you like your home work, computer or even an Internet cafe. There's no installation required. Select the one that's appropriate for you in the following lessons.
4. Installing Python3 on Mac with Homebrew: my fairy package manager for the Mac is home, and that's what will use to install by phone three between stole homebrew. Just go to the humble website below now, Corbyn echoed on the homebrew home page. Now open a new terminal window. You can open the terminal by going to the spotlight. Search on typing terminal. Once the terminal window is open, based a homebrew code and press enter. Wait until all the files are installed to check that everything was properly installed to our brew doctor. Now we'll install Python three. Doing so bites on three. Just type the following brew. Install five from three. Wait until the script finishes to make sure Python three wasn't still properly type Python three Dash Capital V and that's it. Now we can begin our course.
5. Installing Python3 on Windows 10 with Chocolatey: My favorite package manager for Windows is Sugar Lady, and that's what will use to install by phone. Three. Head over to the shock a lady install page and copy the code in there. Now open a power shell terminal. You can find it by pressing Windows Plus R and then typing power shell. However, you need to run as administrator. So right click on the window and on the menu. Select Run as administrator based, recording the power show window and press enter. Wait onto the program is installed. Close the power shell window and open it again as an administrator. Remember, every time you use Sugar Lady to install packages, you need to run power Shell as administrator. Technological lady was installed properly by typing Choco dusty. If you see a version number, you're ready to go now to install, bite on three just to Shoko. Install dash y python three. Close and reopen Power Shell as administrator to make sure that path settings for the python package are applied to make sure Python three was installed properly, type by phone dash over Case V and that's it. Now we can begin our course
6. The Cloud-based Python Development Environment: I'm constantly searching for the best python cloud development environment and I keep coming back toe Python anywhere. They are completely free, but they have really good plans. They have amazing customer service and they have my sequel and post great support built in in this lesson. We will look at how we create our python anywhere account to start the process. Please use the following referral link Toby fully open with this link, I get a small commission if you sign up for a paid plan and this helps me continue to bring you more good content. Thanks In advance, when you land on the page, you will see a welcome page Click on the green button to start the process here you will represented with the different plans. For the purpose of this course, the beginner account is more than enough. If you're thinking of hosting a personal site with your own domain or one better speed and performance, choose any off the pay plans. So go ahead and create the account. You will be asked for a user name, email and password. Make sure to confirm your email with the link they'll send you, and that's it. you will arrive to the dashboard. Don't worry about this yet. We'll start covering how to do all the stuff in the coming sections.
7. Virtual Environments: one of the fundamental tools off your python development environment is the concept of virtual environments or virtual ins. Think of a virtual environment as an enclosure in your computer, where you can install python, an additional libraries as well as your own code without interfering with your computer in general, as well as with other projects. So each project you work on is going to have its own virtual environment. So let's go ahead and create our first projects folder and return environment in spite on any worse handling off. Where, perhaps is different, please scape toe that section.
8. Windows and Mac Virtualenv Setup: one thing that I recommend is that you put all your projects in one folder in your computer . It's not a good practice to just have projects lying around in different folders in your computer. In Mac type LS dash ale slash in windows type L S C colon backslash or whatever the drive letter you use, Please note. We will be using Windows Power Shell as our Windows terminal. If you have t slash oh pretty folder. That's great. If you don't, you can create it using make dear slash o p t. Or make fear backslash so pretty. If you get an error about administrative issues on Mac, use the pseudo command like this pseudo make their slash O p T. You'll need the administrative fast word for that. Then make sure to change the ownership to your regular user. You can see your user by typing Komai and then doing pseudo tone your user slash Oh, pity. Okay, now that's done. Change to the directory using CD slash obesity in Mac or C D backslash pretty in windows. Make sure you're in that directory by typing PWD and checking the path. Now let's create a folder called simple on the score flask underscore app. So do make their simple on the score flask on the score app and change to it with CD Simple on the score flask on the score up now will install are virtually. Do the following python three dash M V E n v ri Envy in Windows Python Dash M V E N V V E M V. This will create a folder called V E M V, where old packages will be installed after you activate your virtual environment.
9. PythonAnywhere Virtualenv Setup: because Python anywhere has restrictions on the user's permissions. Will need to create our directory using python anywheres custom set up. First, let's create a directory. Where will we install all our wraps? Normally, I would use slash appetit, But since we don't have admin axis will just create one in our home directory. So make sure you're in your home directory and then create a slash o PT folder here and inside of that are simple On the score flask underscore APP folder. Now we'll create our Rachel and for our application, So use the following command. This will create a folder in your home directory that looks like the following right down that path somewhere as well. Need it in a feature step. Now, just type the activate so that you can look out from your virtual. I'm
10. Activation and Deactivation: for your virtual IMF. Toby Active. You need to type in command. Toe activated. Activating it Makes the computer think that the main folder to install things is in RV Envy folder and not the root computers folder. So how do we activate it? Simply do source ve nb slash pain slash Activate on the Mac v e n b slash strips slash Activate on windows and work on simple flask app on python anywhere. Notice that now you have a V M V prompt or simple flask app front in your folder path. Not activating the virtual. And it's one of the main sources off issues for new developers. So before coding or installing anything, make sure you see that prompt. Otherwise, activate your virtual him. So the activate. Just type the activate in all platforms. Notice how they ve and be prompt Disappeared. Now we're ready to install flask
11. Installing Flask: it's time to install flask for our project. Since we don't want flash to be installed system wide, we'll use our virtual. I'm so make sure to change directory to your project directory by doing CD slash o pt slash simple flask app in Mac CD. Oh, pretty simple flash cap in Windows or C D o. Pretty simple Flash cap in by phone anywhere. Now remember, at this point we need to activate the virtual, and otherwise we'll install flask for all users in our computer. So do source. Ben being activate on mac dot vamps scripts. Activate on Windows or work on simple flesh cap on by phone anywhere. Make sure you see the ritual and Flavell important. This is, at the beginning, off the terminal prompt. So how do we install packages in a virtual environment for that use? The paper library is the Python package index, and it has thousands of open source packages available for you to use from Twitter. AP I Connectors Toe Web scrapers, Toe Web frameworks It's really one off hyphens. Greatest tools. People allows you to install specific versions off this libraries using a version number. Why is that important? The main issue is that as developers of great their libraries with more features, sometimes those changes can become an issue for our code as they might change the way you interact with the library. There's also issues if we have more than one library and they talk to each other so we'll be using version numbers for all the libraries will install in our projects and flask is no exception. So let's install flask version 1.0 point two in a virtual environment so type taping stall flask equals equals 1.0 point two.
12. The Code Editor: there are many good options for quote editors. Some of the most popular include sublime text by charm and visual studio code. I definitely recommend to try out some of them when you have the time and see which one you feel most comfortable with. However, for this course, I'll be using Adam. Adam is really simple and powerful at the same time and have been using it for some time, so I feel comfortable with it. So go ahead and install your co editor and we'll start building our hello world application next.
13. Hello World: so let's create a file. Inside are simple flask app folder. But first we need to activate our virtual environments for Mac, open the terminal and CD 20 p. T. Simple flesh cap. Then do source. Vend being activated to activate virtual and on windows to city back slash o p. D. Backslash simple Plassat. Then do vamp slash scripts slash Activate by phone anywhere Do CD till the oh pretty simple flesh cap, then do war Khan. Simple flesh cap. From this point on, when I say activate your virtual and please follow their previous instructions for your current operating system. Now we'll create a new file called Hello dot b y with our code editor inside the simple flask APF old for Windows and Mac type adam dot This will open the Autumn editor with this folder selected. If you're a Mac and that command throws an air like Adam was not found, just make sure to quit the atom application, open it again and select install shell comments. So how do we create hello dot B y on Windows and Mac? Select the simple Flask app folder first with your mouth and then hit the lower case a key on the input field. Type hello dot p y. Note that your folder might have contracted just clicking again to expand it and see the contents on by phone anywhere. Hit the hamburger icon on the top right and select files. Then locate the O. P. T. Folder on the directory section. Click on it and then click on the simple flask app link. Make sure you have the full path slash home slash your user name slash oh pt slash simple flash cap on the top left. Finally, on the file section enter Hello Duh p y and click on the new file button. Okay, we're ready to start coding our first flask application on the first line type from flask import flask. This imports the flask class in her file. We now need to create an instance of the class we'll call that object app. AP equals flask. On this going this core name on the score on the score notice we pass on this score in this court name, underscoring the score as a parameter. This is a python built in magic, viable that tells flask which module or package this is running from this allows flask to know where to look for related folders off our application. If an empty line on now type at APP, that route slash the at sign here is called a decorator. And essentially, this allows us to modify. The function will type underneath. We learned more about decorators. Later, on the route, decorator tells flask what your L dysfunction will be called on. In this case, this will be the root folder or slash. We now create our function, which just returns. Hello, world. Back to the browser Death. Hello, World return. Hello? Worked. And that's it. This is what the whole file looks like in the autumn. Editor. Notice how there's a little blue circle on the tap. That means this file hasn't been saved. Hit control plus s on Windows or command Plus s on Mac to save it on python anywhere. Notice how it says on safe changes on the top next to the false path, hit the green save button to save the fire. From this point on, you will be able to get the code on the screen using the from zero code shorter. You will see a little slider like this one pop up every time we have new code for you to add. Just type the code in your browser and you'll be taken to my kid hub repository. At that point in time, you can copy and paste the code from there, although I find it better if you actually code along so that you can get used to your editor and start training your brain to think like 1/4. Now we'll see how to run this application and seed in our browser. We have two different lessons, depending if you're in Windows or Mac or if you're in bison anywhere, escaped of the one that's right for you.
14. Running the Application (Windows and Mac): Let's see how we run this application on Windows or Mac. Once again, make sure to have your virtual M activated so that the word ve envy appears on the command . Prompt. If it doesn't activate to be able to run the application, we first need to set an environment viable to tell flask what application we want to run and then used a flask. Iran Command in Windows Power Shell said the environment viable with the following command dollar sign E N v colon flask underscore app equals Hello p y. In my quest, you said it by doing export flask on this crap equals hello. We can now run the application by typing the following command flask. Run now Open your browser. Untie. Pay this euro http! Colon slash slash 1 27.0 dot zero That one colon 5000 that 1 27.0 That's your other one. It's also called local host, and it's a special I p address that points back to your own machine. You should now see the string Hello world up here in your browser. That's it. Our first flask application. Start the application by going back to the terminal and hitting control. See under running task, Keep in mind that the flask app environment variable will be erased when you close your terminal. So if you stop here or restart your terminal or computer, you need to set the environment viable again. We will see how we can do this automatically later in the course.
15. Running the Application (PythonAnywhere): to run our application on python anywhere we need to register. Ah, Web app under system. So from the navigation menu, click on Web and you will land on the screen. Click on the Add a new Web button. You will be notified of the euro that has been assigned to you. Usually this is reduced her name dot python anywhere dot com For free accounts, that's the only option paid accounts can use custom murals. Click next. In the next screen, you select a Python Web framework. Since we installed Flash Ourselves via are Very Talev Select Manual configuration. The next screen asks what Python version to use. Select Python 3.6 and click next the next green talks about the creation off A W S G I configuration file. Don't worry too much about what WSC I means now. Just think of it as a file that tells the python anywhere server which application should be associate ID with your euro by phone anywhere will create a default ws g. I file for you to add it on the next screen. Click next. Now we're into the configuration page. There are some things to do here first noticed the best before date section. If you have a free plan, that means that at least once every three months, you need to press that yellow button that reads, Run until three months from today. Python anywhere does this to make sure users that are using the servers are actively doing so. Next on the code section, you need to select the source called directory, Click on the Blue Link and enter the following path, replacing the user name with your own user name. Slash home slash user name slash o p t slash symbol flask. Next on the WS G I configuration file, you'll need to replace the file contents with the following code. Just click on the Blue Link and enter this snippet, replacing the user name with your own. Use her name. We're almost done now. Head over to the virtual in section and select the Blue Link and just type symbol flask app by phone anywhere will order, complete with the full path when you hit Enter. So the whole thing should look like this, but with your own user name. Finally go to the top of the page and click on the green button under reload section. Now click on the blue, your URL on the top, or enter your user name that python anywhere dot com In the browser, you should see the Hello World text. If something didn't work, just rechecked the steps and make sure you're not missing something. It's usually some silly, small detail you miss.
16. Debugging our Application: one other things will spend the most time on as a software developer will be finding issues with your and your team's code. Also known as box, the booking mode is a parameter. You pass toe the flask environment so that when it encounters an unexpected error, it gives you more information about the conditions that trigger that issue. As you might already know, Flask runs on top off python with other libraries assisting. If you visualize your application at a certain moment of time, you'd see sort of a stack of pancakes. And when an error occurs, you need to see a cross cut off all the errors from your code all the way to Python. That's why when an error occurs, you'll be presented with what's called the error stack. To turn on the bargain mode, we will set a configuration parameter called the Bug on Flask. There are two ways to do this. One for Windows and Mac and the other on python anywhere. Escape to the section that applies to you
17. Debugging on Windows and Mac: open your terminal, activate your environment and do the following on windows Donor Sign the Envy colon flask on this court. Debug equals one and on Mac export flask on the score, debug equals one. Finally, restart flask by doing flask. Run. Now we'll introduce an error on purpose online. Six. Insert the following X equals one plus quote A. In quote. This will produce a string plus inter your error, Save the file and then reload the 1 27 serious here one cold on 5000 page on your browser.
18. Debugging on PythonAnywhere: to turn on the booking mode in Python anywhere you need to edit the whiskey file on the Web code section off dashboard and set the app dot de bark setting online. Eight. Off the file to True Saved a file. Now go back to your hello p WiFi will introduce an error on purpose online. Six. Insert the following X equals one plus quote a end quote. Save the file on Python anywhere. There's a handy reload server button undefiled editor. I suggest when you work with python anywhere you have to taps open on your browser in one, you'd have your coat editor and on the other, your public webpage. Whenever you do a co change, save the file. Hit the reload servers button and then go to the tab with your application and reload the page. One word of caution. When you're done debugging, I suggest return debugging motor. Do not leave the setting on for extended periods as malicious hackers can potentially extract information about your core base by looking at the debugging stacked trays
19. The Debug Stack: When you reload the page, you'll see something like this. It's a long page, and as you scroll down, you will see the error pointed out at the bottom. If you see a little above that, you'll see that flask tells you the line number and statement that produced the air. Sometimes you'll get lucky like this on the line with the issue is at the end. Other times it will be in the middle. Even though you don't understand all the errors in all the stacks, you have to try to search for the code you wrote. I didn't know the ones about older libraries. This is more art than science. But as you practice, you get better at it. Before we moved to the next lesson. Go ahead and elite line six so that our application is back to normal. Remember to save the file
20. Routing: the method of sending users to a specific part of the code based on the Ural is called Routing in Flask. This is done through the route decorator in our example. Earlier, we had the main route to execute the hello world function. Let's move that function toe another route and create a new function called Index. So modified the script after line for toe look like this. Save the file in Macon windows. You don't need to stop and start Flask. The Flash Theron command automatically picks up the changes. Just head over to the browser and reload the page in by phone anywhere. This is not the case. So remember to save and reload the server first and then check your browser attacked. Now you will see the text in experience on the route. But now if you go to slash low, you will see our old hello world string the Urals. We having the route can also have multiple parts. So, for example, you could assign the you earl slash yellow slash world with hello function and he would work the same. However, an interesting feature will learn now is the concept of viral parts in the euro. So, for example, let's say we want to grab whatever is in the second part of that euro and use it in the function. Modify line eight and after toe this saved a file and load a euro slash lo slash world. As you can see, the second part of the euro was assigned the name viable under out. Once you have that, we can pass it to the hello function as an argument. So what happens if we pass a number in the euro? Try it. It works perfectly well because flask is converting this toe a strength we can explicitly tell flask. That department are we expecting is a certain type. For example. Let's say we're expecting an integer after Hello. We can modify the code to read as follows. Save the file and on your browser type slash yellow slash four. We got on air. Can you guess what happened? That's right. Now the planet viable is an integer and we can't makes an integer and a string. So to return back the hello string we need to convert the planet toe a string. We can use the f function for that. Leslie, If you try passing a string like slash lo slash world, you will get a four afford not found there. Since flask is suspecting an integer in the second part of the euro, we can assign viral parts to a string integer float and a couple of other types. You can go ahead and look that up on the flask documentation.
21. Templates: as you build your application, the pages were returned to the user will start getting more and more complicated. It would get pretty messy if he had each function with a return. Viable several dozen lines long. So most wet frameworks work using a design pattern called Model View Controller or M V C. The sign patterns are a topic for another course, but just know that there are some best practices to approach computer problems that are well known so that you don't have to reinvent the wheel as your career advances. It's good to get acquainted with them, so write that down on your reading list back to NBC. This pattern basically advocates that your application is divided into three main components. A model, which is a file or set of files, which are dedicated to reading and writing from your database. A view, which is a file or set of files that deal with the presentation layer in Web applications. This would be HTML, CSS and JavaScript and a controller, which is the file or set of files that coordinate the user requests and loads and saves data using the models and presents it back using the views in flask. The views off the M V C moral are handled by templates. Templates are files that have as their input a set of variables called a context and usually outputs HTML. So let's go back to our script. You should have your virtual environment activated and half flask running. Let's create a templates folder. Flask has a couple of special directories that he looks for in every application and templates is one of them. In Windows and Mac, go to your Adam editor, select a simple flask, a folder and hit shift A. You will see a pop up that allows you to enter the name off the folder, enter templates When you hit the folder the first time it might contract and not show the folders. Just click on it again to expand. You should now see the templates folder in there in by phone anywhere. Go to your hamburger menu on the top right and select files on directories. Select oh, pity and then simple flask app, and then enter templates on the directory section and click on the new directory. But we will now create an extreme el file for the index page in Windows and Mac click on the Templates folder and now hit a You will see a pop up to enter the name of a new file Inside the Templates folder, you will see the directory in the input field. Make sure to right after it index HTML and press enter in by phone anywhere. You should still be on the file. Stab. Make sure the path on the upper left says Home your user name. Oh, Petey, Simple flask, app, templates and then right index html under files section and then click the new file button . We can now enter some HTML content in here, so let's just write the following h one index page and H one the h one open and closing elements. They note that this string index speech is a header level one, which is the largest. Notice how the first element doesn't have a slash on the 2nd 1 does. These tells HTML that the first is the opening tag and the second is the close intact. I won't go into detail on HTML, but if you follow along, you'll get the hang of it. You can also read a quick introduction towards female in the W three schools dot com website Save the file and now go back to the Hello p Y. And instead of returning the index page string online, six will do the following return. Render on the score template index html one last thing online. One When between port to render tempered function so after the import flask, aracoma and add render template so that the whole line looks like this from flask Import flask comma. Render template now save the file and head over to your route. Euro. Make sure it's the one without any parts. After the slash, you should see the index page displayed on the browser in Beit On anywhere. Remember, you need to save and then click on the reload server bottom. Once there were Lord is completed. Go to your site. Stab and navigate toe the route. Europe. As you can see, the user sees what we wrote in the HTML file, and now we can let that file handle anything output related and keep older routing and logic in the python file. But now let's see how we can pass information down to the template based on the user's input. The viable ZPass toe The template are collectively called context. In the second route, we have the hello planet function that outputs whatever number they use a road on the second part of the euro. So let's create another template on the templates folder will do. Hello, door ext. Email with the following HTML I called it t on the score planet. To make it clear that this is the templates Planet fire. Notice how we use double curly brackets instead of the one we use for the F string. Now the template will print whatever the value Off T planet it gets in the context. So how do you pass the context to the template? Modify lying 10 With the following, we're assigning the templates T planet viable. Toe the value off the planet viable. We get from the euro part say vote files and head over to the euro using any number you want. Now try changing the number to something else and pressing. Enter. You'll see the hello output changes
22. The url_for() Function: one thing you will do often your templates and controllers will be to put links to other pages. So, for example, let's add a link from the index page toe the Hello Paige in our application. Modify the index html by adding the following link on line three eight. Ref equals slash lo slash four. Hello slash This HTML tag is called a or anchor, and it allows you to link the current page to another page, save the file and head over to the index page. You should see this. If you click on the Hello link, you're taking toe the hello route. But let's say now we figure out that we want to change the euro off that function to grating so online. Eight. Go ahead and change the route to read up the route, slash reading slash into planet. Save the file and on your browser, go to the index page and click on the Hello Link. You will get an air now. It would be easy to just update the Hilo html template with a new slash grading euro, but more often that not you will have dozens or hundreds off links like this in your application. So instead of hard coding, the Ural Flax provides a function called euro four that allows us to tie the euro with a function name instead of the route. As function names will often not change as much. So let's do that. Go to the index HTML and replace the H ref with the following a trip equals euro four. Hello, Coma Planet equals four. Hello slash Save the file and go to the index page on the browser and reload. If you hover over the link and look at the address on the lower bar of the browser, you'll notice the euro is properly coded. Click on it and you'll get toe the hello page with no heirs. Now go back to the Hello P Y file and change the rock back to hello. Like so Save the file and reload the index page. You will see the link works perfectly fine and now generates the updated euro automatically
23. The Static Folder: There are certain files that don't need to be processed by our controller because they're always the same. The majority off these are presentation centric files like CSS or Jealous court files that improve the user interaction. Flask reserves a folder for this called static. And just like the Templates folder, it's a special folder. We want Dive to march on these types of files in this course, but let's say we want to make the text. We have a little prettier on our site. CSS Files allows us to do that by assigning funds and color toward tags, so create a static folder on the APS route, just like we did with templates. Now inside the folder create a file cold based dot CSS and entered the following. This will make our H one tax Toby Red and with a verdana font, save the file. And now let's change our index html to include the new base CSS file. We can do that by changing the file to look like the following. Save the file and reload your browser. It should look like this if for some reason it doesn't, it's because static files are often cash by the server and the browser, which your browser and restart the flask server and open the euro again. Even though this is technically working, there's a potential issue here, just like the page URLs can change. The location of the static folder can also change. The application can point to another directory within the server or another server altogether. For that flask has a special euro four method that will set the proper euro for your application so you don't have to worry about that. So own index html. Change the style sheet line to look like the following. Save the file and reload the browser. You should see the same output, but your basis says file your L it's now dynamically generated.
24. Template Inheritance: If you're still on the index page of the application and click on the Hello Link, you'll notice our hello pages title didn't change to read like the one on index HTML. That's because our hello HTML file is not including the CSS static file. Now. We could copy and paste all the HTML with did for the index page, but you can see how this could be problematic and violates the dry principle. Don't repeat yourself. Flask knows this, and it features something called template inheritance, which allows us to create common templates with sections that can be overridden by the active template. Sort of how class inheritance works. Let's see how we do that. First, we're going to define a base html file that is going to be the basic template for all off the templates. Go ahead and create basics TML as an empty file under templates folder. Now go ahead and caught from in this HTML the 1st 6 lines and the last two lines living on Lee the H one on the H ref lines and paste them on base html. Now we need to steps for the template inheritance toe work first on index html. We need to extend the base html template for that. We insert the following statement on line one extends base html Now when index HTML is render, it would use basic HTML as its parent. But now we need to tell flask where the content off index HTML will be inserted on base HTML. That's the second step, and it has two parts first in basic CML between the body tax. Insert the following block content en bloc. What this line is saying is that templates that extend this template can insert content in here using the content. Identify now on index HTML. We need to wrap the whole code with the same block. Extends based HTML block content H one index page and each one a trip. Ural four. Hello Planet equals four Hello and A and block save old files and reload the index page. You should see the exact same result, but here's where you'll see the value of this. Opened the hello html file and insert the extent and block content lines at the top on the end block at the bottom. Like so, save the file and now click on the Hello link on the index page in the browser. You should now see the Hello four letters in red. We can have more than one block in a template, and we can also set a default content for that block under parent template. That's still distinct. Toe fix any show we have now with the title tag. If you check on the browser stab, you'll see that both the index and the Hello pages have the same title index page. It's very important that each individual page has its own title, especially when search engines Kroll our pages. That attribute is set on the base HTML title tack, so let's make this the default Toby Index page if the extending template doesn't pass it but something else, if it is fast, so change this line, toe the following, save it and then open hello HTML. And add the following after the extends statement. But before the block content save the file and now you'll notice each page has a different title, as they should
25. Introduction to Forms: one of the main functionalities and application has is the ability to receive input from its users. To do this, the HDP particle, which is the definition of how webpages work created a set off commands defined as burbs. There are a number off http burbs that do different operations, but the ones will see in this lesson are get and post they get. Method allows you to send the user input from the webpage back to your application using the euro itself, for example, let's say we are writing a form the user needs to fill with their first and last name. They get euro for that operation could look something like this. See how we can see the viable in the euro. The one thing you need to remember is to start the list off field value pairs or query parameters with a question mark. Flask can read this parameters. Let's try that Head over to Hello P y. And let's create a new route that will read these parameters from the get request at the following code and the lying one. At request toe the imports list, save the file and then enter days on your browser. you will see the viable is have been received properly in the application. Notice how we added the new methods parameter on the route. This is a list of acceptable HDP methods that can interact with this view. Since we want to read get parameters, we added to get method here. Also notice that we are expecting both values to be present first name and last name because we're using the parameters without a list get method, which is you didn't confuse with the get HDB method. So, for example, if you only pass first name on the parameters in the Ural like this and hit enter, you'll get a 400 error, but request tow. Avoid that. You can use the following save the file, then stop the flash Server and restart as the contents of the page might have been cached by the browser. Now, of course, you don't expect users to type their first name and last name directly on the Euro bar. It would be better to render a nice form for the user. We can do that using HTML, so let's create a new template on the templates folder called Form HTML on HTML form is the five Using the form open and close tax, anything inside the stags will becomes either part of the form. So start with stark form. And for me, next will add our fields. For that, we use the input tax. So let's at the first name and last name imports between the form tags, input has a type. In this case, these are text fields. There's other types we'll see in the course. You also want to add a name, which is how the viable name will be passed to our application. In order for the user to actually send the data, we need a button. So add the following. This looks good, but we're missing something important. We need to tell the form toe which route to send this when the user presses summit. So at the following toe, the form tack form action equals slash form. But wait. Remember I told you to never hard court any Orioles on your templates that includes the form actions. So let's replace that with form. Action equals Ural four form. So our whole form looks like this. Save the form html file and now head over to hello P Y and replace the form route with the following code. So what's happening here? First, we check if the choir parameter list has a soap made viable. This only happens after we pressed this of me. But if we see that, then would read the query parameters, first name and last name and printed out in the screen. However, the first time we hit the page, we won't have to submit query parameter. So there. If condition fails and we render the form template, save the file and stop and restart the flash server just in case, I'll explain why we need to this in a bit. So now if you head over to local host Colin 5000 slash forum, you will see the form is rendered. Now enter a first name and last name and press summit. You'll see the viable sprint it out. The post method is different from the get method in a couple off important ways get since the data using the Euro post sense data using the body of the requests so it's hidden from the user, which makes it better to send sensitive or private data. There's also a limit to the data you sent in. Get requests. No limit for post get requests are cached by the browser useful to represent a state of the obligation. Post requests are not cashed by the brows. So let's change the form to use post instead of get as first name and last name might be sensitive information. We don't want to be passing publicly under Europe. First, we had a method parameter toe the form tag informants TML so that it looks like this. Save the file. Now we need to modify the route on hello p y and add a post method. We leave the get method because the first time you hit the page to render the form, it's actually a get request. Now to check if the users of meta data we change their if to read like this. If request that method equals equals posts, this condition will only be true when the user presses submit on a form that uses the post method. Finally, to read, the data will use a different request method called form. First name equals requests that form that get first name. Last name equals requests that form that get last name saved a file and restart the Fleiss server. Now go to the for mural and notice how, when you submit the values are not displayed on the euro anymore. There's 1/3 way to read the values off form, and that's using request that values. Just change the two viable assignments to read like this. First name equals requests that value. Start get first name. Last name equals requests values start, get last night, save the file and restart the server. You should get the same result. The cool thing about request values is that it reads both Get and post data, so you don't have to use our or form under request assignment. So that's convenient When the operation after you hit Submit alters the database in any way . It's not good to allow the user to just hit reload over and over on that page because that would create multiple identical records. For example, let's say the first name and last name in the previous example was to create a new user account. So when we land on the section where we fetched the variables and a database record is created, a user can then hit, reload 100 times and create 100 accounts, So it's always good practice to send the user toe a thank you page after the forms submitted. That way the user can reload the page and nothing happens so we could do something like this Under form route. That last line will redirect a browser toe a route called Register. Let's create that We need to add both redirect and euro for toe the file so online. One ad from flask Import flask. Render template request redirect euro for save the file and heat slash form on your brows, you will see how, after you submit your taking toe the new euro. Thank you. You can reload this page over and over and no new records would be created.
26. Cookies and Sessions: http is called a stateless protocol because the server only sees each individual page hit as a stand alone operation. There's no history off where the you, sir, what's before. A perfect example was the last section of our code in the previous lesson. Remember how we sent the user to the thank you page after the form was submitted? Let's say we wanted to display back the message. Thank you, John, on that page instead of just thank you. There's two ways to do it. The first is to somehow upend toe the Ural, some sort of information on the redirect. That could be the message we want to display like this. Or if we had stored the use during a database after the Post occurred, we could pass the users i D. On the database. Both of these methods are somewhat insecure because we revealing information on the euro that could be cashed by the browser or potentially exploited by a hacker. The second way, which would be more secure, is to use a cookie. So what's a kooky Exactly? Cookies are part of the http protocol, and essentially they allow you to store bits of information on the user's computer that can be read by your website after they've been set. For example, if you go to amazon dot com and you log in Amazon stores, a cookie with your user i d. And after that, any page you hit gets that user I d back those allowing you to see your order history or purchase something with your credit card. But then, if you go to Walmart, com that website won't see the amazon dot com cookie. It creates its own new local file for Wal Mart. Let's try setting a cookie for our thank you page first online, one at make response at the end like this, then modify the post section to look like this. So what we're doing here is catching the redirect on a viable called response and then said the cookie called first name under response itself finally were returned the whole thing to the browser. Then on the thank you page, we can read the cookie from the request on display back. This is something you need to remember and that you will probably miss the first few times use cookies. Cookies are set in one page and are available on Lee when you either reload the page or go to another page When you first set your cookie, you won't be able to read it in the same page. You said it. Now Save the file and check it out. Notice how we don't see the name John anywhere in the euro. There is a downside to this method and that is related to security. We'll see that next cookies are stored in the local users. Hard drive un encoded i e. If we know the folder where your cookies are stored, you would find there's a text file where you can read that the first name cookie is set to John. Now it's hard for someone to gain access to your computer, but not impossible. And imagine if we not only have your first name, but also your credit card number or your government I d. Number. They would be lying around your hard drive. Unprotected sessions come to the rescue. Ascension is essentially a randomly generated string stored as a cookie in your local computer. That points to the actual data in the website server. But the data in the website is also encrypted, which makes it really hard to decode, so let's change our code to use sessions instead. First, replace make response with session. Next, we need to add a secret key. Remember how he explained that the session data is encrypted on the server side? For that toe work, we need to set a randomly generated long string, sort of like a password, that flask, and then used us a unique method to encrypt the data different from any other flask application. So at the following line, after your app instance she ation ap dot secret key equals my secret password. Now that's not of our secure key, but it'll do for now. Next, change the postcode to look like the following Notice how the flask session is a dictionary . We can store any data we want using any ki we want at that point, Flask will create the sessions corresponding cookie in the user's local false ist. Finally, on the thank you page, you can retrieve the value for the first name session by doing first name equals session. Don't get first name, save the file and check it out. Works exactly the same if you want to generate a more secure secret key just for on this command in your terminal by phone Dash C import os semicolon Print os Thought you random 16 . Then copy and paste the contents between the single coat.
27. Configuration Management: As you continue building applications, you will quickly learn that the settings required to develop in your laptop are different from the ones used in the server that actually wrongs your site to the world. Typically, these different states off the up our cold environments. In a single development, workflow, you would have at least two environments development, sometimes called death, which is the environment you develop on in your local computer or laptop and another environment. Cold production or prod. That is the one your public application recites are. It's also important for your application to track which libraries are required under correct versions. Remember when we installed flask using paper earlier, we specified version 1.0 point two. However, when another developer installs your code, he doesn't have any indication that this is the version number off flask, or even that we need flask to run it. To attract the libraries, we use a file cold requirements txt that lists all the packages on diversions we need. So create a file called Requirements. Txt on the root folder of the application and right flask equals equals 1.0 point two save the file and now, on the terminal. Whenever you add new packages, you run the following command. Pay per install. That's our requirements. Txt. But remember, and this is critically important. Make sure your virtual environment is activated before you run, peeping stole, or you will install this packages across all applications. This command tells Pip between stole all the libraries and its dependencies listed in the file. This will come handy down the road when we install older libraries. If you run this now, he won't do anything as flats was previously installed. But now we have the information on our code base. If our application it's used by someone else flask version one point no introduced a new way to better handle the environment. States using a library called python dot m with python DRM if we can store all the environment settings we need in an individual file so that we don't have to worry about adding them to our code base. Typically, this environment files will be kept outside over git repository with a dot get ignore and would vary between the different environments as usual. We do it differently in Windows or Mac and Python anywhere, so skip to the video that makes sense for you
28. Python Dot Env for Windows and Mac: So first we need to install bison dash dot m so added to the requirements. Txt file by phone that star EV equals equals 0.8 point two. Save the file. Go to your terminal, making sure your virtual environment is activated and do a peeping stole, beeping stole dash. Our requirements txt next at a Savings B Y file on the route APP directory that looks like this. This will allow us to read the environment variables. That python dash dot M will push from the end file to the operating system, save the file and next open the Hello p y file and changed line four to read ap dot com fick dot from underscore P Wife file settings Beware. This will tell Flashed that we want to load our application settings from the setting Stop ey file, save the file and finally create a dot flask m file in the same directory that looks like this notice. We're passing the flask on the score APP. Environment viable. We had to set up manually before, as well as a new flask on the score. Em viable. This tells flask If we're in a development or production environment, If it's a development environment, it automatically turns the bark mode on for us. It's okay to put the actual secret key here. Remember this dot flask and file will not be saved in other computers or committed to the repository. Save the file. Now you contest that all is working by completely close in the terminal and opening it again. Go to the simple flask app directory. Activate your virtual environment and type flask Brought the application of runs in the bug mode without needing to set any environment. Virals cool, huh?
29. Python Dot Env for PythonAnywhere: so first when he tweets stole python dash DRM so added to the requirements. Txt file python dash dot m equals equals 0.8 point two. Save the file, then open a bash, making sure your virtual environment is activated and do a peep. Install next at a setting start. B y Foul on the route APP directory that looks like this. This will allow us to read the environment variables that python touch DRM will push from the end file, toe the operating system, save the file and next opened the Hello p y file and changed Line four to read ap dot config dot from underscore p y file settings B Y This will tell Flash that we want to load our application settings from the settings, start the WiFi, save the file and finally create a dart flask m file in the same directory that looks like this. It's okay to put the actual secret key here. Remember these dot flask m file will not be saved in other computers are committed to the repository. Save the file. We need one final step, and that is to add python dash DRM toe the whiskey file so at this in line one and right before the APP import ad load on the score dot m Always path. Join bath dot flask in save the file, reload the web and navigate toe the slash form and tried submitting the data. It should work just like before.
30. An Introduction to Databases: like we saw on our lesson on cookies and sessions. Http is a stateless particle that doesn't save anything Between. Sessions with cookies were able to keep a pointer to a specific user, but there's a limit on how much information we can store in them. That's where databases coming. Place databases are big silos, where you can store millions of records. These records are frequently subdivided into logical Silas that are related to each other. In my sequel, the database we will be using the silos are called tables. Tables have a specific structure, also called a schema. What does the scheme I looked like? It's similar to a list of columns that describe things like the name type and length off each column. For example, let's say we have a customer records stable. The schema for that table could look like this. The different columns have a name like first name and email, a type like string or integer and a length in parentheses. Once you at records, the table looks more familiar. Similar toe a spreadsheet? No, it is the first column it says I D or identify. This is usually added automatically by the database, so that we can reference a specific record at any time. Once the data is in a table, you can do queries on it. What are queries? They are essentially data operations to retrieve either one record or a group of records that match a criteria, for example, that say, we're searching for the data off the user or users whose email is jane at example dot com. We would do something like this. The database would then start from the top and start comparing the first email with Jane at example dot com then the second email than the 30 mil old away to the end and emails that match it would add to the results. That and at the end, give us those records in this sample database. It would only return bro number two, right? But if the query was about getting all users whose last name is Smith, you can see that the results said would have records one and two. If we know for sure that each customer will have their own email, we can alter the schema as follows. See the email column Now it says its unique, which means that database knows once it's found the result it needs. It can return it back to you. But there was already a unique field without us knowing it. Can you spot it? Yes, the I D column needs to be unique by default. Now imagine. We've had tens of thousands off records, and we were searching for the only user with the email jane at example dot com. It would be a waste of time Toby waiting around while the database looked through the whole table looking for that record. Can you think of a way that could speed this up? One way would be to sort the data by email so that when we find the email we want, we can stop looking. But there is a tool that databases offer to help us do this or America. Indexing allows us to define certain columns to be the ones will be searching the most. On once we define a column Toby indexed, the database creates a smaller version of the table with just the I. D. On the field. We're indexing, for example, that so we create an email index because we know we'll search users by email a lot. The email index would look something like this that way. It's much faster to search for a customer because we're not having to look at all the records. But not only that. Notice how the emails are sorted as well that a basis usually sort the indexes so that once it finds the records it's looking for, it doesn't have to continue searching. Another concept you'll hear a lot about databases are the crowd operations cross stands for Create, Read update Delete In my sequel, we can do any of those operations on any record by using a specific command as follows. Create, insert, read, select Update update. They lead the league. We will look at each one of these operations in the next lessons.
31. Installing MySQL: it's time to install my sequel as usual. If you're using by throw anywhere, the flow is a little different, so skip to the lesson that applies to you.
32. Installing MySQL on Mac with Homebrew: thanks to Homebrew installing my sequel on the Mac. It's pretty simple just till the following Brewing Stall. That's why my sequel. If you want my sequel to lunch automatically whenever you power on your Mac, you can do brew services start my sequel. I really don't recommend that. Instead, you can start it manually when you need it by doing my sequel dot server Start and stopping with my sequel dot server Stop the second. My sequel is working. Start the server by doing my sequel, that server Start and then logging in using my sequel, Dash You Root Exit using Exit Semi Colon. Now secure the installation by doing my sequel on the score. Secure on the Score installation. My sequel offers a validate password plugging, but we won't use that just type N and then enter a password. I will use Route Pass as my root password. I will also remove the anonymous user and remove the ability to remote route luggage. I will also remove the test database and reload the privileges. It's a good practice to create the database with a specific user and password and not use the root user from the application in The next section will be creating a visitor counter application, so we will create a database cold counter. We will access the database with the user counter on the score, app and the password. My password. So logging toe my sequel with your route user and password. My sequel does, she wrote. Dash P Route Pass. Create the database, create that obeys counter and now create the user and password creates user quote counter on the score app, end quote at Star Coat Percentage Sign in court identified by Quote my passport. End quote semi call it. Allow the user full axes to the database. Grant all privileges on counter dot star too. Start quote counter on scrap and quote at open quote percent design end quote semicolon and reload the privileges. Flush privileges, said Michael. Now exit using Control D and try to logging using the new abuser. My sequel Dash, You counter on this crap. That's be my password. If you are able to log in your in good shape now, try to use the counter table. Use counter semicolon. If you don't get an error, we're good. Now look out using exit semi colon
33. Installing MySQL on Windows with Chocolatey: thanks to juggle lady Installing my sequel on Windows is pretty simple. We will install the Maria DB package, which works exactly like my sequel. Open a power shell as an administrator and type Shoko Install Maria DB. Now close a power shell application completely an open and new regular session. Let's check if my secret is working, logging using my sequel that you root exit using exit semicolon. Secure the installation by creating a root password. I will use Route Pass type. My sequel, Admin, that stash user equals route, Password, quote, Route, pass and press Enter Now try looking mean using my sequel that you root Dutch Be brew Pass . If you look in, it means everything is working. Exit using control. See, it's a good practice to create the database with a specific user and passport and not use the root user from the application In the next section will be creating a visitor counter application, so we will create a database called Counter. We will access this database with a user counter on the score up and the password. My password. So looking toe my sequel with your route user and password. Create the database, create database counter and now create the user and password. Create Yusor Counter app at percent sign identified by my password. Allow the user full access to the database grant all privileges on countered out star to counter on the score app at percent sign and reload the privileges. Flush privileges Now exit is in control. See and try to log in using the new APP user my sequel that you counter on the score up. That's be my password. If you are able to log in your in good shape now, try to use the counter table. Use counter if you don't get an error, would good now low gout using exit.
34. Setting up MySQL on PythonAnywhere: if you are using bite on anywhere. My sequel is already built in, so you don't need to install it manually. Just head over to the dashboard and click on databases on the navigation bar. You will see that you have a user name already set for you, which is usually the same name as your python anywhere User. However, I recommend you set a new password for the database user. So go to the my sequel password section and enter a new password. I will use my passport, but feel free to create a more secure one. In the next section, we will creating a visitor counter application So we will create a database called Counter on to create a database section type counter on the database name. This will create the database for you. However, please note that the actual database name will be your user name, plus a dollar sign, plus a database name you entered. Fight on anywhere doesn't allow the creation off a specific users, so you will need to use their my sequel user assigned for you to use it from the application to make sure we can connect to the database. Open a bash, console and type the following, replacing it with your user name, password and database host Address. If you get on my sequel Prompt were good. Enter exit semicolon to exit.
35. MVC and the Object Relational Mapper: Before we start building our first database driven application, I wanted to introduce you to the concept off the object Relational mapper or O. R M. In theory, we could issue Database Square is directly from our application code any time we want data . So, for example, let's say we're on a route that needs to get at least off users. We could just connect to the database, right the query to select all users from the database and maybe do other operations on the database and close it. But let's say we had a new structure in the data base, maybe a live field, because some users could be suspended for posting bad content. Or let's say we decide to change to a new sequel database server like Post Chris. We would need to come through all those queries and change them. So for that reason, we used the M V C model for applications. Remember when I mentioned the embassy model? When we introduced the templates, we said that templates where the views And now that we have a database available, we will have the model Toby, a file that deals with anything related to talking to the database. That model file will leverage something called an or in which essentially converts data rose into objects so that when we want to access users in that route, we would request a list off objects from the moral, not issue a sequel command. That way, if anything changes with the database structure or we changed sequel servers, we just need to change the model file and not worry about the rest of the application. This will become more clear once we build our first NBC application, so let's get on with it.
36. Our First Data Driven Application: we will be taking a big step in our development, wrote, creating our first database driven flask application. The application is a visitor counter sort of what you would see in those old school websites in the footer. That would count how many people have visited the site as usual. We have different set up instructions, depending on your development system, so escaped to the proper one for you, and we'll all over some together on the other side.
37. Initial Application Setup on Mac and Windows: we will be creating a brand new directory for our visitor counter application, and this process will show you how to set up a brand the flask application with all we know now, let's begin by creating our application directory in slash OPD. Now change to that directory. Let's set up our virtual environment and activated. Now we need to set up our requirements. Txt file. So open Adam on this folder by doing adam dot or by opening Adam and then opening the slash hoppity slash Mr Dash counter folder. Now we're going to create the requirements. Txt file. The core packages we will be installing are the following. You could put those lines in the requirements txt file, However, because off small differences between versions and packages, I've experienced that students sometimes have issues with the libraries I put in the course versus what they get installed. So if you want to be extra safe, copy and paste the requirement 60 below, save the file and install the packages by doing peeping stole that our requirements txt. Once that is done, we can start writing the application
38. Initial Application Setup on PythonAnywhere: we will be creating a brand new directory for our visitor counter application, and this process will show you how to set up a brand new flats complication with all we know now, let's begin by creating our obligations directory in your users slash o p t folder. Change to that directory. Now we need to set up our virtual environment and activated. Now we're going to create the requirements txt file. The package is we will be installing are the following You could put those lines in the requirements txt file. However, because of small differences between versions and packages, have experienced that students sometimes have issues with the libraries I put in the course versus what they get installed. So if you want to be extra safe, copy and paste their requirements txt file below, save the file and installed packages by doing peeping stole dash our requirements Txt. We now need to update the Web settings off our app. So head over to the Web dashboard first on the code section changed the source code Directory two. Home your user name. Oh, Petey Rezidor Dash counter. Next, change the whiskey file and update Line five with the new directory and change line. 11 Toe the following save to file. Finally, update the virtual IMF toe the one in visitor counter. Just click on the Link and Time Visitor dash counter and it will auto Populate Reloaded Web application with the green button. Once that is done, we can start writing the application.
39. Our Application Libraries: So let's go over the requirements. Txt libraries to get a better understanding off what we're including and why flask and by thunder M. You had already seen before. Flask is the where Framework and Python DRM allows us to use environment variables with a simple file by my sequel is what's called a connector library, and it allows our flask application to talk to a bicycle database sequel. Alchemy will be our database or in Remember when we talked about using database records as objects separating the low level sequel quarries from our application sequel Alchemy allows us to do that. Finally, Flask Migrate allows us to track changes that we make took the database schema so that any other team members working alongside with you or any other installations of the application can be kept up to date with those changes.
40. The Environment Settings: Now we need to work on the environment, citing so far application. So let's create our dot flask m file and will explain what they are. So create the file and put the following virals in it in by phone anywhere. Make sure to use the host user and database name that is assigned to you on your databases . Stab so for the python anywhere that obey settings above. I used the following dot flat scam. Save the file and let's check the vibe. ALS one by one the 1st 3 we've seen before, Flask app tells flask, which filed to run with the flask or on command Nordea's reporting managed doctor ey here, which doesn't exist yet. We'll explain that in the next lesson flask on the score, em tells flask this is a development environment so that it activates automatic reloading on our windows and max setups. Sorry, Python anywhere doesn't support reloading as well as turning on the debug boat on. Finally, we need a secret key to be able to use sessions. The rest of the file their finds that that have X user name, password and name we created in our previous section now create the Settings B Y file on the application folder, which looks like this in reality sequel Alchemy only needs the sequel Alchemy. Database your eye setting. But this way you can really tell the components off the DB your eye component. Save the file. Next, let's check out our main application factory.
41. The Application Factory: in our hello world application are hello dot p y file had everything contained in it. The application set up the routes and he was expected to be around by itself. In the real world, however, applications are organized by modules with its module doing something different, which helps to maintain order and build new features more easily. For example, in an accounting application, all user related routes and morals can leave in a user directory and all the transactions related toe. Those users lived separately in a transactions directory. To be able to support dysfunctionality better, we're going to create an application dot B Y file that allows the creation off instances off the APP on a separate manage B Y file, which is the one executed by flask run that will actually spawn. One instance. Because the application dot B y produces instances off the APP, we call this method a factory, and it follows the factory design pattern. So let's check the application DePuy file first, so create an application up ey file and put the following code in it. The 1st 3 lines import the different libraries. We need flask sequel alchemy and flax migrate so far, so good. Next, we set up a viable called DB that creates an instance off sequel Alchemy. This will build the connection with her database using the flask dot m virals. Then we defined the create APP function, which begins with more or less what we had in Hello. Don't be what, create an instance off the flask class and then set up the configuration from the setting Stop ey file. The next two lines actually initialized the database and starts tracking the changes to it . And finally we returned back the app instance to whoever calls dysfunction. This might all sound like a lot, but after a couple of times it becomes second nature. Saved a file finally created. Managed up your y file with the following to lines. This will just import to create APP function from Application B Y and then create any instance off the APP. Save the file on the next lesson will create our first module, the counter module
42. Building Modules with Blueprints: We are now going to see how we continue building our application in a modular way, and that's by using flasks. Blueprints. So what are blueprints? Think of them as the building pieces of your application that are focused on a specific area. For example, let's say we were building a social platform like Twitter. We could have a user module that would deal with the logging registration. In profile editing. We could have a feeds module that would deal with posting the messages toe water users and another relationship module that would deal with the following and on following off other users. Each one of these modules would have a corresponding model controller and views in flask. I use view stop ey for the controller and templates for the views. So I called this the MTV pattern model template view. They also have their own tests that test only the functionality that pertains to that module. I also call each of the modules and app because they're sort of many applications of their own, took a bit simple. We will just have one module for the counter application so that you get the hang of it, so let's build our first counter app
43. Our First Blueprint: So let's build our first blueprint module. This module will make sure that every time we load the page, we increment the counter in the database by one. So we begin by creating our modules directory. So on your root directory, create a folder Cold counter. Since this will be a python model that we will be importing things from, we need to add an in it that b y file. So create that inside the counter directory. Next will parade our embassy controller for these counter app which will call views B y. So create that file inside the file type the following the first line imports the blueprint class from flask and the second line actually creates a blueprint instance bypassing the name off the module which will call counter app and the magic name viable that holds the files module. Now let's create the first route off this module, which will be the root euro. Notice how the decorator doesn't say at AP anymore. Now we use the blueprints name, save the file, and now opened the application dop ey and insert this lines right before the return at. So first we import the counter at Blueprint from the views B y file. And then we registered this blueprint with our global flask application. Saved a file, and now we'll check the site in our browser for Windows and Mac. Go to the terminal and make sure your virtual IMF is activated and enter flask. Run, then head over to local host 5000 in your browser. This local host is the same as the 1 27.0 point 0.1 we've been using on bison anywhere. Make sure you've restarted the server and head over to your side. Euro. You should see counter app on the page. If anything's no working, check out the air messages in the browser or in the terminal by phone anywhere. Also has an error log link on the lock files section off the Web tab. Now that we know the router set, let's build our model
44. The Counter Model: Now we need to build our counter APS model where we will define this model. Scheming the model can have multiple related classes on each class, represents a table in the database. We're making our first application really simple so that you understand how it all works. So we'll need just one class the counter model class. So create a new file in the counter directory called Models B Y and let's start building First, we need to import the sequel Alchemy Database. Instance. Toe the model from Application import to be next will define the counter class class counter Devi Done model. We're defining the counter class as an extension off the sequel Alchemy Model Class. Inside the class will define two fields I D and Count. The first is our I D, which is the required identify filled. This is a number that starts from one on increments automatically, and we tell Sequel AKA Me this by defining it as a db dot integer and making it our primary key. We could call this field something else, but it's standard to call it i d. The second field is Count, which will hold a number off hits the page has received. For now, we just need a number. So we just defined this as an integer. Okay, So far so good. Now we need to define the innit method for the class. The ended method is what will be called when we create the object for the first time. So in the same class, do the following death in it self comb account self. That count equals camp. You'll see this in action when we create the object. Finally, old classes should have a reproduce method, which is how they're printed into terminal when we see the record. So just to deaf r e pr self return f count self don't count. So the whole file looks like this. Save the file. And now let's initialize the database and get introduced to the concept off migrations.
45. An Introduction to Migrations: As our application evolves, the data base models will grow us well. But just as we have get to record the history of our code and have the ability to undo things if we messed up migrations is the same concept applied to our data models. We will be using the Flask Migrate library for this, and there are four important comments to remember. In it. We used is the very first time we start our migrations, my great checks, all the changes in the models of the application and stores. The changes in a migration file upgrade applies the latest migration file. Changes to the database downgrade reverts from the latest migration toe, the one before it on the database. At the beginning, you'll be confused about the order off operations and went to do which. But trust me, it becomes second nature after you do it a number of times. Just remember that Migrate only creates the changes on the Migrations folder, but doesn't actually change your database. That's what upgrade does. Before we do anything, though, we need to an important step that you need to remember when creating new models that you want to add to the migrations. Please write this down as it is very important. You need to be able to see the model from your application. P Y you see the way flushed my great discovers her models is via they migrate equals migrate app comma db line in application. P Y. If you follow the rest of the file, you'll see that now we import counter that views online. 19. Okay, so open countered our views. Notice something missing? Yes, there's no mentions of the models. Be why anywhere here. So if we do the migration now, Migrate won't see any models anywhere and won't generate a migration so online. Three. Insert the following command from countered that models import counter. Now Flash My great will go through applications B Y. Then go over to counter the views and see the models and be able to know there's some database definitions in this application. Now go ahead and save the file. Remember this rule, as this is 80% off the issues with migrations not being created. So let's initialize are Migrations folder. Go to your terminal or open a bashed in by phone anywhere. Make sure your virtual F is activated and do Flask db In it, you will see some messages regarding the creation off a directory called Migrations. Now, if you look in your code editor, you will see the directory notice that we have, ah, versions directory inside that is empty. When we do our first migration, we will see a file created in there. So at this point, nothing has happened. Plus, my great just initialize directory where the versions will be stored will now do the first migration. So do flask. They be migrate. If your database connection is working correctly, you will see the first version file created on your directory. If you see some errors, check that your Mike sequel server is running and that you can connect to it from the terminal using the counter app, user name and password. Now open diversions file. It would look like a string with numbers and letters ending with underscored dot B. Y. You will see there's a revision. Identify our section and then two functions upgrade and downgrade Upgrade shows the commands to move from the previous state. In this case, since this is our 1st 1 it says it'll create the counter table and add two columns I D and Count Downgrade just says it will drop or delete the table that would effectively return us to the previous state when we had no counter table. It's always a good idea to look at the latest version that my great is generating, and check that the actions in their match the changes you are intending to do. If for some reason they don't, you can safely delete it before doing anything else. Check for any missing stuff in your model and then generated again. Once things look good, you can complete the process by doing an upgrade, which actually makes the changes on the database. On this first time, it will actually create the table for us. So go ahead and do flask db upgrade. Notice the message that says Running Upgrade. Empty message. That's how you can tell it actually implemented the changes on the database. When you're moving from one verse in tow. Another, you will see that two version I ds in there. This is good enough for now as we continue building our application and adding more tables and fields will get better acquainted with the migration workflow
46. Database Operations from the Shell: one of the things I'd like to do before writing code that reads or writes objects on the application is to test them on the python flask shell, just as you can spawn. A python shell flask allows you to open a shell that has your application loaded. So let's try that type flask shell. You will see the familiar three angled arrows, but now we can import things from our obligation and test. Um, remember the crowd operations we talked about earlier will do all of them in this lesson. So first lesson poor the counter class from counter models from counter miles in poor counter. We'll also need to import that DB sequel Alchemy Object from our application file from Application Import DB. Right now the counter table is empty since we just imported it. So let's double check that type counter dot query that all. Believe it or not, we just executed a query on the database through the sequel Alchemy or, um, we had an empty list, which makes sense. So here were using counter as a representation of the counter table. We always use the query method to execute queries on the data base and all just means get me all the records. So let's try writing our first record under database. First, do counter equals counter count equal one. However, nothing was read into that. I base just yet. Sequel Alchemy has the concept of recession. You can check that the counter object has not been written. Toe the database by checking its i d counter dot i d. Since it hasn't been written, the database has not assigned it on i d. Now we'll add the counter operation toe the session by doing db that session. Don't add counter. So think of a session as a series of database operations that are related to each other that once we have all the necessary ones, we commit toe database. This has two benefits. One. You don't have to write many operations individually, but can do all of them with one call, making it easier for the database to have less rights. And two, If something goes wrong with any of these operations, we can roll all of them back easily. In our case, we only want to write our counter object to the database. So to the B that session that commit now, check the counter dot i d success. We now have one rolling the database that looks like this, and that was the sea in crowd. Let's do an R. So how do we retrieve the value off this record? There are two ways. First is using its i D. So if we know the idea of the record, we can do the following counter on this score. One equals. Counter that query dot Get one. You can now print the object counter. Underscore one notice The format off the object follows what we created on the ripple method off the counter class. We can also get the value off count counter on their score one dot count. The other way is to do a list type query, for example, we saw this one earlier. Counter on the score list equals Counter that query that all Now, if you print the counter list, you'll get the holy stuff objects in the counter table to get the first result on assigning toe, a viable we do counter on the score. Two equals counter on the score, lest off zero. And if you print counter on the score tool, you'll see it's the same record. There's also a handy method to skip the bracket zero least operation. If you know that the query will result in just one object in the list or the first result is the one you'll always want you can do, Counter underscores two equals. Counter that query that first, that will come handy often. Okay, how about the U in cracked? Let's update the record. So first we fetch it, just in case we lost it. Counter equals counters a query that get off one and bring the value of count counter dot com. Let's set count to two. So do counter. That count equals two. When we do updates, we don't need to add to the database session. Since sequel, Alchemy has an i. D. For the record, so to write our update just to they be that session document and that's it. Try fetching the record with another viable and check if the count value was updated. Finally, we can do that D off crowd the lit toe, delete this record. You can fetch it first and then call the delete method off the session. Counter equals counter that query that get off one. They be that session that the elite counter to really delete it in the database you need to do a comet, they be that session dot com it. And now, if you try to get any records, you'll see the table. It's once again empty. Counter the query that all Okay, this is all we need to start building our counter application.
47. The Page Views Counter Application: The first generation of our application will be just to measure how many times the home page has been loaded. So open your Adam editor or navigato Python anywheres file editor, and open the counter views B y and add the following code to our innit method. We'll start by fetching the first counter object. Counter equals counter. Don't query that first notice. We don't need to pass the all method with it. Earlier in this case, we just want the first record period. If the country is no, it means that this is the first time we're running the application and we should create the record so we can do, if not counter counter equals counter off one db that session. That ad counter, they be that session that commit. See how Winston she ate the counter object here. We didn't need to pass the count keyword argument because it's a positional argument on the counter in it method. We then add the counter to the session and finally committed to the database. So now what happens if we do find a counter record? We do this on the else els counter dot count Glass equals one db that session document here . We just at one toe the counter that count and commit the session. Finally, we can put this on the page. There's one more thing before we run the app we need to import the DB object from the application, since we're accessing the B dot session. So at the top of the file after the models import right from application, import the B, save the file and now run your flask application. Head over to a local host. Call in 5000 the first time the page will say the counter is one real debates and you'll see the counter incremental, even though it looks very simple on the page, you've now graphs some pretty fundamental concepts about website development without knowing it.
48. Setting Up Our Test Infrastructure: professional developers integrate testing early on to their development flow, and my intention is to teach you how a professional developer works. So let's write a testing suite for this application. If you're using python anywhere, you'll need to create a test database manually. Since we don't have root access to their my sequel server, I let you know when to do that. The first thing we need to do is modify the application people I file so that we can override the setting virals from the test. So on the create APP method at the following this allows us to pass arbitrary keyword arguments to the function without pretty finding them. Then, after the load CONFIG line at the following, this update method allows us to overwrite the settings initially loaded from the settings file. Save the file. Next, we need to act in my sequel Root password toe the dot flats came file and the Savings B Y file so that the test script is able to create and destroy the test database. Why do we need a separate test database for tests? Well, the idea is that you don't mess up the existing data in your main database. We also want to make sure that all the code words with fresh data every time we run the tests. Otherwise, there could be leftover data that could mess up the validity off the tests. So on dot flask em at the my sequel Root Password Viable and Put your Road Passport for PC or Mac. If you are on python anywhere, make it look like this. Save the file. Next, we need to add the my sequel Root Password to Settings B Y While you're at it. Let's also add these custom sequel alchemy, setting for track modifications. Otherwise, when you run the tests sequel, Alchemy will complain about not finding it. Save the file. Next, we're going to add a utility to create and destroy a test database. I opted to place this utility on a new you tills folder. The idea with this utility is that we don't repeat the same code over and over in each of the tests, and it will also gracefully manage. If there's no root password set four cases like the python anywhere users. So go ahead and create a you tills folder and add an in it that B y file in it so that we can import it as a module. Next great. A file called test on the score db dot b y and put the following contents on it. The class is more or less self explanatory on the innit method, we said the viable for that of his connection. Based on if the root password is present or not, notice that the name of the test database will be whatever the main database name is, and at the end, it tags on the score test. So if you're that of his name is counter, then the test database that will be created will be counter on the score test. Then we have a create on the score Devi method that creates the test database and returns the final connection string to the caller. Finally, we have a drop DB method that will destroy the test database. Notice that both methods only create and destroy the test database If the root password reset. Okay. With that out of the way, let's create our first test. I always put each APS test within the APP folder itself that way. Older test related to its functionality are right inside of it. So create a tests, be while in the counter folder and lets it begin with the imports in the first section. We're importing the application factory main method and changing its name to create APP base because we're going to have our own create app method. In the test, we also import unit test, which is the Python built in testing library. In the next reliance, we need to import the thought flask M sightings manually, using the DRM of library as thes file is being run directly by python and not by flask. They last three lines import our models and the utility we just created for the test database creation. Next, let's define our first test class. That's files are organized by classes and corresponding tests, and you can have more than one class on a single file. Think of a test class as a group Off related tests, since our application is so simple, will just have one class called counter test. So we begin with the following. Let's focus on the set up and tear down methods. These aren't required methods. Notice the weird camel case method names, but that's how you need to write them. The set up method is run at the beginning off its test until down at the end of each test. The idea is that you start with a fresh version of the APP for each test. So on set up we first instance she ate our handy, tested the utility and get the database connection from it. Next, we create an instance over a flask app and storied on APP factory. But notice that this is done by executing that create app method on the test, which just returns. An instance of our app believe the savings overrides. These are flat settings and you've seen them all except testing. When you define a flask up Toby in testing mode, Flask disables the error catching during request handling so that you can get better error reports when performing tests. Requests against the application. Notice that we're setting the sequel Alchemy that advice your I to the DVD your I returned by our test the B utility. Once we have the up factory, we cannot create the most important piece for tests. The test client. So we call this app and it allows to send requests to our different Urals and the APP will respond exactly how are normal application does. Finally, we need to create all the application tables are tested be utility creates a database, but not the tables inside it. Until now, we did that with migrations. But sequel alchemy provides a method cold. Create all that can create all the tables that are models need. The tear down method is the opposite. It first drops all the tables. And then we called our test DB utility to destroy the test database. But what is this APP Context? Business On both methods, this APP context method allows us to simulate anything inside off the with block, as if we were running it from the flask. Execute herbal. Remember I told you this file is run from Typhon and not from flask. So if we ran db dot create all we felt the context. We will get an error because the DB object is created once we execute flask like when we do flats. Run context is one of those things that you'll get more used to when you use it more. For now, think that if we need to do any operations that would normally run inside of a view you need to run. Using the context I know feels like a lot going on, right? Don't worry. It's hard the first time you see all this, but every test fire, you right will need all this code first. So this is one of those times that you can copy and paste and not feel bad about it. So with this, we can finally create our first test.
49. Our First Test: so far we have just set up are test class and we're teaching to write our first test. So let's do it. It's test needs to begin with the word test on the score so that the unit test library knows that it needs to execute the set up before and the tear down after it. So that's right the first part. Okay, so the first test it's called test on the score counter. First we execute a request to ourselves dot app by hitting the index euro. That's what the slashing their ISS. Also, to get in the method means it's a get request. The output off this operation is stored in the RV viable, and it will be a bunch of html sort of what you would get if you did a view source off the actual application. Next, we want to assert that the string one is somewhere on the HTML. We know that if the application is running correctly and it's the very first time, we will get the string counter semi colon one on the output, right? This is what tests boil down to asserting or making sure that something that we expect to be happening is happening if the result off that assert its falls. The test is said Toby, not passing. Save the file. Okay, Before we run the test, we need a test runner in the root folder. So create a test the P Y file on the visitor counter folder and put the following coat. The snippet will automatically discover all tests in all the apse in your application and run them. Saved a file. If you are using python anywhere, you need to create the test database manually. So go to your databases section and create the counter test therapies. If you're using Windows or Mac, we're good to go. So open your terminal. Make sure your virtual M is activated and type by phone tests. DePuy. You'll see a little dot and then the message ran one test in X seconds. That little dot represents the test counter test. If you get in the air, try to see what's producing the air and double check. The code is good. You can check the whole code base here, so let's add another assert toe. Our first test. We know that when we load the page the first time we get the message counter colon one. But what happens if we loaded again? Right? We should get counter colon to so we can add the new assert in the test counter test right after the 1st 1 So at the following save the file and run the test to see what happens. Great. The tests past. If you had created a brand new test and asserted the to what do you think would have happened? Try to say out loud, I'll wait. The test would have failed because if you create a new test, the database will be reset by the set of function. Under counter will be one again. Go ahead and try. As you can see, this is what a failing test looks like. Don't forget to revert your code toe the way it waas. And with that, we can move on to creating our new applications, one that will be more useful but also more complex. A personal block
50. Flogger, a Simple Flask Blog: we're going to now build a personal blogging application where we will learn a lot of the concepts that a professional developer would use. The block allows you to raised her an author and logging as that author. After creating our author, we can create new posts with images, categories and tags. We can also see articles by their categories and by tags with full pagination capabilities . Finally, will be able, tow, edit or delete posts. In the surface, it looks more or less simple, but the code behind it will be a good challenge off what you've learned so far, and it will give you new perspectives off where to go next. So let's start setting up the application. As usual. We have instructions for Mac and Windows or Python anywhere, so skip to the lesson that's right for you.
51. Initial Application Setup on Mac and Windows: We're creating a brand new directory for our blogging application. So do the following in windows. Make fear c slash opt slash blogger in mac make dear slash Off slice longer Now change to that directory. Now let's set up our virtual environment and activated. Now we need to set up our requirements. Txt file So open Adam on this folder by doing adam dot or by opening Adam and then opening the O P. T Flow Ger folder. Now we're going to create the requirements txt file. The core packages we will install are the following your actual requirements. TXT file should look like this. Save the file and installed it packages by doing paper install. That's our requirements Txt.
52. Initial Application Setup on PythonAnywhere: we will creating a brand new directory for our blogging application. So go to your bash console and type the following. Make dear till the slash r p t slash floor change to that directory CD till d slash orbiting slash blogger Now we need to set up our virtual environment, make little lymph dash B by from 3.6 flutter and activated work on pfleuger. Now we're going to create the requirements txt file. The packages were Will install are the following your actual requirements txt file. She'll look like this, save the file and installed the packages by doing peeping stole dash our requirements the extinct We now need to update the Web settings off our app. So head over to the Web Dashboard first on the code section changed the source code Directory to home Your user name. Oh, pretty Fluckiger. Next change the whiskey file and update Line five with the new directory Saved a file. Finally, update the ritual and toe the one in flutter. Just click on the link and type Pfleuger and it will auto populate. Reload the Web application with the green button
53. Our Application Libraries: once again, let's go over the requirements. Txt deliveries to get a better understanding of what we're including and why these are old libraries that you've seen before. This includes Flask Python, Durham for the environment, Variables handling on the My sequel, or M on migration libraries. WTI Forms is a very popular python library to manage. HTML forms easily and efficiently instead of us typing forms manually and validating their input wt forms. Does it for us a curious debate about the library. It's supposed to be the abbreviation off. What the forms and not the other WTF we'll know about markdown is a text input standard that allows us to format content using a small set of codes so that we can apply bold italics, hyperlinks and other formatting features to our block post slog. If I is a small utility that allows us to produce standard compliant Urals from text inputs , we will use this to generate the block posts. Urals. Finally, pillow is a wrapper around P I. L, which stands for the Python Imaging Library. It allows us to resize and convert images for our block posts, and that's it. Let's now move on to the core application factory
54. The Core Application: Let's set up the core application quickly. If you don't want to type all days, you can download a sit file off this branch off the floater repository. Next will set up our flask m as follows again. Some of this stuff you've seen will create a database called Pfleuger with the use of human passport and include the root password for our tests. If you're using python anywhere, remember to change the DB Host toe the host in your database dashboard. The last two virals block name and blogged post images path since the name of the blawg and the path in our server where we'll upload the block Post images if you're using Windows, said the path using windows formatting by phone anywhere should look like this. Just remember to enter your own user name above next Will door settings B y With the environment variables we just entered. We now create our manage Me Why, like this? Now create the application P y. With the following code. Nothing you haven't seen before, right? We can now create our first blueprint. The Blawg app. First create a block folder, create an empty in it B Y file inside and then write the following interviews B y file. Since we don't have any database operations yet, go ahead and type flask, run and give the application that's been. Make sure your virtual M is activated. When you browse to your local host, you should see the title block home. Now let's set up the database.
55. Setting up the Database: As you probably expect. We have two flows to set up the database when for Windows and Mac and the other for python anywhere since we've done this before, I'll go quickly through this for both. Looking to my sequel with your route, user and password, create the Pfleuger database and now create the user and password. Allow the user full access to the database and reload the privileges. Now exit using exit and try to logging using the new APP user. If you're able to look in your in good shape now, try to use the floater that obeys. If you don't get an error, we're good now low gout. Using exit, we will create a database called Pfleuger on the Creator that are based section type pfleuger under database name. This will create the database for you. However, remember that that are based. Name will be your user name, plus a dollar sign. Plus it that amaze name you entered To make sure we can connect to the database, open a bash console and type the following, replacing it with your user name, password and database host address. Now try to use the floater database. If you don't get on there were good. Now log out using exit
56. Creating the Author App: so the first thing will tackle is the creation off the authentication flow for the blog's author? We will assume that anyone can register as an author for our block, as I don't want to complicate the application to march for us, at least at this stage. So go ahead and create the author folder on the application route, then create an NDP y file insight so that we can import from somewhere else. Finally, let's create the views B y file and add the following notice. We're putting both get and post methods here. We will be using the post method when we create the registration. For next, let's add that new author module till the application p y. So in the import blueprint section, add the author app. Save both files into a flask run. If you visit local host 5000 slash register, you should see the author registration page
57. The Author Model: Let's start working on the author model, Create a Models B Y file on the author folder and let's at the following. We're going to have an author object with a full name, email and password. Since all these fields are strings, we use the string type and passed the length off that field. Notice that we're making the email unique. Bypassing the unique equals true flag. This means that no two authors can have the same email, and also that the table will create an email index for faster searches off authors by their email. Next will create the image method off the author class to look like this. This will be called when we create a new author finally will create a reproduce method to display our author objects on the shelf. We're done with the file. Now let's create the actual my sickle tables by issuing a migration
58. The Author Model Migration: remember what I told you about migrations and the path to models in the previous section. Right now, there's no path to the models. B y from the application p y. Since there's no mention off author models in our author views, if their migrations doesn't see the file, it won't create the proper migrations. So on author views at the following line. After Blueprint, import and save the file. Now go to your terminal, making sure your virtual lamp is activated and type flask baby. In it, you will see the migration folder being created. With its initial settings, we can now do the migration operation where the database operations file or snap shirt is created. So do flask the B migrate. If you get an error here, make sure that that my sequel server is up and that your credentials on the flask m r correct. It's a good practice to check the file that was generated before we do operations on the database. So go to the Migrations folder and on the Versions sub folder, open the file. Inside, you will see that the upgrade method creates the author table and then adds the columns. We have on the model. The downgrade method drops the author table, which makes sense if we wanted to roll this operation back finally, to apply their migrations on the database and create an update, the tables do flask db upgrade.
59. Testing the Author Model in the Shell: after applying the migration. It's a good practice to test if the table was set up properly in the show. So let's open a flask shell and try to do some basic operations on the author model. So two flasks shell now import the author model from author dot models import author, and that's create an author by doing author equals author. Full name equals John Smith. Email equals J. Smith at example dot com Last word. My password. Now remember, at this point we haven't saved anything on the database. We need to add the object to the that of a session first, the B session at author. What happened? Well, the things that importing the model doesn't automatically import the sequel Alchemy. The B object. So let's import it from the application p y file and retry from application import db Devi session add author. That's more like it. Now the object is added to the session but hasn't quite been written. Toe that a base, it's on standby sort of speak. A way to check if the record has been saved is to check if it has an i d. So let's right the object to that I base by committing the session and now checking if it has an i d Perfect. That's the little you search so that we can have a clean start for our next lesson.
60. The Author Registration Form: we will now create our very first form that will allow our authors to register. Historically, creating forms was a pain for developers because off all the operations involved, which included rendering the form on the page validation of the data reloading fields with data entered by the user when something was not passing validation and using the same form for editing. Thanks, toa Amazing open source libraries like WT forms. This process is now much more streamlined and we'll see how to go about implementing this functionality. Forms for a nap should be in the same folder, so I usually just create a forms that b y file inside the module. So go ahead and create one for the author folder. The first formal create is the registration form. So type the following. We begin declaring a register form class. As you can see, it's a subclass off last form, which is the flask WTI form main class that will give us a lot of the functionality we need . Inside, we define a full name property. There will be a Stringfield or, in HTML, context, a text input field inside of the field. We passed what the label or title next to the field will be, in this case, full name, and finally, we have a list off the validators we need. In this case, we're just telling WT form that this field is required. He cannot be left empty. Then we have the email property, which is an email field, which in HTML has a slightly different manipulation. Then a plain text field has a label off email address, and it's also required but needs to be validated against an email format. The password property is, as expected, a passport field, which in HTML forms you see us little dots or stars instead of the actual content, and this one is also required but also has a minimum and maximum left. We don't want passwords off less than four characters. Finally, we have a confirmed property, which is also a password field, and it allows us to have the user enter the password again, so make sure he's typing it correctly. To enforce this. We have a special type of validation called equal to where you pass the field to compare to , in our case, the password field above it and what their message to show the user if it doesn't match. As you can see, forms and models are separate things, and sometimes we'll have fields in the form that don't appear in the model. So now let's do the imports. The first line imports flask WTF. The second line imports the fill types we need under validators function. And finally we import the email field from a separate HTML five WT forms library that offers better handling on the HTML side for modern browsers. Save the file, and with that, let's see how we render the form in a template.
61. The Author Registration Template: we are now going to see how to render the form we just created into an author register template. The register form class allows us to create a WTI forms instance that we can pass directly to a template. So go ahead and open the author views file and let's replace the register function with the following here we're creating a new instance off our register foreign and assigning need toe the form viable. We then passed the form instance toe the author registered template will create next before saving the file. We need toe out the render template function toe the view as well as the register form class. So modify those lines on the top toe look like this. Notice how I leave the python libraries on the top and insert a space between them and our own library imports. After this is a good rule to follow for readability purposes, save the file. So we now need to create the templates folder for our application like we saw in her first hello world obligation. The Template folder lives in the root level, and inside of that will create the author APS templates folder. So go ahead and create the templates. Author folder once agreed that Creative filed cold register dot html Now put the following html on the file. So let's go over this code in detail. First, we create the form. Using the post method and pointing the action toe are register function notice we used dot register here. This refers to the author blueprints registered function. But since we're calling this template on Lee from the author views, we don't need to pass the full blueprint thing, However, if we want to use it from another blueprint with need to use author on the score app that register in the Ural function. Don't worry, Flask will let you know if it needs the full blow print. Next, you'll notice we have a weird form hit intact. Viable. The stock inserts a C SRF token. CSR F stands for cross site request forgery, and it's a security feature that WT form provides. Essentially, a CSF token protects you from unknown user forms, boasting toe the server by generating a random token every time the form is rendered right after you will see four lives with the form object on each of the fields. First, we display the label and then the actual field. Save the file. Now go ahead and run the flask server with flask. Run and navigate to register. You will see the form with the four fields. Now try to see the source code so that you can see what flask is out putting to the browser Just left, like on the page and select view page source. You'll see that WTI form is doing a lot of the heavy lifting for us bringing out the field . I DS names and other properties also noticed the CSR of token value on the top. If you refresh the page while looking at the source, you will see that the value changes every time. The other neat thing is that part of the form validation is being done for us in the browser level. If you have an HTML five compliant browser, for example, if you don't feel the full name and try to submit, the browser will complain about it. You'll see a sort of dialogue pop up next to the field. Same thing if you don't put a valid email on the email address field or if you don't feel the password field But we also want wt form toe valued a deformed on the server side, and for that we need to modify our view and print out the errors in the form. Let's check how to do that.
62. Author Form Validation: when you submit the form, WT form exposes a method called validate on Submit that's available on the form up. It's at that toe. The author of You file on the Register method at the following Save the file. Now run the flash server and enter all fields and press Um, it you will see the patriot fresh on display the words validated. That means that WT form checked all the fields and found them valid. So it passes the request to the cold section inside the if. Now go back and try to enter a password off three letters on both password fields. If you remember a register foam class, it asks for password to be at least four characters, Then submit the form. You'll now see that the form is re displayed, which means that the if section is not valid and the requests is passed back to the render template at the bottom. However, we don't see any errors in the form itself. That's because we're not displaying the errors in the template. Let's fix that. It's field has an air list, but let's just do the password one first to check how it works. So on the register html form at the following code on the password day, Save the file and now run the flasks server and try putting a three character password impressed Summit. You'll see the air displayed next to the field like this. But as you are already seeing, if we went into what the air messages for all fields, it will result in a lot of repetitive code. Right? Remember the dry principle. So we're going to leverage a functionality from the ginger template ING engine called macro . A macro allows us to create reusable, extreme code that can work as a function where we pass parameters and something is returned . Based on those parameters, I usually prepared macro templates files with an underscore so that I remember that these files are not to be used by themselves, so create the underscore form. Helpers html file on the template root folder and type The following note. I called it form helpers. That's because I can store more than one micro per file, so the first macro in this feild is called Render Field. I needs a function that I'll pass a WT form field object and you will output some important properties of that object. First, it displays the Fields label, which is sort of the title of the field. Then we output the fields contents with any keyword arguments I want to pass and by place using the safe ginger filter as this is not user enter code, and thus I don't want the macro to html escape it. So what type of keyword arguments can we pass? Well, we can pass a class to style the field or other costume parameters. We'll see that later when we'd style to form. Finally, we automatically print and errors this field has using that you l or on order list html tag . So we see the errors in a bullet, at least for me. Save the file and now go back to the race for html file and change it to look like the following. That looks much cleaner, doesn't it? Now you just need to add the macro toe any template and then use the render field function on each field. Save the file and make sure to run the flash server and hit register again. You will see the same form, but now all feels have the error checking for field this time tried to enter two different passwords longer than four characters. Press, um, it and you should see the following on the next lesson. We're going to make the application look better with the bootstrap framework.
63. A Better Looking Application: in this lesson will put a slightly better looking field toe. Our application, using the bootstrap firing, will also set up a base HTML template that will be the master template for all off the pages in our obligation. So let's create the basic steam l file under route off the Templates folder with the following contents here were defining foreman areas Toby, filled by templates inheriting from this base template, a title, a navigation bar and the main content area. We're also injecting the bootstrap CSS Online nine and the Bootstrap JavaScript on Lines 29 through 31. Also notice how we have on the footer the block name using whatever is stored in the block Name Come feet viable. Save the file and now open the author register html file at Make it look like the following here. We're now making this template inherit from basic HTML. We said a title and put our main content on the content block. We also added some Dave's toe. Better display the form using the bootstrap great system. Finally notice how we're now using the keyword arguments off our render field macro, bypassing a bootstrap glass on all our fields on also added a form role toe the form opening tack. Even though this course won't go into detail off how to use bootstrap, it's really easy to spend one afternoon learning the library. It's not too complicated. Save the file. And before we run our flasks server, we need to do some changes under render field macro as follows. We added a form group class toe, the fields Dave as well as a text danger class toe. The errors save the file. Now we're on the flask server and go to register. Looks much nicer, right? Try entering a password with three characters and press the register button. You'll see a nice red bulleted error. Okay, enough eye candy. Let's now see how we actually save the author information properly under database.
64. Processing the Author Registration Form: So let's see how we actually create the author record on the database with the information we input under register for So opened, the author views file. And let's add the following on the validate on submit section. Okay, let's do this step by step. The first thing you'll notice is that weird generate password hash function. What is that? A general rule of security that, unfortunately, some developers steal, Don't observe is that we never, ever, ever safe passwords exactly like the user typed it. If a hacker would gain access towards Atabay, somehow he would be game over for all our users. So the best practice is to encode the password. Using a method called hashing. Hashing generates a random string of characters using another base random string called Assault. That way, even if the same password issues in another website, the hashed password is different because off the salt, the cool thing is that not even us a developer knows what the password is. It's really hard to turn that password hash back toe a plain text, Even if you know the salt. The only thing you can do is compare that password hash with the hash off the same password and turn again by the user. We'll see how to do that on the logging method will write shortly. Once we create the hash, we then create a new author or an instance with a full name, email and hashed password. Then we add the author object to that of a session and finally committed so that it saved to the database will print out the author i d to the screen to make sure the record was at it. Before we test this, we need to add the hashed password. I burrito the file, so type the following online, too. And since we're doing that of its operations at the DB instance online for save the file and go ahead and run the flask server and enter some author information under form and press raised her, you should see this output on the screen. Don't worry if the number is not one, as long as you have a number there. If you get an error, make sure you're running that my sequel server properly, that you have access to it with the application user and password or any other issues with the code itself.
65. Checking the Record Creation on the Database: we can quickly check the record on the database using the flask shell. Go ahead and stop the flax. Never and type on the terminal flask show. If you're inviting anywhere, remember to have your veto lamp activated on the shell type from author Doug Models, Import author, author, aquarium. You should see your newly created record there. If you want to see all the fields off the record, do author equals author? That query that first author dot dick that's two underscores the word decked, and two more underscores with the exception of the sequel Alchemy, Instant State. While the other properties is what you have on the database, we can also log into the database to see the record, exit the flask shell using exit and now enter my sequel using your credentials as I described them earlier in the set up. Now select the floater that I base by doing use Fluckiger show the tables using show tables . You will see their migration table, a lambic version and the author table. Now do select star from author. You will see your full record, check the password field and notice. It's not the same string you used, but I rather long Siris of random characters. That's the password hash exit using exit
66. Using PDB: If you are in Windows, Mac or Lennox, you can also use another method to check if the record is being stored in the database or if there are any errors. And that's using the python debunker or PDB. Unfortunately, this doesn't work on python anywhere as there's no flask terminal available. But stick around just so you see how this works. So right up off the hash password viable at the following line. Import PDB. So my colon BDB said trays. I know it's weird. Write this down somewhere because you'll forget it over and over again. I think I remember it after using it. For five years, Python 37 introduced the break point function, but as of this writing were using Python 3.6. So that's not gonna work. So now run the flax server and enter the information on the form and press the register button. You'll notice the browser hangs, but take a look at the terminal. You'll see you have a prompt that is that by Fundy bugger. The prompt tells us where online. 15 off the author of Use file. The little arrow means that the hashed password command will be executed next, but it hasn't been executed. The script is frozen in time, waiting for you to do something. We can see, for example, the values on the form Instance. Just type on the prompt form dot Full name date. You'll see the name he just entered or form dot emailed or data to see the email to advance the script. Type the letter n, which stands for next. Now the script moved to line 16. That means the hashed password is set, So try printing it out with hash bass word. Since we're entering a block with multiple lines, type end and press enter. Any trick is that PDB remembers the last command. So if you just press enter, he will be just like if you have type and so press enter until you see the D. V session at author line. But stop right there. Okay, At this point, we have created the author sequel Alchemy Object type author to check it out. Now type author dot i d. We don't get anything. Why is that? Well, we haven't done a commit, so the record hasn't been reading to the database, so type and again toe advance toe the commit line and press enter to advance. One more line now type author Thought i d He should now get the records i d in the database unless you type on existing email and you get the following error. What is this? Well, you might remember on author model we added a unique constraint to the email field, So that means you can't register to authors with the same email. Will check how to fix that next using custom WTI form field validators.
67. Custom Form Validators: to pick up where we left off. We have found a potential issue with the author Registration function to trigger the error raised her to authors with the same email. The second registration throws a database error and hold our obligation to make sure this is checked. Before we start. The duplicate email author will use a custom WT form validator. WTI form allows to create custom validators using the validate method. On its instances, we can do form white validations, which will do for the logging form but for the registration will do an email specific validator so opened The author forms file and inside the racer form class introduced the following code. This method only validates the email field, so we pass email as the only parameter for this instance method. This email viable will hold whatever the use or entered on the email field off the form. We then do a look up on the author table to search if any user is returned with that email . If there is one, we raise a validation error with a message which communicates to the view that the form is not valid before we contest this at the following line under the system imports. Remember to leave one empty line above it. Also, we need to add validation error at the end off lying to save the file and start your flax server. Now, try entering the same email twice. You should get a nicely formatted error.
68. The Author Login: Now that we have an author in the database, we're going to build a functionality to lock them into the system. Let's start with the author form that's at a form will call log in form. This is pretty self explanatory. Will have an email and a password required for the author to log in. Save the file. Now open the author view file. And let's create a new route for the logging method. Don't forget to what the long inform in Line six. Save this file. We're going to need to create a logging HTML file on the templates Author folder with the following code Looks pretty decent, right? We have more or less the same fields we had in the race to inform template, save the file and check it out by going toe the logging euro. Enter any email and password combination and press the log in button. You should get a message that says Locked in
69. Checking the Login Credentials in the Database: off course, it's not good. Anyone can log into the application, so let's actually check the credentials in the database. First, go to the author form and add the following validate code inside the log Inform class. This validation is different from the custom validate email validator that was on Lee checking the email. This validate is value rating the whole form, and that's why there's no feels being passed as parameters. The first thing we're doing a global validator is to check if the form passes the normal validation. So first we execute the validate method, passing this instance as itself. If the form doesn't pass, validation will return falls, which returns control to the form with an on validated state. Then we tried to find an author record with the email passed in the form, which we access with self doubt emails, the data. If we find an author, then we check if the password hash stored in the database matches with the past bass word hash. If they don't match, it means the user is entering the wrong password and we append an error to the password field with the text, incorrect email or password and return falls, which again marks the form as invalidated. Otherwise, we'll return. True. The final else just passes the air back because there's no author with that email on the system. Now add the check password hash import online for saved a file with your flask server running tried logging in with the wrong password or with an email that doesn't exist, you should get the air message under the password field. Now try logging in with an email and password you actually stored. If you don't have one, you remember. Create a new one on the register. Euro. You should get the log in message.
70. Author Session: When you log into a website or application, you need to set some sort of cookie so that other pages that the logged in user loads received the user's information and prevent him from seeing pages he's not supposed to, as well as keep out unlocked users. The most secure way to do that is by using flask. Sessions will also redirect the user to the block home page when he logs in. So online, one at the redirect session and euro four libraries toe the flask import next at the following code on the logging validate on submit section. So here we look up the author and store two different sessions. The user I d. Under full name. Finally, we were directly user to the blocks home page. Notice. We don't do any checks off the password here because that's already being done by the form validate function we wrote earlier. Save the file and logging. Using a valid email and password, you should be redirected to the blocks home page. So how do we check if the session was stored? Let's do a quick check on the home page for the session. Open block views and on the index method. Do the following at the session, toe the flask, import online one and then save the file. Now, if you reload the home page and you are logged in, you will see the users locked in name. There's another way to check if a session, he said. Most modern browsers have a JavaScript console where you can see the cookies that have been stored by a site. For example, on Google Chrome Goto, view developer, Jaster console and in application, look for cookies and select the local host 5000. You should see a session string in there.
71. Logging Out the Author: if we have a logging method, we should certainly have a lager method as well. It's pretty straightforward. We just need to delete the session cooking. So head over to the author of You File and add the following The pop method removes from the session object both the I D and the full name elements. After that, we redirect the user to the log in page, save the file and now hit the low guttural. You should be redirected toe the log in page. If you now go back to the home euro, you should see the Blawg home String on the user at this point has been locked out.
72. Flash Messages: the last thing will do in this lesson will be to improve the communication with the user and notify him that actions he has taken have been successfully completed and for that will use flasks. Flash messages. Flash messages are a special type of notification that allows the user to consume them and then they automatically disappear. Let's see them in action. First will create a macro toe display messages in a nice wrapper. So go ahead and create a file in the root Template folder called On the Score. Flash messages html With the following contents, the macro essentially loops through all the flash messages we get from the building. Get flashed messages function that flask offers notice the with statement at the top. This essentially is a block that ends with end with, and it makes the viable messages available within the bloc. So if there are flash messages, we going toe a four loop and display the messages with a little bit off. Bootstrap you. I help save the file. And now let's include the macro in the author logging HTML template in line 11. Save the file and now opened the author Views file. Replace lying 22 with the following to lines and then add under. Log out the following. Don't forget to add flash at the end of the import online. One. Saved a file and create a brand new author. When you press register, you'll see the flash message above now locking and then hit the log out route. You will see the other flash message user logged out.
73. Unit Testing the Author App: We have done quite a bit off the author app, and we don't want to continue building our application before we are testing for this piece . Always build features with their corresponding tests and you'll be liked by your buses on your cold. Developers first will create argue tills folder with the test of utility we used in the counter application. Just copy and paste it from there or from my gate Hope repose. Make sure to add an in it P Y file inside so that our test DB module can be imported from other files. Next, we'll set up our order Discover test file in the root of the APP. Save the file. Now let's start building the author tests file, create author dot tests and put the following boilerplate code. This code should be familiar to you from the counter application. It sets up the different necessary imports sets up. Dot m creates the main author test class with a create app method to create our test app. A set up that leverages are tested be library and a tear down to shut it all down. Let's start adding some tests, but first will add a custom method to quickly create a user dictionary, since we'll need that in a lot off for tests. So our first test case will be user registration. So we start with the following this first case will register our John Smith user, and then we'll check that the string you are now registered is in the results. We need to follow redirects flag here because the register method will redirect to the logon page where the actual string is printed as a flash message. If we didn't have follower directs, the test would stay on the register page without a way to check if the string is present on the output, just to make sure we're on the right path, Safe to file and on the terminal, run by fun. Test that B Y. Make sure you have your virtual amp activated. Great. Our first test is passing. If an author record was created, we should be able to check it in the database. How do we do that? In that case, we need to set up a context because this is something we would normally do. We think of you off the app so we do the following here. We're creating a context of the app we call C Hit the home page and check if the author table has one user. This user is the one created in the previous registered test. Remember that all tests within a function or test case maintain the data on the database. When we start a new test case, all the data is a race and we start from scratch. Why do we need to get the home page? Technically, we could hit any page, but through that call were able to start up the context toe. Allow us to do that that I base operation run the test, and we should be all good. Let's do two more tests for the registered test case, one that tries to raise her another user with the same email on the second that tries to register with mismatching passwords. Notice how in the second test, we're just modifying the email and confirmed fields off the user dicked object. This allows you to write really concise tests, save the file and run the tests
74. Login Tests: Now we're going to write some tests for the logging functionality will create a brand new test case so that the database is clear. Let's start with the following. Make sure you invent this at the same level as the test you so register function. So the first line in the test case creates the user with a user dicked. Next, we create a context because we will be testing. If I user session was said, something we wouldn't be able to do without a context. Next will test the lookout functionality. Once again, we need a context because we're testing a session, not the output on the page. So if the session is none, it means the user has logged out. We'll finish with two easy ones logging in with the wrong password and with an inexistent email on the 1st 1 we create a new user and overwrite the password toe an incorrect one. And then on the 2nd 1 we just passed an email that hasn't been created. Save the file and run the tests. Feels good to have all our current at properly tested, isn't it? Now it's time to start working on the block, posting up so that our author can publish some entries
75. The Nav Bar: before we start working on the block posting feature, we're going to create a navigation bar so that users can easily go to the different areas off the app and logging or log out, create a file called NAFTA html on the tempered brute and at the following code. We're using bootstrap code. But notice that if statements where we check if the session is set, if it is, we display the use of the same and the log out like otherwise, we display a logging link. Save the file. We now need to add the nap bar to the existing templates. So opened the logging template and in Line five, insert the following line. Save the file and now opened the register template and do the same thing on the same line. Five. Safety's file as well and restart the flax server. Go to the log in page and you will notice the new enough bar on the top. Now logging with a valid author credentials, you will be redirected to the home page, but this is not a proper template, so we won't see the nap bar. Instead. Manually, go back to the log in page. You will now see the new locked in state off the nuff bar with the author's name and a log out link. Click on the log out link and you should go back to the looked out state, and with that, we're now ready to start working on the blawg posting at
76. The Blog Post and Category Models: the first thing will do in our blood gap is to create a temporary block index template. And even though it won't render any posts, at least it will have a proper structure and naff bar. So create the Block folder on the Templates folder on inside. Insert the following on a new index, ext. Email file. Save the file and now replaced the index function on the block Abuse Toe The following Remember to add render template in the imports on line one. Save the file and now go today index page to check it out. Now we're going to create our block model will have a post class where a block post will be stored, and we'll also want to organize posts by category, so we'll create a category class. So let's start by creating the block models. Python file Inside the blow gap. We'll need to import the B R sequel Alchemy instance from the application file as well as the daytime library for the published State Off the Post. Now we'll create the post class section. I'll write it and I'll explain what we're doing here. So here we have the i D. For the record the title and body for the Block Post, a published state and a life flag, which will use to mark which posts are seen on the block. When we make the delete function will be setting this life. Flag Toe Falls that slug is that you are a friendly string for the article pages, which will generate with the slog. If I library this way, each post will have a nice looking mural that will help us with search engine visibility as well. Now take a look at the category I. D. It is an integer field and references a foreign key off calorie dot i d ah, foreign key is a way to connect one record on a table toe, another one in another table. And what we really doing the database is that we stored the I D off a record in the external table in the internal table record, for example, let's say that we have a post title. Mets win the World Series with an i D off 15 in the post table. Now on the category table, we have different sports categories like football, hockey and baseball. Let's say baseball's category I d is three We would then assign the post toe the baseball category by adding the number three in the category I. D Field. Likewise, we have the author I d. Foreign Key toe the existing author table to be able to know which author wrote this post. So how does Sequelae Camino with Table to link this author i d to the foreign key parameter references is the name off the table. If you check the table created by the author class, you'll see it's called Author in lower case not author in Upper case. You'll see this more clearly when we start inserting records under blogged Post stable. Next, let's create the Enid Method, which is called when we create the record, Do the following Here we said the fields for the post record some things I want you to notice first, since we will be passing an author object and not an author, i d integer toe the post. We still need to record the integer for the post author Foreign Key. So we extracted from the author object passed on the perimeter. Now, if you see the category parameter noticed, it will also be an object. But this time It's optional since we defaulted to none. So we check first if it's being passed and then assigned the objects I d toe the category i d. Finally, if published, state is not being passed. Then we said it to the current time. Notice that I used a UTC now function. This is the coordinated universal time at zero degree longitude, and it's not affected by any daylight savings time. Why not use the local time where we live or the user's local time? Because other users looking at the block might live in a different time zone. And it's much easier to calculate the time difference between UTC on the user looking at the post. So always, always used UTC on anything that stores the date and time in your models. We're almost done, but there's one more feature will use in the model. It's called a relationship method, so before the in it type the following this allows us to have the actual author or category object attached to the record. Instead of doing another database query. When we want to fetch that information, for example, let's say we want to display the author's name on the food er off the specific post page. Since we're only storing the author idea on the post record, we would have to do another query interview to get it before we render the page with sequel alchemist relationship. We already have a post that author object that we can traverse, so to print the name of the posts author, we would do post that author that full name. So how does relationship working this case? You passed the actual class, not the table name. First, we didn't define what the backwards reference looks like or back right, which allows us to traverse from the other table back to posts. So it's like killing two birds with one stone. Now on the author and category objects will have a post property, which allows us to get all the post and author has written or older. Post a category contains. So if, for example, we're on the author detail page without any additional queries, we can do author that posts and that would have a list off all the posts. By that offer. This type of database relationship is called one too many, because one author can have many posts and one category can have many posts, however, noticed that one post can't have many authors, at least in this model with created. So there's always a direction in the one to many relationship. We'll see the many to many relationship later, when we create the tags feature. Whenever you're creating any model and you're not sure where to put their relationship definitions, it's useful to remember which table is the many side and put the relationship definitions on that side. Finally, we pass how to load the list off related objects by declaring a dynamic type off Lacey loading. I know this sounds a bit funny, but think of this as how eager you are to have the related objects loaded in memory since we think we're not going to need all the related objects loaded every time we use Dynamic, which just returns the parent object and Onley loads the related objects. If we ask for it, for example, by doing post that author that full name, this saves time to render the data on the screen. Don't worry too much about this for now. When you're ready, you can learn about other types off Lacey loading. Let's finish the block models by creating the category model. It's pretty simple. We're just going to the fine and I d and the name and that's it. Finally, let's add a reproduce method for both classes so that we can display the instances properly on the shell for the post class will do and for the category class will do save the file and will move next to the block post form definition.
77. The Blog Post Form: we're now ready to start our block post form. Let's right the main class and we'll go over some of the new stuff. We have a title, which is a Stringfield, which is required and has a max length. We then have a body, which will define as a text field decks. Fields are the ones you see on hte email forms that have multiple lines. Next, we need to tackle the categories, so we'll have to fields for that. First, we'll have a drop down, which we do. Using the Query Select Field here we defying a query factory, which is a function were right shortly that grabs the different options from the database will allow the select field Toby Blank. If the user wants to create a new category, then we call Days new category field and well defined it as a non required string. So above that will define the categories Query factory function Since we need it defined before it's called in the post form class, that was pretty easy. Were just returning a role category query. You could do some fancy queries like filtering or ordering the data, but we'll leave. This US is now Let's add the imports and we're done. Save the file and we'll start working on our block post. Create template next.
78. Blog Create Post Template and View: we're now going to develop the template that will allow us to publish a new block post, so create a new file called Post Op X TML inside the Templates Block folder and then write this in it. It's pretty straightforward, and nothing you haven't seen before will be posting toe the post method interview with the title body category. Select on the field to enter a new category, Save the file and now let's open the block for you. File and enter the following code. We want to make sure the form it's rendering as intended for now on the top. Let's do the following import. Save the file before trying it out. We need to do the database migration since we added the new block models. So to flask they be my great You should see the migration execute. If you get any errors, double check the model file. This operation generated the migration version file. It's always good to check it out before doing the actual changes. This is what mine looks like here. We see that we're recreating Tune your tables category and post notice at the end of the post. Set up how we're setting the foreign keys toe author in category. If you see any errors, you can delete this file, fix any issues on the model, and we run the flask. Db Migrate Command. Remember that at this time no changes have been made on the database. So let's do the actual upgrade by doing flask, they be upgrade. Great. Now we're on the flat server and head over to post. You should see your post form render. At this point, if you press submit, nothing will happen. It's now right, the actual database processing off the form.
79. Blog Post View Database Processing: we're now going to take the authors, block post data and save it on the database. The first thing we need to figure out is the category piece. Is it a new category the author is entering, or is he selecting one from the drop down? Let's store this either way in a viable will called category, so enter the following under the validate on Submit. First, we check if the new category field has stayed on it. If so, will create a new category sequel. Alchemy upped it with the name on it and added to a session. Now the thing is, we need this safety on the database because we need the I d for the Post model, remember? So how do we do this? There's a special method in sequel alchemy called Flush, which doesn't save the data on disk, but it does do a sort of a pre safe, which generates the potential I D but still keeps decision open for other rights or updates . So once we do the flush, we get the proper category D and assign it to our category viable. If the new category field is not set, then we assigned category toe. Whatever the authors elected on the drop down next will write the actual that are based Operation Notice. On the first line, we get the author object by looking up the author by the locked in session user i d. This, of course, assumes there's an author logged in. Next we get the title on the body, applying a Python strip operation to both so that we take out any proceeding or posterior spaces. Then we create the post sequel Alchemy Object and then added to the session and committed, which will right all pending operations to desk, including. If there's a new category, we're almost done, but we want to generate the block posts. Who are l using a slog generated from the post style so online two at the following import . Then after the commit, we just wrote at the following Here we generate the slug using the slow defied library, we use a combination off the Post I D. On the title. So I used the I D because if we're right to block post with the same title, they'll still have different Urals. We then just modified the post object, adding this look property and since we're not adding a new record, just modifying it. We just commit to this, save the file and make sure you're locked in before you post the first article. Go ahead and try posting your first block post, creating a new category using the new category field. When you hit the post button, you should be taken to the same form with the same content. If you get any errors, double check. You're not missing anything. How do we check if the post was saved? You can log in, tow the database and see the record by doing the following notice how the slug is saved and that the public state is stored as UTC time. We can also check the record in the flask shell. Now let's try something else. Log out using the naff bar on the browser and try to create a new block post. Notice how on our category pulled down, we now have the category we created earlier, which is good news. Select that category now Try clicking the post button. What happens? We get in there. If you check in the stack, you'll see the culprit. There's no session I D. So how do we ensure that an author is locked in and that other block visitors can't post to your blood by using something called a decorator, which will work on next?
80. The Login Decorator: when we want to restrict a specific route unless a certain condition is met. A useful feature to use is called a decorator. The word decorator comes from the so 40 signed pattern, and in essence, it involved wrapping a function with another function so that the inner function is expanded in some way without modifying its internal structure. We've already used a decorator, the Route decorator in our views files. Decorators start with the at sign. The Route Decorator assigns a specific girl to whatever function is underneath for our application. There is a perfect use for another decorator battered. We went to easily make certain routes to be accessible on Lee if an author is logged in and specifically the post route. So let's build a locking required decorator. Create a file called Decorators B Y inside the author folder and put the following code in it. We're using a python library called Wraps, which is, ironically, in itself a decorator. The function we want to define sits inside the decorated function definition because we're importing session from flask online to we have access to the session. So if the session I D is not said, we're going to send the user toe the log in euro. But notice we're passing a next parameter saving the current request you, Earl, that allows us to send the user back to where they were before we diverted them. Toe the log in page. Since there's no else here, the function just continues its way. If the session I d set, which is what we want, save the file, we now want to slightly modify the log in page so that it can read the next parameter when users hate the protected page. So at the following code online, 31 off the author views Page, we will be saving the referring Your l passed on the next parameter on ascension. Viable. We will also call next, then replaced Line 38 with the following code. We check if there's a next session, and if there is, we read it the little session and redirect to that page. We need to at the request library toe the imports so added at the end Off line one. Save the file. We're finally ready to use our decorator Open the Block Views file and online eight will import our decorator, then on 9 17 will add our decorator before the post method and after the route decorator, Save the file. And now go to the home page and make sure you log out. Then go to the post euro. You'll see something like this. Notice that the Ural has the next parameter in the Euro, although the page looks a bit funny since it is your all included log in using a valid author and as soon as you again you should be taken back to the post page. Pretty cool, right?
81. Blog Article and Markdown: We now want to be able to display posts to our block visitors, and we'll do that using an article view and template. So let's create a new file called Article X TML in the Block Templates folder with the following code. In this template, we are printing the title body author and the category. If we have it, notice we have a funny line character called a Pipe and Award marked down next to the post body. A pipe is a modifier for attempted viable. We're going to be rendering blogged articles using a mark up language called You Guessed it marked down With Mark down, you conform at bullets, titles and subtitles, Italics and bowls Using special characters, Google marked down for a little more background on what you can do with it. Save the file. We have flask markdown already installed in our requirements. Txt. But we need to add it to our application for your wife Ill. So open the file and add the following import online for and the line 22 at the following Save the file. Next will add a route on the block Views file So old away to the end at the following notice this handy query filter cold first or for four. If no post its return, it throws a for four, not found error for us. So how do we see an article? We haven't worked on the home page yet, but we can see on article right after we created. So let's add the following code after the DB session. Commit line on the validate on submit section of the post. Make sure to add flash, redirect and euro for toe the flask, Import online one and save to file. Now let's try creating a new block. Bulls Try using some of the mark down codes, for example, adding asterisks too bold some of the words or do. Subtitles with pound pound When you submit, you should be taken to the article view page.
82. Blog Post Tests: we have written enough code for us to think about adding some tests. So let's start writing the block tests for what we have so far. Create a tests. Be wild file on the block directory. We'll start with the regular set up, which should look familiar to you. We have our regular imports, but notice the's lock. If I import, then the dot m the models and utilities. And finally, the main test case we're calling Post test with a set up and tear down methods will create till dictionaries that will reuse through the tests. A user dicked and opposed dicked perfect. So the first test case will be about posting articles. Let's begin by trying to post without being logged in. We should get a message asking us to log in Next will register and logging our mock author . Now let's try posting the article with are pretty fine. Posting will assert that the article was posted and that it was filed under the tech category. Save the file and let's run the tests perfect. With our obligation fully tested, let's move to creating a proper home page for a block
83. Blog Home Page and Pagination: before we start the block home page, let's add an option to post any articles on our naff bar. So opened enough html file and add the following item online. 12 that will display the link to create a new post on our naff bar when we're locked, then save the file. Okay, so we're going to start the block home page. Let's start with the template. So opened the blawg index html template and replace the contents with the following. Let's take a look at what's happening here. First, we looked through all the posts that are being sent to the template, assigning each one the post viable. We then display the title of the Post with a hyperlink toe. The article detail page. Then, with this play only the 1st 220 characters off the post. Since this is the home page, we then display the authors full name and the date of the post Former did with the String F time function. Notice how, thanks to the Data base models relationship connection, we can do to harps first post than author than his full name. This is the power off foreign keys and sequel Alchemy Finally, we display the category. If there's one, save the file. Next. Let's set up the views B y for the home page on the block directory. So replace the index method with the following Here were fetching all the block post that have the life, Field said too true and assigning it to the posts viable. However, we want the most recent posts appear on the top. So we grabbed the post query object and applied the order by function on assigning toe a new viable with cold posts Order. The order by function allows you to manipulate a query salts list and order it by any field . We are using a special method off the publish state object called Desk, which means descending i e. The newest posts. First we finally passed the posts Order object to the template, assigning it the template name posts. However, we can make this code much shorter by using sequel Al Commies. Daisy chaining. Essentially, what we can do is combine two or more operations using a dark between them. You've used it before when we've done the first method on the queries, but let's do it with the ordering, so replace the code as follows. Now we don't need to have separate variables for the two operations and just store the results on the posts viable. As long as the viable is a query list and not just a plain tight on list, we can continue doing more operations on it internally. What happens is that sequel Alchemy waits until you really need the results and just aggregate all this operations, as the court instructs. So really, we're doing only one query here to the database. Not too, which is very efficient and fast. Save the file and now start the flask server and go to the home page. Depending on how many post you have, you will see them listed here in descending order. Go ahead and create new block posts so that you can see them here when we have four or five posts or even a dozen. It's OK to display them all in the home page like we have here, but what happens if we have hundreds of posts? We might want to introduce a concept called Imagination, which displays a subset of the results and displays some sort of navigation links to move to the next substance. Let's implement that solution. But first, make sure you have more than five posts in your block so that we can see the pagination in action. Okay, ready. First, we want to modify the block views. Let's do the following. We define a page parable that will read a page parameter being passed to the route. If there's none, it'll assigned the number one to it. We will be able to determine what page of the results were at using this parameter. Then we're going toe daisy chain another function at the end of the posts Query called paginated. Imagine a trunk. It's the results in sets or pages on the function takes three parameters, which page we're currently on. How many results for Bates we want? And finally, if we want to display a 44 error, if somehow were forced to, a page with no results will set this toe false. As I don't consider days to be a really error notice that I put a constant called posts per page at it online 12 and let's set it to five. Why not put the constant inside the index function I usually like to live constants defined at the top of the file below the custom imports so that other depths No, this is something they can change and so that we can use it in other routes where we might want to use the same value. We also need to add the request library from flask. So changed these online one. Save the file. Now we need to modify the block Index template Change line 18 to the following. So what happened Now the posts viable doesn't just have a list, but it has the subset of records in the items property. It also has other values that we're going to use shortly. For now, save the file and load the home page. You'll see only the last five posts displayed. Now at the parameter question mark ph equals two to the euro and you'll see the next set of results off course. Users are not going to type this manually under your URL to advance to the next page, so we'll add a meaning navigational element on the bottom off the template just at the following. So now our posts viable. Not only has the results in its items properties, it also has a bullion if there are more posts before or after this page and also the previews and next page number from the one we're looking at. So here we're checking. If Posts has prev is true. It means there's a page before this one, and we render the link with the previous page as a parameter for the view. And similarly, if Posts has next, we display the link with the next page number. Since we're on reverse chronological order, we say newer posts for the previous page and older posts for the next bait. Save the file and now open the index page. You'll see the links. If you have more than five posts, next will spice up our block posts with the ability to add images.
84. Uploading Images: In order for us to upload images, we need to do some changes on some existing areas off our code. We'll start by adding the file upload field on our forms file. So open it and at the following image field on post for the WT form file. Field Renders have filed a blow dialogue on the form where you can select a file from your computer and send it along with the rest off the data to the server file. Field has a validator called file allowed where we can define the file types we allow on server. So in this case, we're allowing only J. Peg and PNG image file types. Make sure to what the file field in the imports online, too, and to file allowed validator online for save the file and now open the post HTML block template will add the actual image element at the beginning off the field list on the form save the file and now go to your block post page to check out the image element there. Of course, selecting an image here won't do anything just yet as we need to implement this on the database model. So let's do that. Next, open the block models file right underneath the body column. Let's add the following. What we're going to do is to store the image name and not the actual binary file off the image on the database. My sequel also allows the storage of binary files, but I found this to be cumbersome for storing images for something like a block platform ID . Rather stored the file itself on a server that can then serve the image statically than overload the obligation server to fetch these from the database. So why 36 characters in length? We're going to use a randomly generated hash with that library called you You I D. That generates strings off 36 characters. I'll explain a bit more. Why in a bit now at the Image property on the innit method. Save the file. Since we modified the data base model, we need to do a migration. So on the terminal, run the Migrate Command. Next, we'll check that the new migration file looks OK. This looks good for the upgrade. It adds the Image String column on the post able, and if we downgrade it, deletes that column. Now We'll apply these changes to the database. So to flask, baby upgrade Perfect hope you're getting the hang off migrations. Okay, time to do the actual image processing on the block views controller. So opened a file right underneath the validate on submit function. At the following we begin by creating an empty image, I d viable. If the Post has no image, the field will be stored as no. We then check if there's an image being sent through the form by checking if there's an image field with data in it. If the user then imposed an image formed, our image still exists, but the data property will be empty. We then assigned the F buyable toe the contents off the form image data. Next, we generate a random i D for the image using the U. I. D. Library. The slavery generates a random string that is suitable for unique I DS and that will always have a length of 36 characters like I mentioned earlier. So why not use the name of the original file? The problem is that the file name might have weird characters or spaces that can break the external rendering, and we don't really get anything valuable storing the original name off the file, continuing with the code with then create a file name with the image I D. Plus the extension PNG. Since we will be converting all image types to the PNG format, we then create a file path where we will save the foul, which is a combination off the block post images bath setting we had on the file name. We used the OS that path that during library, since we want to keep compatibility with Windows and UNIX based folder structures. Finally, using the Python Image library, we open the file data and save it in the path converted to the PNG format. We're almost done, but we want to address another piece of the image bustle. When users upload images, they can have different sizes and proportions, and we want to somewhat unify the image dimensions so that our post layout is consistent. For that, I created an image rece icing function that I just copy and paste every time I need this functionality. So at the end of the file, put the following code. What dysfunction does is that it requires the images file path the unique i D. The sizing pixels off the with We want on an extension toe the note. The different size in the file name. Using a bit of math, we detected images with and then recites it, using the with size. We want keeping the height proportional so that we don't deform the aspect of the image. Finally, we saved a file with the extension passed to the function. With this in place, go ahead and at the following under the form image conditional, we wrote earlier. So we'll save a large version off the image for the article template and a small version for the index template. We need to add the image field toe the model on top of the file at the imports that we need on the block Post images path constant from settings. We're done with a view. So go ahead and save the file before we create our first post with an image, we need to add the image to the article and the index template on the article template at the following in line 15. Now open the index template. And at this online 30 we're essentially dividing the article into two columns on the left will have the article and underwrite the image. If we have one safe to file, you need to create the local folder where we upload the images, so go ahead and create it. In my case, I created static images. Uploads folder. Now go ahead and create a post with an image. When you press submit, you should be taken to the article view where the image is displayed, and if you go back to the home page, you should see your first post with an image. Now go check the static images Uploads folder. You will see the three images there with their U I. D filings. One is the original image. On the other two are the rece iced versions. Try uploading a few images with different ratios to see how they are resized.
85. Editing Posts: everybody bakes me. Steaks and block authors are not the exception. So we went to what functionality Toe added our block posts. The first thing we would be tempted to do would be to create a new template on our Block folder called Edit XML or Something like that. He would have the same fields as our post HTML image title body category, etcetera. But one thing I want you to always think about, which differentiates beginner developers from professionals, is toe. Always identify areas where you're repeating code and think about ways to eliminate that repetition. In other words, dry or don't repeat yourself. So we're going to add code so that we don't need another template, but rather used the post extreme El Template tow both right new posts and added them so open post html and will add condition. ALS, based on a new viable will pass through the template called action. If the action is new, then it's a new post. Otherwise, we're editing an existing post. So online 13 replaced the title toe. The following Now, since we want to post the different routes based on the action, viable will change the four method toe the following notice on the edit part of the method were using a parameter called slug. This is how we'll identify which article were editing. Will also be passing the current contents of the post to the template using a post viable next will want to display the posts image so that the user can see it and has an option to upload a new one. So below the form hidden tack, insert the following Finally, will want to display slightly different messaging for the submit button, so change it to the following. Save the file Now before we work on the new route, let's make sure we can create new posts. With this template. We need to add the new action tempted Viable toe the post route. So at the action, viable online 78. Save the file and make sure you can post a new article. Now let's do the actual edit route on our view right after the article route. Let's start with just the rendering off the four. Notice how we're using a slightly different version off the post form class when we're doing a new post. We just used post form parenthesis, but if we want to edit an existing record, we pass it to the form using object equals. So first we fetch the post using the query filter and then pass it to the fore, save the file and now goto any of the existing articles and replace the posts on the Ural. With edit, you will see the same article now loaded into the form. Of course, none of the changes we do here will be saved in a database until we put some logic on the view. So let's add that first, let's add the validate consummate. We're going to save the original image and title on temporary variables because we're going to check if those changed later on. But look at the last line there. The popular object method off the form. What this flask WT form function does is to take the contents of the form and applied toe on existing record in this case post, which were fetching from the database when the form is received after the submit. So now let's process the image taking to consideration that the user might be changing it. This is similar to what we did on the original post method, but notice that if there's no image data being passed, we set the post image to the original image variable we used at the beginning. If we don't do it this way, when we use populate, object and the use of an impasse in image, it would actually delete the image from a record. And we don't want to do that. If the user doesn't select any image, it means they want to keep the original one. Next, we check if the user entered a new category again similar to our original post code. So what happens if the user changes the category using the drop down on the form? The popular object takes care of that as it will replace the new category in the post record selected by the user on the form finally will need to update our slog if the title changed, and that's why we stored the original title at the very top. Okay, that's it. We can now save the edited record on the database, save the file, and now try to add it some of your articles, selecting them and then replace in the post with edit on the euro. Try changing the images as well. Off course. It's not very user friendly to keep using the euro. Edit hack. So let's actually at an edit link on her articles. I opened the article, ext. Email template and add the following online. 31 Save the file and now every article will have an edit link.
86. Deleting Posts and Writing the Edit and Delete Tests: along with the editing function, we should also have the ability to delete posts. We will be using the life flag on the model, since we never want to really delete anything but rather hide it from the user. That way we can restore post that we accidentally erased as well as conserved all the data , which is really cheap today with low storage costs gets created. Elite method After the edit one. Unblocked views Pretty straightforward. We just fetched the article slug and set the life lacto Falls on updated on the database. Save the file. Now let's add the lead functionality to the article Template online 33. Just insert the following Save the file and now you should be able to delete any article from its article view. Now that we have edit and delete functionality, we need to write tests so that we make sure they're working correctly and guarantee that no new code breaks the logic. So open the block tests file and add the following. First we'll register the user, then logging and post an article. We then proceed to change the title to my new awesome post within Checked that the article , edited message appears and that the title has changed on the article view. Finally, we hit the delete route and make sure that the article deleted string appears on the page, save the file and run the tests.
87. Blog Tags and Tests: we're now going to implement a feature that requires a new kind off database relationship. Until now, we've seen one type of relationship, the one to many, which is the relationship between author and posts, since one author can have many posts. Similarly, we have the post to category one to many relationship. We can traverse the post related to an author or category, thanks to the DB relationship decorations on the Post model. But now we want to implement tagging tore posts tags allow us to search related posts based on different strengths. But the up to now difficult thing will tackle is that one post can have many tags, and one tag has many posts. It's sort of a bi directional one to many relationship in order to do that will need to create a special kind of table called an association table, where we store into columns, the posts and the tags and the relationship will be each record on that table. So open the blood models and let's add the tags model at the bottom. Pretty simple stuff. So far now, beneath the last import will add the following code. This is the association table and I like to call them X ref tables because it's the tag to post table will now add the relationship column under post model Bear in mind, this is not really a column that will be added to the post table. It's more of our reference that sequel Alchemy will keep to know how to get the tags related to the post and vice versa. So notice that we're defining tags as the relationship in plural because we will expect to get a list here next notice on the secondary parameter, we're passing the tag ex Post X ref table and that the lacy parameter Issa sub query, which allows us to load the tags at once as part of the original query so that we save time and because we'll always need the tags when we get opposed. Finally, we also set the backwards relationship from tags, which will be called Post, and those we can Lacey load dynamically because we don't need to load the posts from a specific tag every time, save the file. And now let's add the ability to add or edit tags on the post template. The way we're going to tackle days is to manage it outside of WTI forms because we're going to need some custom processing for the tax, allowing the user to pass it using a comma separated list of tags so opened the block Views file and on the post function will start by assigning the tax field from the form to a viable and then adding it to the render template in Line 80. Let's do the answer mitt in a bit. Switch to the post template and let's add the tax field form input online. 31. Now let's go back and finish theon. Submit method we're going to do to help her functions, to be able to save and low tags. So at the end of the Views file, add the following This function expects the post object and the tags field contents. First we clear the existing tax the Post has by calling the Python clear set function. We then looked through a list of the tax by explaining the field by the comma character and checking if the tags exists. Notice that we slog if I the tack name, since we don't want spaces or weird characters, if the attack doesn't exist, we create a new tack object and upended toe the post tags list. So going back to a validate on submit online 67. You can add the following. We don't need to do anything else, since we've already saved the tags. Toe the post record on the helper function. One less thing. Let's add attack model on the import online. Eight. Save the file before we test posting our first article with tags. We need to do a database migration to add the new tables. So let's to flask. Baby migrate. If you check the migrations file, you'll see we're creating both attacks and the X ref table. Okay, so did that of a soap grade flask. Baby upgrade. Now try creating a new post with tags on it, separated by commas. You shouldn't get any errors, however. We can't see the tags on the post yet. For that Opened the article template and at the following online. 31. Save the file and reload the article page you created earlier, and you should see the post tags we now need to be able to add it. The tax on the edit form for that will create a low tax helper function so that we can display the stags on the four. This function essentially gets the post object as the parameter and then creates a string with all the tax separated by commas. Notice will return the strings without the last two characters, as they will be a comma in the space now on the edit route at this line after the form initialization, this is saying, if we see the tax on the request, use that otherwise on the first load parts attacks on the Post Using the load Tax helper function, Let's add the tax field toe the template context and let's add the safe tags helper before the database commit. Save the file and now try editing the articles. Stags. Let's add us more changed your tests so that we have some the full tax on the main post generator function and also test the editing off tags on the edit test. So open the block tests file and that the following to the Post Dictionary Online 51 then Online 78 will replace the tags on the post at it. That means that we've replaced the tax off the post to just be the angle So let's test that flask is no longer attack in the post for that ad online. 84. The following Save the file and run the tests.
88. Filter by Category or Tags: The last thing we'll do is to enable users to see articles related to a category or attack . Will put hyperlinks whenever we display them so that the user can see posts related toe, that tag or category. So the first thing that we would be inclined to do is to create two new templates 14 categories and one for tags where we display older posts and pulled imagination. Etcetera. Well, you can see how this can become repetitive and repetitive is bad because off the dry principle right, What we should do instead is to extract the post list code from the Block Index template and put it in its own template. Helper will call this the article list helper. Save this file and then change index html to replace all that snippet, toe this save the index text email file and finally at the title Viable on the Block Views index function. If you're on the flag server, you should see the same list off boats, but now you should have the title on the browser bar. Now let's create the categories view route. So at the following before the image precise function notice we're passing the category i d as the parameter on the euro. We then fetch the category and next week wearing the posts that have that category ordering in descending order and pack in aiding them. Finally, we passed the posts toe a category posts template will create shortly. We could have also fetched the post using the reverse relationship we created under Post Model like so since we're interviews file, let's go ahead and create the tack route right underneath that one. Notice we're using the tag that post square here instead off using post the query. Since this is a many to many relationship, he would require us using something called joins if we started from the posts. But since we have this handy back relationship to find in our model, there's no need for something complex. Save the file. Now let's create the category posts template with the following code. We essentially doing the same thing as the index stars. With the exception of the pagination, which connects the Ural toe, the categories view we just created Save the foul and let's do the same for the tag posts. This is very similar, but notice we're not repeating code as the pagination is different. Saved a file. Everything is ready to go, but we're missing something important. There's no way to reach this routes unless the users type it manually under Euro. So let's allow users to get to those pages by putting hyperlinks on the template where you can get to that information. First, let's do the article X TML. We're going to add the hyperlink toe the category on the if statement, and right after that we add the tags. Hyper lings, save the file and now load on individual article. You should be able to click on the category and the tags and get a list off posts related to them. Finally, let's update the article This template helper with a hyperlink to the category in. Since we don't display tags here, save the file and check out the home page off the block. The category should now have the hyperlinks with category page, and that's it. We've completed our amazing flask block. Congratulations on making it all the way here. Now I want you to build a new feature on your own, so let's check that out
89. The Final Project: There is only one way to learn something really good, and that's by doing something by ourselves. You have now been exposed to a number of techniques, and so I want to challenge you to add a new feature to your blawg without looking at me. Type it and hopefully without copying it from somewhere else. The task is that you build a capacity off anyone to add comments, toe any of the block posts. They don't need to be signed it, so you only need to ask their name and the text of their comment after the press submit. They should be able to see their comment on the bottom off the common list, so comments should display in regular order i e oldest first newest last. So go ahead and try adding that functionality. If you want me to check it out, put it up in get hub and then tweet me a link to the report and I will look at it. Good luck
90. Conclusion: Congratulations on finishing the course. You have taken a huge step in learning how to build a complex flask with publication using best practices. See you in the next course.