FastAPI Python framework - Returning HTML templates (with HTMX integration)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi there in this video we're going to look at fast api and how to integrate that with templates and with htmx we're going to look at the click to load pattern and we're going to see how to set up ginger to templates using fast api now fast api is a high performance web framework for building apis in python but it can also support traditional template-based web development and in this video we're going to look at how to set that up so let's dive into the code i've got vs code open here and we have a requirements.txt file now what you want to do is install these three requirements pip install dash r and then requirements.txt and ideally you'll do that in a virtual environment and that'll install these three packages here now obviously we're going to use fast api but we're also going to use jinja 2 for our templates and also uvicon which is a very fast asynchronous server so what we're going to do here is because we're going to use templates with fast api we're going to create a templates directory within this project now this is just a folder that has a main.pi and a requirements.txt file we'll create a templates directory and within that we can create an index.html and to this template we can add some boilerplate html5 code this is an emit abbreviation and it's available in vs code once you've done that we can change this title to anything we want for example fast api demo and finally to the body we're going to add hello world for now and we'll change this later when we're wiring up hdmx next i'd like to go to a page on fast api's documentation this is the page for templates and you can find it under the advanced user guides down here it's called templates and this will tell you how to set up jinja 2 with fast api and fast api actually supports any template engine that you want to use now arguably ginger 2 is the most common you'll see that frequently used with flask which is another very good web framework in python so we're going to go with ginger 2 in this video and we've already installed it so we don't need to run this command so let's copy the imports into our main.pi file that we've defined and that'll go at the top and we can remove the static files line we don't need that now we've imported this fast api object that's the central object and this library so we can instantiate an app object using the fast api object there and that will create the app object from which we can create roots in our application going back to the documentation after the app has been created we can set this templates variable up and this points to a ginger to templates instance which we've imported from the fast api dot templating module so let's copy this here and we'll paste that below the app that we've got there and the directory that we're setting up here is passed as an argument and it matches the templates directory that we've got in our directory here so let's now set up a fast api route and it's going to be an app.get request and then the first argument to that is the path which we will say is just index and the app.getdecorator takes a second argument for the response class which we're going to set equal to the html response and that was imported here from fast api dot responses and the html response is how you specify that you're returning an html template as said before fast api is often returning json data in this case we specify that the response class is an html response so that's all we need for the decorator now we can set up the function which we'll call index and we'll pass the request into this function which is going to be an instance of the request that we've imported from fast api and you should note in the documentation that you have to pass the request as part of the key value pairs when you do the template response therefore you also have to have it in the path that's why we have it here as an argument to this function so we have that and then what we can do is we can copy this here and we're going to return a template response so that's the function there and it's going to return a templates dot template response the first argument to that is going to be the name of the template which is index.html we created that here and the second argument is going to be a context which we're going to set up now so above that let's set up a context dictionary here and i'm going to pass the request in here and that's going to be an instance of this request that we get as an argument and that should be all we need for this function so let's now see how to run the server and see this template in action now we saw in the requirements file that we have uvicon installed as a dependency and we're going to use that to start a server here so the command is uvicorn and we specify the name of the file which is main and then the name of the app object which in this case is called app so main app and then we'll also say reload which will allow us to reload when there's any changes to the application so once that's done we can then go to localhost 8000 and you can see we get a detail not found here and that's because we haven't got the right route here we need to go to the index route so let's copy that and we'll say slash index and we're still getting that this is not found so let's go back to our root here i think we need to slash the start of this root so it's going to be slash index and if we refresh now we get hello world which is what we have in a paragraph tag within our index.html file so what we're going to do now is we're going to add htmx and tailwind css to this project we're going to do that within the head tag of our template below the title we can paste these two lines and i'll link to the cdn's in the description of this video the first one is htmx and the second one is tailwind css and we're going to use tailwind to apply some basic styles to a table that we're going to create in a second so let's firstly test that tailwind is actually working by adding some tailwind classes to this paragraph tag let's give it some padding we'll give it padding of six and we can also give it a background color of red and that is followed by a number in this case we'll use 500 here and that'll give us a particular shade of red and if we save that and refresh the page we should now see that we have hello world and there's a lot more padding applied to this as well as that red background that you can see so this is all working tailwind is working and we've also loaded htmx so what we're now going to do is create a table and display some data in that table so i'm going to remove the paragraph tag and i'm going to paste some code here and we'll go through this code very quickly within the body we set up a div with some margin on the x-axis and then we have the paragraph tag that has some text saying movie list within it and this has some additional tailwind classes we're making this text very large it's two times extra large here we're also making the font bold and we're giving it some margin bottom below that we create a table and we apply this particular tailwind class to say that the table has to be at least half the size of the page and then we also apply some margin bottom to that now this table has two columns one for the film's name and we're going to work with movies here and another column for the director and we've had coded a table row here a single table row with a single film now soon we're going to replace this with some data from the server but we'll leave it here for now and below the table we have a button and that will allow us to load more and this is the click to load pattern and it's going to allow us to load more data into this table whenever we click the button so let's see how this looks on the front end if we refresh this page we now have this very basic table again the styles are minimal we aren't focusing too much on the styling we're just looking at the table here and when we click this button we want to load more data into the table so the next step is to return some data to this page from our fast api function so let's go back to the main.pi file and within the index function here we're now going to create some hard coded data i'm going to paste that in here and it's going to be called films and it's going to have three movies within that list and then we can add that to the context here with a key of films and that should then be available to us in our template so let's go back to the index.html and we can replace this table row with a ginger two for loop and it's very similar to how it's done in django we're going to say for film and films and then we close the for loop here with end four and what we had before were these two table data elements so i'm going to bring them back and we can replace the hard coded names with the referencing the actual film itself so film.name and then below that we can copy this and we can then replace ridley scott with the films director now these are keys that are available in the data you can see that here there's a name key and a director key so we can reference these within this variable here and it should hopefully display on the page so if we refresh this page we now get this very ugly looking table something's gone wrong here so let's go back to the template and we're not creating a table row for each film so let's do that now every film should be enclosed by a table row close that tr tag and we should now be able to see this in proper rows and we get that now so we have data that's coming from our fast api function we're now going to set up htmx to dynamically load more data into this table and to do that we need to add htmx attributes to this button so let's go back to the template here and down to the button and we're going to create an hx get attribute and we're going to point that at our index endpoint that we created and the main.pi file so every time htmlx sends the get request it's going to hit this function here and it's going to generate these films and return this particular html template now this isn't going to work perfectly we're going to change things a little bit soon but for now let's see what happens so make sure we've saved the index.html and we can refresh the page and when we hit load more we get this effect here it's loading another table within the button now we don't want a table embedded in a button that's arguably not the best user experience so let's change that up by telling hdmx where to swap the content and using the hx target and the hx swap attributes so back to the button we're going to add a target here it's going to be hx target equal to the table body so i'm going to set an id of table body here and to the table body we're going to give that the same id here so table body so now when we get the html back from the server for the index.html page it's going to swap the content into the table body so let's see what happens now if we refresh the page and load more we now get this weird effect instead we need to set the hx swap attribute and the reason for this is because the html is being swapped into the body of this table but remember we're returning this whole page here at the moment so that's all being swapped into the table body so what we're going to do to address this is create a partial template here and we're going to extract this for loop into the partial so let's call this table.html table.html and we can paste the for loop in here so when htmx sends a request to get more data we want to return this template rather than the entire index.html so if we save this what we can now do is use the include statement here so similar to django we include the table.html here let's see how it looks at the beginning here does it load properly it does so that's all working fine we want to make sure that that returns the table.html if it's an htmx request that we're dealing with so how do we detect if it's an htmlx request to find that out we can go to htmlx's documentation and in the requests and responses section you can see that there is a header that's included in the requests that htmx sends it's the hx request header and that will always be set to true when htmlx is performing a request so we can look for that header and if it exists we know it's an htmx request now to get the header and fast api we can go to their documentation and what you can do is you can import the header object from fast api so let's do that just now at the top we'll add that to our import and after that we can accept any headers as arguments here and we give it the name that we need to in this case we've got user agent and that's an optional string that is set to this header object so let's paste in ours here we're going to add it to the index as an argument and we'll change user agent to hx request in this case and we need to import the optional construct from typing so from typing import optional so now that we've got that let's quickly explain why that works if we look at the fast api documentation on the headers page there's a section for automatic conversion you can see that fast api does some automatic conversion of headers for you so for example it will convert the underscores and your parameter to hyphens so in our case what that will do is it will take hx underscore request and it will change that to hx dash request and that's what htmlx's documentation has here it's hx dash request and fast api will also make sure that the case doesn't matter so for example we've got all lowercase here this is the typical way to declare a python variable or an argument but this will successfully pick up the hx dash request parameter here and that's because fast api handles this for us and you can read about that here http headers are case insensitive um so you can use these lowercase versions even if the actual header has some uppercase characters so now that we've done that let's go back to the code and we can check whether this hx request is none remember is optional so it could be none and if it is none we know it's not an htm x request however if it's defined then we know it is an hdmx request so we can use an if statement here fhx request and if it is an htmx request we'll return a different template so we'll use the template response class and we'll specify table.html with our context so if we save that and go back to our frontend we should now see that nothing actually happens at all when we click this button now there's one final change we need to make in this tutorial we need to change the way that the content is being swapped into the table body so if we go back to index.html here currently our target is the entire body of this table here so when we get a response with our films this particular partial template is loaded with all of the films and then that's swapped into the table body but that replaces what's already in the body what we want to do is append to the end of the table with new rows for the new data so there is an hx swap attribute in htmlx that we can use for this so hx swap and the particular method is before end we want to before the end of the table body we want to swap in these new rows of data so with that one change we should be able to refresh the page and when we hit the load more button we get another three movies coming up here and it will keep adding these new rows to the table now obviously this isn't particularly smart we have in our main.pi a hard-coded list of films in real life you would fetch this data typically from a database and it would not just be a hard-coded list in the next video we'll explore how to set up a database with fast api and return that data using sql alchemy but for now this is all working so let's quickly walk through what's going on one more time we have within our index.html a button here that has some hdmx attributes when clicked this button will send a get request to the index endpoint and it will swap the response into the table body before the end of the table if we look at htmlx's documentation for before end at the swapping section here you can see that before end will append the content after the last child in the target so when we return new rows of data from our partial that is retrieved by htmx it's new table rows that will then be swapped in after the last child of the target so the target is the table body the last child will be the last table row within that body and htm x will then swap the new data as new rows after that and the new data is fetched from our fast api function here with some hard-coded films that we're returning in the context and we've seen how easy it is to set up templates with fast api we simply instantiate a ginger to templates object we pass the directory that contains our templates and then we can use the template response and our fast api functions to return that html response so that's all for this video we've explored how to set up templates and htmx with fast api and we've seen a little bit about tailwind css as well although we haven't gone into much detail about that in the next video we'll look at database integration and setting up sql alchemy with our fast api project until then thank you for watching if you've enjoyed this video please like and subscribe to the channel and we'll see you in the next video
Info
Channel: BugBytes
Views: 43,394
Rating: undefined out of 5
Keywords:
Id: yu0TbJ2BQso
Channel Id: undefined
Length: 17min 36sec (1056 seconds)
Published: Fri Feb 04 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.