Django and HTMX #6 (part 1) - Building a Sortable Drag and Drop Interface

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi there and welcome to another bug tutorial on django and hdmx in this tutorial we're going to look at how to build a drag and drop interface for our film list you can see at the moment we've got now an ordering to our films from one to five in this case we can still add new films to the list which get the maximum number plus one as their order and what we can do now is we can drag and drop to different positions in the list and when we actually drop them you see that the numbers dynamically update to give the film the the correct order so this is all new and we're integrating this with django's database we can drag and drop things anywhere we want them and quite interestingly as well if we delete a film let's say deleting this film that's just some random text we'll get our confirmation but you'll notice that the films below which have orders four to six they have their order dynamically updated to prevent any gaps in the ordering so all of this is done through django and hdmx some of this involves restructuring our database a little bit and our views but we're going to walk through that it's a bit dense but i hope you get something out of the video and thank you for watching so let's get started with the first section as you can see we have a list component that we've built so far and we can add films to that list as we want them and as we add the films they appear at the bottom of the list so the newly added films are put to the bottom of the list so what we want to do is work on how to get a better ordering of these films at the moment they are just displayed in the order that they were added but a user might want to see this in alphabetical order or they might want to be able to customize the order and have their very favorite film at the top number one and the second favorite and number two and we would like to eventually be able to drag and drop these films around and we're going to work on that throughout this tutorial so what we're going to do first of all is show a very simple way how to list this in alphabetical order so if we go back to the code and we open models.pi this is the current setup of the models we have the film model which has a name this is what we want to sort by so what we're going to do is add a model meta class and the meta class is going to have an attribute called ordering which we will set to name now what this is going to do is order the data by the film's name so if we go back to the browser here we should refresh the page and you see that it's now an alphabetical order starting from escape from new york and going down to raging bill now there is one problem with this if i add something random here that's lower case that's actually added to the bottom because this is case sensitive if we add a film that has capitals it will go to the right place in the resulting list but it's the lowercase ones that don't so what we want to do is we want to fix this and django's models offers a function that you can use to do this i'm just going to copy the import from django.db.models.functions import lore this will lowercase um all of the names before performing the ordering so if we pass the name field to the lore function and then go back to the browser you should see now that the lowercase is fixed so that's how you quickly fix that now we have things in alphabetical order but let's get to the point in this tutorial and that's to see how to use drag and drop with htmx in the hdmx documentation we've got this page for sortable this is a javascript library that you can integrate with htmx and we're going to add a sortable class to our list of films and we're going to see how that works now so let's start by copying this code because we're going to use that and what we're going to do is go back to the code here we're going to import this into base dot html and within this script tag now this is javascript so we need to do this within a script tag here i'm going to paste that code and basically what this will do is on the load event it's going to search through the document for all elements that have a class of sortable and then when it finds those it's going to iterate over them and create a new sortable object we don't actually need to know the specifics of this library this is all really that we need to do the only other thing we need to do is import the script for sortable from a cdn so i'm just going to do that here and the link to this will be in the description you can get this from the js deliver cdn so now that we've got that what we're going to do is we're going to change the film list to allow us to do the drag and drop now going back to the sortable documentation or rather the htmx documentation which shows the example you see that what we get here is the ability to drag and drop these items to different positions in the list and that's what we're going to try and achieve now in our own project we're going to look at this here so what we have is a form with a class of sortable so if i go back to the code we're going to change the list that renders this it's a ul by default we're going to change that to a form and we're going to give it a class of sortable remember within the base.html this query selector is searching for all classes of sortable so we'll add it to our form here and what we're also going to do is add some hdmx attributes hx trigger and it's going to be the sortable end event that we're going to listen for and when we hear that event we're going to send a post request to an end point we'll just say sort for now but we're going to create a real endpoint in the next tutorial and finally i'm going to copy the hx target here and again that's going to be the film list dev that's where we swap in the html so that's all we need for the form let's go back to the example and the documentation what we now have is a div with a class of htmx indicator now this isn't this isn't actually necessary for drag and drop but we're going to add it anyway just underneath the form class and this is an htmx class that allows you to sort of show a message when a request is in flight and before it completes it's not essential for this tutorial but we'll put it there anyway and finally let's go back to the documentation again what we actually need here is a div that encloses all of our objects so within the for loop which lists out each movie we're going to create a div that will contain all of the inner html there so within this for loop and we'll end the div at the bottom can't type now sorry and finally we'll also change the ul to a form we we change that from a ul to a form so we need to close that off as well so now within this div we're going to do what we need to do for sortable to work and that's we add a hidden input m like so so i'm going to copy and paste what i've got and then we'll explain that inside this div here we'll just paste this input and it's a hidden input so we won't see on the front end we're giving it a name of film order and that's what the end point that we post to will will use to get the data and finally we set a value that we're going to send to the endpoint and that's the primary key of the film that's all we should really need to do i think in order to get this working in a basic format so if i refresh this page you see that we can actually now drag and drop now we're not using hdmx at the moment we're not changing anything on the back end so when i refresh the page the godfather will no longer be at the top here as you can see in the next section we want to actually persist this in the database and to do that we're going to need to change the database models a little bit so let's move on to that now so let's look at the current setup of the models and the database if we look at the models you see that we have a film model and a user model and there are many too many relation between the two of them so users can have many films in their list and a film can also have many users who have added it to their list what we're going to do now is have a look underneath the hood at the database and we can do this using vs codes and sqlite extension if we open the database explorer we are going to look at some of the tables here now we have a film table which you see here just has one field the name of the movie and it has an id as well and we also have the user table here as well we've only got one user and that's our user mark that we're using to log in now what i want to do is show you what actually happens when you create a many-to-many field and what happens is that implicitly django will create another table for you that is not represented by a model but it exists under the hood in a database and it's called a junction table and as you can see this table is what's used to track the many-to-many relationship so both the models involved have a foreign key in this table to their parent model so we can link the user id to the film id why is this useful because let's say we have this user mark and he has seven films in his list but there might be another user um let's say with id2 who also has film 36 on their list so we can track this through the many to many field and the the junction table in the database but what we want to do now is let's say for all of mark's movies here we want to add another column that is the order we want to actually track what order has mark go in the front end for this maybe we have mull hall and drive at number one we want to represent that in this table but we need to add another column so the question is how do we add another column to a table that's created implicitly by django we're going to see how to do that now let's close the sql light browser and what i'm going to do is add another field to this users and it's called through we can specify another model and this through option and it's going to be equal to user films so we're going to create another model class called user films and i'll do that down here class user films and inherits from models.model so the first thing we want to do with this junction table is add the foreign keys to the two parent tables so we'll add user and film foreign keys this is done by the models dot foreign key field and what we now need to do is add our other field and that's going to be order and we're going to make this a models dot positive small integer field and that will give you values between 0 and i think it's 32 000 let's see the documentation it's 0 and 32 767. so it's unlikely a user is going to add that many films to the list and we can't have negative values so we're going to use a positive small integer field and that's going to encapsulate the order and then i want to also add another meta class here and we'll say ordering equals and in this case we're going to say the order so we're going to order the results of queries to this table by the order field now what we need to do next is migrate these changes but there is a problem here and i'm going to share this link with you in the description but basically when you try and change many to many fields django will not like that so there is a workaround to this which i'm going to walk through right now and i will leave this link in the description so that you can see what's going on so what we need to do is we actually need to create the table before we create the through model so we'll get rid of the through here and what we'll do is create this uh here so i'm going to close off sqlite explorer and let's stop the server and we'll make the migration and this should create the new model user films and we'll also migrate these changes now that'll create in the database this table that links the two of them together but what we now want to do is we want to actually add the through model so we're going to create a separate migration for that again this isn't something you would normally do but in this case we need to do it because of django's rules for many to many fields so we'll create a through model that links to user films which is this class and then we'll create another migration and when we try and migrate we're now going to get an error so you cannot alter that field they're not compatible types now let's go through the work around very quickly if you go to migrations and you go down to the the migrations we've got here the workaround actually says that we change the alter field to remove field and then use another add field so basically what we're going to do is we're going to remove the many to many fields from the model and then we're going to re-add it again later so that's the gist of it again this isn't super important just work through the example and get it working so it's going to be migrations.remove field and we'll get rid of that and what we're going to do now is add the field back in with the link to the through table now i'll copy paste this in and we'll change the right fields again this is not the important part of this tutorial but it is something we need to do unfortunately to get this working so if i paste this in here this is what we removed from above earlier and we'll make these model names film and the name is users so with that done we can now try and do these migrations again by running migrate and you see that it goes through okay and what that's done is it should have created the many-to-many table and if we open the database in sqlite and we see now that we've got a films user films table so rather than django implicitly creating this from amenity many field we've actually created our own junction table as a model and now it's represented in the database and if we show the table obviously there's no data in that at the moment but we're going to see later on that we can add data to this and it has in addition to the two form keys the important part is it also has an order and that allows you to track for each user what order does the film appear in their list so now that that's done let's test the front end and we're going to see that the front end unfortunately is now broken because we have changed the structure of a database so there's going to be certain things that do not work anymore uh first of all i need to run the server actually and now if i refresh the page we don't have any films in the list if i try and add a film we see nothing happens and the reason for that is that we have a not null constraint feeling um the film's userfilms.order show this new order field that we have the way we normally create a movie did not take that into account because order didn't exist so the not null constraints failing because we're not actually setting an order so we need to do that and we're going to do that in the next section of the video we're going to edit the views.pi and we're going to edit the code within here to work with our new many-to-many field so stay tuned for that
Info
Channel: BugBytes
Views: 636
Rating: undefined out of 5
Keywords:
Id: V-f_yYKUJo8
Channel Id: undefined
Length: 15min 2sec (902 seconds)
Published: Tue Nov 09 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.