speaker 1: Everyone, everyone full from lunch, ready to learn about some Jango forms, modern Jango forms. That's right. I'm wake you up after you want to go from, go to sleep with a nap. Like I said, like you said, my name is Josh. I'm the senior web developer at the westvilt company. I've been a web developer, a professional web developer for about four and a half years. So not too long, long enough. Like I said, I work at the Westervelt company. We're a lumber Land Company. We own a bunch of timberlands, own we own land and try to use it in a responsible way. And Jango is a big part of that. We have a lease application that manages our hunting leases, among many other things that there are links. We have our main website and then our GitHub profile, where we actually have a bunch of open source Jango libraries, mainly for my sake, so I don't have to keep on rewriting things over and over again, but hopefully maybe something y'all will find useful. Okay. So what are forms? What are forms? That's what we're going to talk about today. Well, as far as html is concerned, in the web, there one of only two elements that actually kind of can interact with a server built into the platform. The other one being an anchor tag. Forms are the only ones that actually take user input and allow a server to respond. So what are forms? But what are forms in Jango? Well, they're primarily a data sanitation and validation and presentation layer. They kind of play a dual role, and it's kind of why they're so complicated. They take user input, sanitize it, make sure it's safe to store or it matches certain validation rules, and then also presents the form to the users for them to interact with. First question is, how long have forms been in jangos? Anyone know? I know some old gravers down here now. Well, the answer is pretty much since the beginning. I went back and found it's the second public commit on the GitHub repo made by Adrienne. There's the link, the actual link to the commit, and then the permalink to the Jango core form fields. That's what they were called then. This is the only public link I could find of them. Before that, it was in a svn repository. I think I was talking with Jacob Kat lamoss, and he said, pretty much since the beginning, forms have been in Jango because they're such an important part of the web. Here's a few kind of notable changes to Jango forms over the years. And I just kind of combed the release notes in 0.95. That's kind of the first available release on GitHub. Forms were included in 2000 62007, something called Jango new forms, which is actually the Jango forms we know today. Pretty much 16 added geojango form widgets. 107 was a big form validation release. Form add error was added then, and just a bunch of validation stuff in that one. 1:11 in 2017 added template based widget rendering. And then there was kind of a wide gap between major features to the form library up until 2020 14.0, when we got actually template based form rendering. So previously it was just widgets in fort auto. The entire form library was rendered by jgo temple language. It also introduced the form render class that was responsible for that. 4.1 brought the div based form templates as well as being able to customize your form template name. You form your default template on your form render, and then a 5.0 aspfield group, which we'll get into later. I put on my data science hat to do this. This is kind of an account of the commits over the years since 2005 up to this year, kind of showing you the different modules, main modules. We got contrib admin, we got off th sessions. Core dv is in there. And the forms is kind of right there in the middle. You can kind of see it. It's never been the most popular thing to contribute to, but it's kind of just always been there and just kind of always in the background. You can also see, I know of these, it's hard to read. There's new forms and old forms are down there as well as a reference to where they came from. Okay. So what parts make up jinga forms? Well, these are kind of the core bits we got. You know the form is kind of the central piece of the puzzle. It's responsible for your validation and you're rendering of just all the fields on the form. Your form set is just multiple form instances. And is it a pain to deal with, which I will not be going into? Fields are forms, but just on a single field level. They're responsible for validation and rendering of a single field. The widget is the thing that actually renders the input to the users. Your bfield is a combination of field and data, and that's either the user created data, user suppdata, or the initial data that you give it when you instantiate it. And then there's also erlist and air dict and those just kind of handle all the errors in your form and associate it field with the errors that go along with it. And to me, when I was learning Jango, this kind of all seemed like a humongous puzzle. It doesn't seem like a lot, but how they fit together in the different layers can make you kind of feel like this when you're going through. And it I feel like that, and I've been preparing for this talk for a while. I still feel like that because forms are complicated. So the form library is kind of complicated, but it's complicated to hopefully save us time when we're building our Jango apps. Okay, so now we're going to go through and talk about a little bit about leveling up your Jana forms with a couple modern additions, new additions. We're going to go through four levels. First up, this is an easy one. Use the platform. Use the platform that we all use, the web platform. What does this mean? Of course, it's all the input types that we kind of just get out of the box with. Html, your type number, email, url and password, those are kind of some of the most common ones. And you know how that looks is everyone knows this. You have a number filled. You can't. I'm typing in letters. It's not letting me. No JavaScript, no nothing. We'll let me do numbers. Send your email itvalidate that it's a valid, valid email url. Same thing. And a password will mask. So jump from counting. Can't spy on your password. And how this looks, of course, in jangos is pretty simple. We have our form widgets and there's a number input, email input, url input, password input. And if you use model forms, they come out by default with integer field. You do have to specify localize equals false, otherwise it renders to a text input. But if you specify that, then you get a number input just provided by the library. There's also a handful of less commonly used or less commonly known. I feel like I rarely see these. Your color, your search and your your telephone input types and how you would use them in Jango is similar what to how you would define a custom widget. And that is inheriting from widgets that input and specifying the different inpetites for color, for cerx, for tell. And this, Interestingly, this stuff is coming in the next release, I believe Jango 52. I think I copied this directly from main ine when I was creating these slides, but you can use these today. And how they look is like this. You get a color input with a nice y gamut of all the different colors that you can choose, and it's platform specific. So if I pulled this up on my phone, it would render the actual iOS color input same for search and for tell, itbring up the number pad and a list of local numbers that you're using. There's also date input types. Those are a little bit trickier because in html they have no time zone data. Well, we have to handle times on data, otherwise we get those weird bugs. There are a handful of track tickets on the Jango ticket tracker discussing this, and it's been brought brought up that maybe Jango should have this built in to the form library. I don't know if that's ever gonna to happen. I mean, it's you got to handle the time zone somehow, but if you wanted to do it yourself, this is how you would do it. And then you get through a nice little date. Picwithout, any JavaScript that's going to be a theme. I threw this in that the last minute has I don't does anybody know the css property? Has it was just it's kind of been around for a little bit, but it's been broadly available this year. Has anyone familiar with it, used it? Yeah has this great. I'm not going to go into any detail beyond acknowledging the potential of it, especially within the Jango forms library where you perhaps want to act on a custom widget that you don't want to copy that custom widget template into your own project because then you've got to maintain it. You've got to think about it later on when a library updates it, you got to update it yourself. Has allows you to style a parent element based on child elements, attributes, anything, state data attributes. So I've just begun to play what has and I encourage you to as well. So that's use the platform that's level one. Level two is the Ashfield group introduced in Jango five zero. And that allows you to define custom templates for your Jango fields. You can do it a couple different ways. You can do it as a attribute, sorry, a past, then attribute a fast end variable to when you instantiate, define your Jango field template name. You can also do it at the request level and have it render a different template. You can also do it at the form renderer level and have a global custom field template to rule them all. And then then your form template, you have to adjust it a little bit. You have to call your form field as field group, but that's all you got to do. And then depending on how you define that template name, the template just works. So that's field as field group. Next up, form render. And it's well, it's what as field group is for forms. And it's defined very similar. You can define a custom template name on a form, on a request, and at the template level, or excuse me, the form render level, you can also set a global forrender to a custom one. I would generally not advise this. That's this is the way I did it at the beginning of the year. And you can ask Jeff triplet. He has had many headaches because of that decision. This is a big hammer, and you should wield it responsibly. If you changed something in this template, it's going to apply to not only any form that your application is using, it's going to apply to any third party that's relying on the form template library, or excuse me, the form rendering library. I made a change to add a required asterisk, red asterisk, to help my users out. And I started seeing red asterisk everywhere in the delutoolbar and the admin. Everything uses this. If you do this, use it responsibly so as form renderer. Next up, the last one is maybe don't use Jango forms, and I'm obviously being a little facetious there, maybe don't use Jango forms only. And this is probably a pretty common practice. We have a bunch of awesome third party libraries. Jango crispy forms, obviously is the most popular one. There's Jango widget tweaks is probably equally as popular. There's an interesting one that I've been wanting to play with, Jango form set. It is kind of a rethink of the Jango temple library and does it in its own way. And it allows for grouped fields and group form sets. Super interesting. There's also some template based component libraries. Carlton's jgo template partials is great, and you're going to see some later. I know jgo components and slippers are both two very popular template rendering libraries. I wanted to bring attention to Jango cotton. That's kind of a brand new one as of, I believe, nine months ago. It kind of reimagines what Jango templates can look like. Instead of using your curly braces and your percent signs and your typical Jango template goodies, you instead use that anaccotton dot or excuse me, cotton slash input html in there, you use all your familiar Django template variables and control it's and then in your actual template, use this kind of funny syntax that kind of makes it look like a custom form or, excuse me, custom web element sedash input. You can have slots, default variables like the type text or a leading icon or trailing icon. And so you end up kind of getting a nice little form input right down there with the leading icon. Okay. So those are the four levels. Use the platform, use the inputs, use css. Css is great and it's getting better every day. The field is field group. We got our form renderer. And then you know all the additional third party application, third party libraries provided by the Jango ecosystem. Okay, so let's go ahead and build something with all this kind of knowledge that we've just gained. I'll show you what we're going to build. We're going to build a password reset form, deceptively complicated. So we're going to have a current password, obviously, we're going to have a new password with a validation. And then we're also going to have a toggle for to display change between type password and type text. And so how that looks, you know, everyone's seen this. Everyone's seen a password reset form, except this one has inline validation using htmx. If I do this, I got one, two, three. That's a numeric password. I go away. Validates against my password validation rules in my Jango project. Yeah. So that's what's going to look like at the end. It's got fill required as well. No refreshing, no JavaScript, minus a handful of libraries. I do want to add a disclaimer. I built like 90% of this, and then I realized it has a humongous security bug, which I'm sure someone will point out to me and make fun of me later. So don't use this, please. This is just an illustrative purpose. Kind of give you an idea of the different apis that are now available to the forms library. Form library was pretty static for a while. And then within the past year, there's got a new life. There are new apis, new new goodies to play with. And also say like the reason for the title le of the stock is this is an opinionated guide. This is just one way to build a form like this. It's not necessarily one I would agree with in four months. Like I said, these apis and these techniques are kind of new ish. And we're just trying to feel our way out, find the right abstractions, find the right patterns. Okay, so let's get started. We need our current password, new password one, new password two. We're just going to start out with charfields, define the form, use the generic form view, create our template. Boom, we're done right. Zip. We got a password reset, except, like I said, Jim from accounting comes across, and he's going to capture your password. So let's go ahead and use the platform, use those custom widgets, forms that password input thatI'll, set that input type to type password. And then Jim doesn't know anything. Okay, except it's you know it's kind of looking on the plane with jazz it up. People like to use nice looking inputs and forms. So let's jazz it up a little bit. Let's move our let's create a custom custom password feel and go in and hear it that or add the forms that password input widget as our custom widget and then we'll go and say if we don't PaaS in a template name when instantiating the field and set a default one, this kind of allows us to adjust it later if we like. And then that custom widget template kind of looks like this standard Jango widget template. And we got our field label with some nice little tailwind css. We got our field harors. We got our actual field in the help text. Everyone knows this. So then we change our char fields to our custom password field, and then we're going to go ahead and add some nice different tiwind styles to the input, make it look nice given it a nice placeholder, a nice border, when it's highlighted, when it's focused, excuse me. Now we're going to go ahead and adjust our submit button as well, make it look nice as well. Now this this is a form. This is what I'm talking about. Now this I can use every day except, let's see, except I don't really like new password one, new password two. That didn't make sense. Those form fields go together. They're they're kind of a form group. That's I just it just I doesn't run b me, right? So we're going to change that. We're going go and set the labels to be default as blank strings, get rid of them, throw them out of here. And then we're going to call our as field group, we're going to go ahead and keep the current password saying that one's fine for now. And then we're also then we're going to create a new field set with a legend of new password, and that's going to be the label. And then we're gonna to use grid and do our new password 12 as field group. And now look group together. This looks nice. This looks nice. Usable, logical. It makes sense that they're together, except I don't remember what I just typed now. Is that my current password? I don't remember. Wouldn't it be nice if I had like a toggle to go between nice little eye icon to make sure I knew that I was typing the right password? So we'll change our template, our widget template, to a custom widget template at password input. Then this one starts to go out here. Ry, I hope you guys can follow along. I'm going do my best to explain it. We're using alpine alpine js. It's a nice little simple JavaScript library for adding attributes to an html element that give it the nice interactivity that we all like with modern applications. And you get to brag that you don't actually write any JavaScript, you just run a library. And so we're going to start by setting the outside container with an x data of hidden it equals. And so that means if it's hidden, it's a password input. It's not hidden, we're just going to change it to a text input and make sure we can actually see it so we can make sure we typed in the right password. So we'll go down and we'll actually show the actual input. We're gonna to do a bind is what an alpine speak is, what you call that cone. We're going to bthe type to the hidden variable that we just set right here. So if it's hidden, we're going to set the input type as password. Otherwise, if it's not hidden, we're going to change it to text. And I believe those classes have not changed. So we'll move on. And then we're going to add our button button on the edge. And we're going to say, when we click it, we're going to toggle between the two different states. Hidden. We're not hidden. We're going to use Adam Johnson's excellent heroic con's template library, or excuse me, icon library. And depending on whether it's hidden or not, we're going to show an eye with a slash, do it or just the open eye. And that x shows is doing that right there. And so that's kind of how it all looks put together. Yeah. So how are we doing? How are we doing? Yeah, I'm liking this. This is feeling pretty good. I'm feeling like I can really change my password a lot of times. Now that was a little scary. Now we're going to really get to the hairy parts and I'm going to lean on loop plants. Excellent Django html patterns repository. Not only talking about forms, but it's got a bunch of patterns that we can use in our Jango applications when using htmx. And this, what I'm about to show you is kind of inspired by his there's a form validation documentation in there. It's kind of inspired by that. Well, first up, we need to pop that those field groups out as a template partial because we're going to do some inline validation. So we're going to load our Jango template partials. We're going to define the field partial up there. And if you've never used hdmx, this is a lot of variables or a lot of attributes. Excuse me, but it's pretty easy to follow. Like the hx get just means we're going to issue a get to the current url. When this is triggered, we're going to PaaS in the field name as the validate field in the request. We're going to make sure to trigger it from a custom event password blur, which we'll get to in the next slide. And we're going to save the password blur event from the container of the widget container, excuse me, we're going to include the entire input. We're going to target this specific field partial template, and then we're going to use the morphdom Jango, or excuse me, morph dom htmx extension because it handles since we're using inputs and we're going to have focus states, the morphdom library, the morphdom htmx and excuse me, handles that focus state pretty good, pretty well. Okay. So then down in our form, we just kind of swap the aspfield group and use the Jango, excuse me, the Jango temple partijango partipartial templates that we just defined using those field. And then here's where it gets a little scary. Previously we just had hidden because we have an input with a text input in a button that's gonna to toggle between password and text. Well, we got to figure out how to handle it. We couldn't just use if the input, the text input loses focus because then when we tab to the hidden button, it would validate and lose our focus and throw the user off. So we're going to handle that somehow. So we're going to set a new variable has focus, we're to set it to false. And then we're going to have a handler that basically says, if we lose focus, trigger dispatch this custom event, password blur. And then on the two inputs, excuse me, the input and the button, we're going to do the Exxon event. And we're going to say, if we focus on the input or the button, it's and if we blur or we go away from the input, we're going to set the focus as false. And then on the next tick, the next rendering cycle, we're going to go ahead and call that handler. And if both fire inputs or excuse me, if our input and our button have both lost focus, then we'll just trigger that dispatch, that event. We do need to adjust our fit or form view though. As a reminder, this is what it looked like. Very simple. It's about to get more complicated. We're gonna to override the get method and we're gonna to check if the request has is an hdmx request using Adam Johnson's Jango htmx package. We're also going to check for the get request for that validate field variable that we set in the request. And if we have both those things, we know we're trying to validate that specific input. So we're going to PaaS it into the form class. We're going to check if it's valid, and then we're going to get the bound field from the form data form clean data, and then we're going to render the form using a custom template with the paral, using the fragment, the hash, the number sign. And we're going to target that template partial that we defined earlier, the fill partial. I know that's a lot to follow, especially in talk slibut. Basically, it just means that if I focus on this, it's fine, but if I go away, field is required doing that inline validation, but if I type something, go away, it says it's valid. And if I go away like that, kind of just go around, pop around it and just kind of just works until the hairy to get there, but it just kind of works and still know lines of JavaScript that we have written personally. Okay. So that's that was kind of the hard part and now we're going to kind of spice it up a little bit or put some sugar on top. Let's check if the current password that is given to us matches what the user's password is. Since this is a talk demo, I'm just going of hard coat it to dcuus 2024 just so we can prove that it works. And that's all it takes is just on the form overriding the clean current password method. If it doesn't match, we'll return a validation or raise a validation error. And now if I don't type, you know, you can see not ddc us 2024 does not match current password. That's just what we want. But if I type in light 24, we're all good. We're all good. Okay. I believe this is the last step. You know I'm like king, where we're going so far. However, on the new password as a user, I don't know what expectations we have. So let's add some help text as well. So we're gonna to put import from Jango, control off the password validation module, and then set the help text to the password validators, help text html, and then also throw a new clean method for a new password, grab it from the clean data and PaaS it through the password validation. And so now, now as great as a user, I know exactly what to expect except do so if I do, a single number comes back with my validation in line. I think that is it. Yep. So I'm going to stop there, mainly because I ran out of time. But there are plenty of ways we can just keep on iterating on this. Like instead of the help text, excuse me, instead of the validation text being on the top, we could try to swap the help text in place. And so you know exactly which ones you have yet to do. You can add a progress more to see how long it is, how close to eight characters you are, kind of the mine reels. And so that's it. That's a. I think I went a little too fast. I was excited. I'm excited. This stuff gets me excited. Yeah, that's kind of it. I can make more slides. It's like y'all want to sit there and watch that. So the talk slides will be on my personal website later today. I was busy building those forms to do that so that qr code actually doesn't even work. But itbe there. Josh Thomas, Dev slash talks. You can find me on the different places. There's my personal website. I'm also on GitHub, and I have a mastoon, and I'm also on blue sky. I'm giving it a try. So that's it. How long it . speaker 2: took you to find the comet . speaker 1: in their life? Probably 20, 30 minutes. Like I can even remember, I started by clicking back a couple times in the GitHub and that didn't work. And I think I wrote a little small little script and using git and just find the oldest commit on here. The first commit is actually documentation. The actual code comes from the second public commit. New. Yeah all right. This one comes . speaker 2: from an online attendee says, I'm curious, Josh, in your example you were building a form from scratch. Was that for demo purposes? Or if you run into trouble integrating these techniques into your the Jango prebuilt form classes in the past. speaker 1: I mean it mainly for the top purposes, for demonstration purposes. Kind of show you beginning to end. You wouldn't do all those kind of steps. You know, I don't do all those steps, but I was trying to do my best to show the as field groove, being able to customize the rendering kind of throughout it. Like, no, you're not going to use that for every single form, every single application, but it's there and it's not too bad. It's getting better. It's getting better every release. Thank you very much. You mentioned libraries by Adam Johnson plant. So it sounds like you have at your disposal toolbox of . speaker 2: different components. speaker 1: What was the experience of integrating them as they unified pieces of software seem to think in the same way. Well, that's a good question. I mean, it just depends on what layer in the application they're kind of working with. Jango template partials and Jango cotton, for example, both use custom template loaders. So getting that integrated together, getting in the right order. Luckily, both libraries are very excellent and they have good maintainers and they have good escape patches like they offer automatic setup of the template loaders freeease of use, but also have escape haches for manually setting all that up. So it kind of just depends on you know like those are two specific template loader libraries, but if you're using like Jango htmx and Jango cotton, or Jango tempartials, or Jango widget tweaks, like those are taking care of two different things. So I I've yet to run into major issues. Just kind of depends depends. You didn't have problems with them fighting with each other at any point. So no, not really, really good experience. Yeah. I mean, it was it was a pretty painless, pretty seamless, hopefully a nice user experience as well. speaker 2: So my question comes from the use of regular or just custom style sheets. Say you want to venture away from css frameworks. What would you actually recommend to implement something like that? You know, would you use your typical mop or like a different package? Or would you just use raw Jango? speaker 1: You so let me repeat the question bags just so I make I understand you're not talking about you're talking about moving away from css entirely or using . speaker 2: a I'm just talking about not using something like bootstrap or toewind and using purely css and implementing your own. speaker 1: I'm like a person to ask. I'm deep on tailwind. I love tailwind. It helps me write css these days and it's extendable as getting fast. A pattern I like with tailwind now is to you know still fall back to css defined in a css file, but have tailwind process it so you can still access your theme, your nice design package. That's kind of the utility classes are not a nice addition, but really the theme, the design patterns, especially as someone who is design challenged, like leaning on that, I tend to just stick with that and not fall back to Ross sscbut. I mean, Ross sscis great these days. And it's like I said, it's getting better and it has just came out. There are container queries. I mean, the list goes on and on. You don't even need sas or scss these days. Really. I hope to answer your question. I'm sorry, I'm all in on when. So that's the answer. That's the answer. speaker 2: Any more questions? speaker 1: Well. speaker 2: thank you, Josh. speaker 1: and big round of applause, please.