71 - HTMX Typeahead & Search in Django - Python & Django 3.2 Tutorial Series

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
now we're going to go ahead and implement an actual app that will handle our search feature and then we'll also be using htmx to actually perform the search itself so let's go jump into our project and python manage.py start app and we'll call it search in this case it's just simply search i am not necessarily going to put in models right now i'm really just going to be focusing on the views and so the main thing here is just defining a search view that takes in a request and we want to grab the query which if you remember back it's request.get.getofq and then i'm also going to add in something else in here but before i do anything further i'll go ahead and say if request.htmx then we're going to return render some sort of response here some sort of template with some sort of context that context in my case will just start off as just the query okay and then the other part is having a fallback if it's not a htmx request we still want to render something out of that same context cool so really these two things aren't that much different i have been using them over and over again which is repeating myself so really i actually can just do something more like this where we declare our default template in this case let's go ahead and do search and view.html and then we want to have our other template in here and this template would be search maybe we'll go ahead and do partials and results dot html so let's call this results as well cool and so now we'll just go ahead and return back that template like that of course in the request.htmx if i needed to change the context that's fine but realistically i just need to change the template and this is true for our other app as well all right so let's go ahead and now put this view into our primary urls as well as into our settings as far as the app is concerned so in here we'll go ahead and add in search using single quotes and then we'll go ahead and add in our url here so no longer do we need that search view i'm going to get rid of the article search view altogether and then just do from the search dot views i'm going to import search okay so i don't even think i even used the article views anymore none of them in fact so we can get rid of all of those imports there i am going to leave the search view here though and we'll come in and call this search and then simply search view and then we'll go ahead and give it a name of simply search okay so search is going to be available anywhere so in my template i already have a block for that form i don't want that anymore instead what i'm going to do is i'm going to make a folder for search and in here i'll go ahead and do my search form so search form.html and that's going to take place of what this is so i'll go ahead and cut this out paste it into my search form and now use include and it's going to be search and search form dot html there we go and our search form now is gonna go to the url of search okay so no big surprise here hopefully with a lot of these things so there's a couple of things i do need to implement in my search folder here i need to add in the partials folder and in there i want to go ahead and do results.html this of course would show me all of the results so really it's going to be for object in query set or object list depending on how we name it in our context variables i'll leave it in as that and i'll give it a list element of simply just object.name and we'll link that to ahref and it's going to be object dot get absolute url hopefully nothing surprising about these things right it's something we've already done several times and of course now outside of partials i'm going to go ahead and create the results let's call it results view actually so revo results view and then just simply results so of course in the results view we'll go ahead and extends base.html and then we'll go ahead and do our block content and and block and naturally we'll go ahead and include our search partials and results.html okay so far so good and our results here one other thing i want to do is add in a item for empty so if the query set is empty we'll go ahead and say no results found cool so now in our base.html we've got our html here our view we just needed to change the actual template that was being used for the primary template so that's results view now search results view okay so let's go into our home page and let's do a quick search and i'll just say hello world hit enter and i've got no results found cool so naturally there's no results found for several reasons the biggest one uh being that there is no query set so how are we going to go about doing this well there's several different ways on how we can consider doing this but i'm going to make it fairly simple on us first now one of the things that i want to do is in this input i'm going to go ahead and say value equals to request.get.q just like that what that does is at least gives me the previous value that i actually searched so it's actually in there i think that's actually a good idea to have next what i'm going to do is i'm going to use a select drop down so i'll go ahead and do select and type being equal to well the name actually being equal to type and the the options i want to have are simply the values of let's say article and it's going to be article this is really just the different model types i might end up using so article and recipes right so in the long run maybe i don't even use articles but in the short run this at least gives me some sort of value that i can drop down and select notice that type actually comes up in here and so what i want to do too is update which one of these is selected by default so it sort of pre-fills that value now the there are several ways on how to get around this and one of the things you might be wondering is why am i hard coding this form when i have django model forms the reason i'm hard coding this form is just to make it nice and easy on me to do some of these conditions so we totally could have it in other places but when i hard code it in this case i can still get that get call anywhere and then i can also render these things out so in other words this template does not rely on a view at all which is important because of how i'm actually using it right here okay so again the template does not rely on a view cool so going back into that search form um let's go ahead and do a couple things first off i'll go ahead and say if request.get.type is equal to article then we'll do something otherwise we'll do something else and what i'm doing here is i'm looking at the request method right and i'm looking for the type itself so perhaps it's going to be articles or article we can do either one it doesn't really matter but what does matter is when we actually use it so if the type is article then we'll just go ahead and say selected okay and so i'm just going to copy this exact same thing for recipes okay so recipe and we might actually want these to be plural because it is searching cool so now if i refresh in here it actually will show me the correct url and the ability to change what it is i'm searching in now of course i could also do something like all departments which is not something i'm going to select just yet right i will put it in here for an option but i'm not actually going to set it up just yet right so we've got all recipes and articles okay great so now we need the actual view to handle this but even before i put the view in something we could do potentially is well what do we want to do here now on this input type i could call the action of search i could use htmx to actually call it so i could use htmx get here of search as well or of course i can actually come down here and use search right and the reason i want to do it on the input is so that i can have that type ahead feature something we've already kind of seen and that was that hx trigger and that trigger actually went for key up when it changed and we delay however many seconds i'm going to actually delay it to 200 milliseconds and so the reason we want this on the input has to do with the fact that it's going to monitor the key up so every time i'm typing it's doing essentially a type ahead but what's hap what's not actually being included here is this select item so to include it i can actually come in here and say hx dash include and then i can either i can pass any sort of css selector here right to make things easy on me i'm just going to go ahead and say id equals to search dash type and i'll go ahead and use search type so now when i actually push this with a get it's going to also include this right here so we can test this out in our results we could say something like searched for request.get.q under request git and type and we can even say i think there's a title case let's try that out i'll explain that in a moment okay so it's refreshing here yeah so search for hello under article and maybe we do s articles that doesn't work for alls which is why i don't want all um also we're not gonna ever implement or not implement the method on how to handle all just yet so okay search for hello world under articles and now we search it for uh recipes so if i search again there we go okay so now let's go ahead and make sure we save everything and let's give it a shot so our view should have the htmx going through just like that and it should be able to return that based off of that template okay so let's go ahead and go back to our home page and now i'm going to type in let's say hello world and recipes okay hmm nothing seemed to happen well of course it didn't happen because one of the things that we didn't do in our search form is we actually don't have any element to push this to right we don't have a target so to do the target i'm going to go ahead and add a another div class above this form and right above the the form we're going to go ahead and say div id equals to type ahead results okay so now this search here hx target and yet again we can use a css selector in this case i'm using the id and it should go in there okay so we refresh now and i'll go ahead and do hello world and there we go it actually is giving me those exact same results now of course if i hit submit it still goes there if i hit enter here it should still also submit it which we would see with the refreshes there and our logs um so this is pretty cool so that's actually how the timepad works now of course i need to actually set in results in the view something i don't have yet but this actually is now working pretty well i think so let's go ahead and implement the actual search now before i do there is something i need to do in my models for the recipe itself and that is actually having a search feature so you may recall back to when i created search for articles i actually made this so we can copy all that i'm going to copy literally all of it now typically i don't love just copying and pasting things willy-nilly but this is something that is fairly fundamental to what we are doing and the reason i made it in this method was so we can reuse it so now we'll go ahead and put recipe manager recipe query set and we'll reuse that and now i'm going to go ahead and say objects equals to that okay and the really the only thing we should have to import is just q i did import literally everything but i think q would be the only one as far as i know for the import so i'll bring that q lookup right up here as well okay so now i should have the search method on this query set now the reason i did that is everything to do with the type so search type equals to request.get.get of type and now let's import the models we actually want to search so from articles.models import article from recipes.models import recipe okay and so what i want to do is i want to map what the search type is to what the model would be so search type mapping and in this case we're going to do recipe is equal to recipe recipes is equal to recipe and then the same thing for articles right and i should probably reverse these okay let's put these up here just like that okay so this search type mapping now what i want to do is give a default class i'll call it class with a capital k the default class i'll use is recipe now i'll say if search underscore type in this search type mapping dot keys then i'll just go ahead and set the class that capital k class equal to that search type from the search site mapping okay simple enough so now we've got this class in here so it's either going to be the article class or the recipe class and what do we know about these things well i can do query set of that class again replacing the actual variable that i used here with the actual model itself dot objects dot search query equals to that query and now in my context i can bring in the query set being equal to that qs i i definitely do not need query as a context variable any longer because that query is coming right from here so we've already seen it in our templates we've used it a few times now right here right here so we definitely don't need that as context the template can infer it itself so we save this and now we have a fairly robust search now assuming that we have the actual model manager set up correctly on every given model for performing a search in this case i do not have it set up correctly this should be instead of title it should be name content it should be most likely description right and i can add more lookups to this still like let's go ahead and put this in parentheses here and parentheses here and we can separate these out by lines so they're a little bit easier and more user-friendly to read definitely make sure it has a pipe except for the very last lookup okay so now we have at least a little bit better of a lookup that's more specific to recipe one of the things that we should notice is in my search results i used object.name of course the the actual articles don't have a field called name now you may or may not remember this it's okay if you don't but they do have the git absolute url method so since they don't have one name they have one for title i can actually come in here and just say property and do define name and that's going to return self.title now i think i actually use these things interchangeably too often it'd probably be better that i use one or the other all the time but sometimes that's not practical but since i actually changed this on article what i'm going to do in my recipe is the exact same thing but for title so just reversing it just to ensure that if i accidentally didn't change any of these lookups they it would still work now that also might be true for description and content but i just think title is like kind of the key one here because these are the two that i'm actually going to use in my search results okay so let now let's actually see if it all works assuming the server is still running it is let's go ahead and take a look i'm going to actually go to my home page this time i'm going to go ahead and search a taco and i want to search in recipes now notice that it actually did not trigger that again right so it's definitely not triggering it one more time so how do we solve that well going back into our search form it shouldn't be that surprising that it's actually using these same triggers right here but this time instead of including the search type what we want to do is include the search query okay so we save that everything else is the same let's refresh on our home page with nothing in there and i'll go ahead and say taco no tacos under articles hit recipes uh oh recipes didn't do anything so of course it doesn't necessarily work perfectly in the type of head in this case so i'll go ahead and submit it again and of course i now have those things showing up and it does change the location as to where things are the submit button is still there which i think is nice but of course there's a number of things that i might consider changing such as remembering which type that i end up using any given time so if i search taco again this time now i've got here so this actually makes sense to where we might reverse the order of the drop down and just altogether get rid of this right so again it's not necessarily a perfect method and there definitely is a way to make this all work with htmx but it's just something i'm just not going to get into right now but really we refresh in here go into recipes search a recipe there's all of our recipes it's in the type ahead so we didn't change our url at all it's literally right here so i can click on one and what do you know pretty pretty cool so this also might ring a bell of like hey maybe i actually don't want to have the entire query set coming back in my hdmx request maybe i only want a few items in there so in that case we would actually come in and say context of that query set equals to the qs and then we can slice it up to let's say five results and so that means that it will only give me five results back instead of everything which i think is also really cool because then if we only have five results we can also change the context that's coming through for our rendered template here to say hey view all in other words let's go ahead and say context say you know htmlx hmm wait a minute i'm putting context as hdmx.request.htmatch what about request.git i used all that stuff now the next question would be if you're following my line of thinking here in results can we see if request.htmx and if so can we actually use these for that search so now i'll go ahead and say ahref equals to well search and then the q equaling to this and then the type equaling to this and view all okay so we're refreshing here let's go ahead and go to our homepage we'll go recipes taco hey what do you know it says view all i click on it hey it takes me over to that search and it has those other items pretty cool now if i do that search again i mean i'm already on that search page so it's not necessarily showing me that but i think i think it's like this is hdmx this is what's really really cool now one of the things that i haven't talked about a whole lot i don't think is these pipes and this right here that's called a template filter so there's a bunch of them inside of django where you can maybe uppercase something right or you could lowercase something which in this case it is already lower case and there's many many other things that you could add to this so feel free to look at the django template tag filters using a pipe like that but this one right here is very similar to python's if you use like my string in python it did title that's actually what happens here and what's cool too is you can actually make those custom ones yourself it's not something we need just yet but that is actually a fairly robust search feature i would argue now there are still a lot of downsides to it and that is how we do this search type mapping thing what would be better is just to have one query and have it search everything that is computationally possible but it's it's a lot more challenging to implement this i think is just like really simple to implement but now we have a way to let the users decide what they're searching the other part about this is what are users searching most right so one of the things you might consider is actually making a model for search to monitor both the query and the search type like they're intentionally looking at articles more or they're intentionally looking at recipes more so what you would end up doing is maybe changing the default values for this or you would actually you know decide to spend more times creating articles or articles that help them with recipes i mean it could just tell you a lot about what people are looking for to improve your overall search altogether so yeah it might be a good idea to save that [Music] you
Info
Channel: CodingEntrepreneurs
Views: 1,392
Rating: undefined out of 5
Keywords: install django with pip, virtualenv, web application development, installing django on mac, pip, django, beginners tutorial, install python, python3.8, python django, web frameworks, windows python, mac python, install python mac, virtual environments, beginner python, python tutorial, djangocfe2021, digitalocean, production, python, django3.2, web apps, modern software development, trydjango2021
Id: ggo4Vt1lbgA
Channel Id: undefined
Length: 25min 16sec (1516 seconds)
Published: Sat Aug 14 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.