What are Flask Blueprints?
Hello everybody and welcome back to only Flask tutorial. So in this video, we're gonna be talking about blueprints, which essentially allows us to divide up our application into separate Python files where we can actually pass specific views and render templates from different areas of our kind of project, our application.
Now this is really nice because sometimes you might create, let's say maybe like an admin page or a specific login script or something that you could reuse in different applications. Well with our previous knowledge, we would have had to put all of that in the same Python file, which would make it much more difficult to reuse those different components in new Flask applications.
So here I'm gonna show you how we can divide things up with blueprints, how we can create kind of our own little mini apps inside of the big web application, and then how we kind of reference those and use those properly. Shouldn't take too long, but let's go ahead and get started.
Creating a Blueprint File
Now the first thing I'm gonna do is create a new Python file which is gonna be our blueprint. Now the blueprints are kind of just extensions to your app. So you're gonna think of this main file that we have, and I've just kind of modified this a little bit from last time, and I'm sure you guys understand what's going on here, as like the driver for our application. This is kind of what sets all the blueprints up. It's the first thing that we go to, and this is gonna define kind of the behavior and those blueprints are kind of little extensions that can be used from this file.
So what I'm gonna do is go File, New File. To keep this simple, I'm going to save this directly in the same directory as my main.py file. I'm gonna call it second.py and what we're gonna do is just import a few things at the top here. So from flask import Blueprint and import render_template. Now what I'm gonna do is set up this as a blueprint. So the way that I do that is I'm gonna create a variable, in this case I'm gonna call it second, but you can call this variable whatever you want so long as you know the name of it. And I'm gonna say is equal to Blueprint.
Now in here I'm gonna set the name of my blueprint, which I recommend is the same as the file name and as this variable, but doesn't have to be. And then our import name is always going to be __name__. Pretty much like, unless you're doing some advanced uses, you're always just going to do this, which represents the name of this file. It's a special Python variable.
Now the next thing that we need to define, and this is optional but you usually will want to define it, is the path to your static folder and your template folder. Now the reason you do this is because technically you could have a different folder that stores the templates for these views. And this is gonna have whatever functions we define here. Maybe they want to use templates with the same name but that look a little bit different. So in that case, maybe we create a new template folder, we create a new base.html file, and from this template or from this blueprint we're gonna render those templates. Now in this case what I want to do is just reference the original template and static folder that we have. So to do that, I'm gonna say static_folder equals 'static' like that, and I'm gonna say template_folder equals 'templates', if I could spell that correctly. Okay, so that's as easy as it is.
Defining Routes and Registering the Blueprint
And again, you can change the name of those to be whatever you want. And what is this black box? I'm gonna try to get rid of this and be right back. Okay, so I don't know what that was, but anyways, now that we've done this, um, everything's kind of the same as what we've done before. There's no need to run like app.run, do this, if __name__ == '__main__', because we're not gonna be running the application from this file. We're only gonna run it from here and then we'll just use some code from here.
So what we can do is just set up our routes and set up our functions like we would before. So what I'm gonna do is rather than using @app this time, I'm gonna say @second.route and then I can set these routes to be whatever I want. So let's start by just doing /home and let's actually set another route and let's just make it equal to / as well. Now we'll just make this really basic, we'll say def home(): render_template, and then we have that home.html template. Since we've referenced this templates folder up here, we have home.html, we can render that, and then we'll see this image popping up. I'll just get rid of that h1 tag for now. Okay, awesome.
So now that we have that, what we're gonna do is actually set up this blueprint from our main Flask application so we actually use it properly. Now, what we need to do when we start doing this is just import the actual Python file that holds this blueprint. So second is the blueprint, we need to import that file. So I'm gonna say from second import second. Now if you named your variable something else, so maybe you named it second1 like that, then you would have to change this to second1 there because that's actually what you want to import and what you want to use.
Okay, so that's pretty much all we really need to do. Now we're just gonna say app.register_blueprint(). We're gonna type the name of the blueprint which is second, then we're gonna set an optional url_prefix. I'm gonna set it equal to blank for now and we'll get back to this in a second and talk about what that is. This is as easy as it is with any other blueprints you have. If they're in the same directory, you just go from third import third, from fourth import fourth, and obviously you can name them whatever you want, just do those imports, register the blueprint as whatever it is, and then whenever you go to /home, it'll just find it in this blueprint and you'll go there and we'll talk about how this works in a second.
Understanding Route Precedence
So notice first of all before I run this that I have this app.route('/'). So test is / and it's gonna render <h1>test</h1>. But here I have / as well. So what does that actually mean when I type /, am I gonna go to test or am I gonna go to the homepage? Well that's what we're gonna test right now. But take your guess and you know why you think we're gonna go there.
So let's run python main.py. Let's get our web browser up here. I'm just gonna go, this was already up before, so let's go / hit enter and whoa, we get an error. And that is because I forgot to return from here. So let's make sure that we return that, let's refresh this page, or it actually already refreshed for us. And give me a second, there we go. So notice that when I go to / and I apologize about that, that I go directly to the homepage. I don't actually go to that test page that was here.
Managing Routes with URL Prefixes
The reason this is is because essentially whenever we register a blueprint, we look at this URL prefix, which in this case is blank, which means any URL we pass it to the blueprint, so into here, and we see if anything matches. So we say in this case we type /, we go to this blueprint, we see that / matches, so we immediately return and render this home.html.
Now, if / didn't exist in here, so if we get rid of that and we run this again, so let's go here. Now if I click enter on this, you see we get directed to test, and that's because we didn't have that / route in this specific file. So since it didn't find it in there, we went to here.
Now how can I make it so that we can actually reference / here, but we can also reference the / route over here, maybe using a little bit of a different URL? Well this is where things get a little bit interesting and this is where we can do the URL prefix. So essentially the URL prefix is what needs to come first for us to send something to that blueprint. So let's say this blueprint represented all of the admin functionality of our website. In this case, our URL prefix would be admin, and I guess we can do admin/ like that or /admin. And if we see /admin, what we'll do is we'll actually pass the rest of the URL to this second.py file and then go to this view based on that. So in this case what's gonna happen is if we type /admin and we don't type anything else, what we'll get is just go to this / page here, because the kind of extension after /admin was nothing, so we're gonna return home. And then if we go to /admin/home, we'll reference home here and we'll go to that page.
Demonstrating URL Prefix Behavior
Now to make this a bit more clear, I'm just gonna say def test() and we'll add a route here. So @second.route, let's just make this /test so that you guys understand how this works and let's just return in this case, we'll return some h1 tags and just say test like that.
Okay, so let's run this again and let me kind of show you an example so this makes a bit more sense. So why do we run this? By default now we go to test. That is because again, if we look here, we have / that's gonna go to test and we only go to this blueprint if we see /admin. So now watch what happens. I type /admin, you see that we rendered this homepage. Now why did that work? Well we have URL prefix of admin, so what we do is we pass whatever comes after /admin. So if we have like /admin/, that's what came after it, so we pass that here. We see that we have a / so we render the home template.
Now let's do a few more tests, I guess I'm gonna have to actually get rid of whatever I wrote here so this doesn't crash it. So let's do that and let's go to /admin/test and notice when we do that we get this test because again, we took that /test after admin, rendered the view. This is very useful, this makes it a lot cleaner so you don't have to type /admin/home, /admin/whatever in all of these blueprints, and that is kind of how that works.
Modularizing Blueprints into Packages
So now I'm going to show you how we can do this in a bit more advanced way with a different template folder and different static folders inside of kind of different directories and then we'll be done talking about blueprints. All right, so now I'm going to show you kind of a more advanced part of templates where what we can actually do is have a better structure in here where we kind of have mini apps inside of our main app. So to do this, I just want to quickly mention that I actually found this web page, you guys might have seen me pop it up before, that explains this really well, kind of how this project structure works, so I'll leave a link to this is kind of the way that I figured out how all of this works so I figured I'd give them a little bit of credit and put it in the description. So anyways, you guys can have a look at that, it explains it really well but I'm gonna go through kind of an example here because this web page doesn't really go through examples, it kind of just explains it on how we do this.
So what I actually want to do is put my second.py file in its own folder and it has its own static images and its own templates. Because realistically, if we can do that, then that means we can just take that folder and we can just put that into any Flask application and just use that as kind of like a little component of the app. For example, you know, logging in, admin, all that kind of stuff is some basic examples of what we might use that. So I'm going to start by just creating a new folder in here, and let's just start by calling this, I don't know, admin, so it has some admin functionality for our application.
Now what I'm gonna do is move this templates folder, move this static folder, and move the second.py file into admin. So to do that, this actually might take me a second. I think I can move this. Okay so we'll say admin/ perfect. That moved that. We'll do same one here so admin/ oops / and then we'll move this second.py, so last one, admin/. Awesome. So we moved those in here into this admin folder and we have this main.py file. So now how can I actually import the second file and have the blueprint work properly like it did before? Well all we actually need to do is add one file inside of our admin folder to create this as a Python package.
Importing from a Package & Conclusion
Now I'm not gonna explain how this works because it's kind of a whole new topic on its own but essentially creating an __init__.py file, just saving it and not putting anything in it inside of a folder, will actually make that folder a Python package. And what that allows you to do is reference the folder name to import modules from it. Now this might seem a bit confusing but from my main.py file, now I can't just import second because the thing is there's no second file in the same directory as this main.py file.
So how do I actually import that file? It's inside admin. Well to do that, all you do is admin.second import second and we don't have to change anything. This is just gonna work properly now. Now the reason this works is because when you create a Python package with this __init__.py, it allows you to reference the folder name and then that other folder. But if we didn't add this __init__.py in there, we'd be out of luck. This wouldn't work because we couldn't reference admin.second.
So anyways to prove to you guys I'm not making this up, I'll just actually run the app again. So you see if I go to /admin that works fine. When I go to /admin/test same thing, and then we can go back to the home page and we just get the big uppercase test. So that works properly, that's how you do that.
Then inside here now we have our own static and our own template folder. And if I wanted to create a new kind of like mini app that had its own blueprint again, well I can just create another new folder, in this case, we'll just call this like I don't know, other. And then inside here what I can do is the exact same thing I did here. So I can create another file, another __init__.py, templates, static. Just mention again like we have in second that our static folder is static, our template folder is templates. It will use the ones that are inside this interior directory so inside other, and then we can have different kind of templates and different static files for that. So that is how blueprints work. You can use as many blueprints as you want. All you need to do is just register them here and set their URL prefix, and that's pretty much all there is to it.
So with that being said, that has been it for blueprints. This will probably be the last technical video and we're actually gonna do a deploy next I think, and show how we can get this Flask application out onto the web so that anyone can access it. But with that being said, if you guys enjoyed, make sure you leave a like and I will see you guys in another video.