Migrating Features - Building SaaS with Python and Django #102

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi welcome to building sas for python and django my name is matt lehman and we work on django apps on the stream we're going to continue on the homeschool application that i'm building tonight we're going to work on merging a couple pages together i've got a limited amount of time this evening so we're going to get right into it and check out what to do i've been working on taking a couple of pages that were very similar and combining them so we're going to get into that hopefully that'll be interesting to you i hope you'll stick around if it is before i do that i want to just say thank you to my patrons you can support me on patreon.com mblament if you're interested but i want to thank rupert andrew patrick eric philip and miguel for supporting me helped make it possible for me to do podcasting and much other stuff so if you like what you see and you want to support me financially you can go check out that site and see what i'm doing let's look at this issue so last week i was working on this two different pages i have a course page and a student's version of the course page to see how much they've done on this homeschool app that i'm building and um i should note that you can ask me anything about python django or web development that's what i'm here for but i'm giving you context of what i'm building today so the the features of this particular page i've combined some of them and put that behind a feature flag that was the big thing that i should was showing off last week because my customer is not necessarily certain that she wants that um to be available or not until it's all ready and so i i set that up uh so that it was behind a feature flag so that she could check it out but i i could wait until the rest of it was ready for um before sharing it to the larger uh group of users and there's a bunch of things that she highlighted that said like actually this actually really needs to be there this was important for stuff and so we need to get these things back in there um so i'm going to continue on that path and start checking through them and find the important ones and then we'll we'll see how far we get in the time that i've got a lot of tonight the first one that i want to accomplish is trying to differentiate differentiate between tasks that are completed by a student versus tasks that are not so let's get up and look at some code area i've got some other notes from other research that i'm doing for this project but that's not where we need to be we need to be looking at the course views and we need to look at the particular this is the course detail view that we've been modifying so that's up here much of this didn't change we were putting the extra data behind this combined course flag so all of the data is going to go behind this and we can compare some of the features that were required and i'm going to bring up the the web server so you can see what it is that she has commented on on on needing as a priority before that we can fully replace the other thing uh because there were some features from one page that i just haven't implemented and put into the other one because i thought they would be might be unneeded but i turned out to be wrong so let's take a look here and i do also recall that this is uh the cutoff for when i have some sample data but the sample data like the school year ended at the end of april and um i have some max limits in my school year so all of my rich set of sample data is now gone and so we're on to the next school year so that's i guess exciting and that the app has been long enough that my test data is is no longer applicable but it does mean that we have a limited set of stuff here that's probably okay because we can we can add more as we need them so what i'm showing you right now this is the combined view previously without this flag the course page is which is what we're looking at you can see from the url it's got the course and it's got a hash id showing the actual course to look up had the list of tasks and these controls to move tasks up and down and to add new ones and delete them but it didn't have this extra column at the end the extra column is showing an enrolled student so if a student is enrolled in third grade as represented here then they are going to show up as this extra column of data and that's where we need to do more stuff and and i probably need to populate this list with a little a few more tasks before um this is really going to be representative of the thing that we're trying to do so let's do that first before we get into it so let's create a task we'll just call it a demo and we'll make it these not graded tasks and we'll replicate this we'll do it i don't know let's do it five times and actually let's just number these so that we have something to compare so these are those are replication features that i added recently that was fun to do um i did stream on some of that stuff a while ago but not all of it so now we've got more data to look at here and the first thing that she might my customer who by the way is my spouse this is primarily for my family to start but i do have some actual customers outside of my family and i want to make the best tool that i can for all of them so that's that's the goal here so we now have a set of tasks to work with but we need to be able to differentiate between the tasks that are complete and the tasks that are incomplete so i'm going to actually go ahead and mark a particular task we'll set it for today's date which is the 5th of may 2021 and set that so happy cinco de mayo out there for those that of you that celebrate that and so now you can see that we have this this date set so this is now a completed task for this student and we want to be able to show that this task right here is visually distinct from the rest of the tasks that's an important attribute that is missing right now and was available in the old version of this in fact we can go to the um area where it has flags and let's go ahead and disable this page for this flag for a minute and see what it looks like with the old view which should take so that's turn to false and then we can refresh this page and we get this view where like this is what it used to look like and it what it still does look like for the majority of my customers customers except for my spouse who is triangling out this new view and so when when looking at the actual school year and digging into this this is the page right here that i'm trying to replace and you can see there's what happened to that first task well one of the features that i have to restore that's really important is she wants to be able to to when a school year has started and she has students who have the stuff um to to do when the task is done that's no longer the priority she still wants to be able to access it which is why it has this show completed tasks button but this is where we can start to get the hint of the thing that we need to implement first and that thing is a visual distinction of this item is done let's mark it as a grayed out version so that we know that it's done so that's what we're going for on this page that is this new version and so i'm going to turn the flag on now you have a baseline for the understanding of what it is i'm trying to replicate and i'm not trying to do the filtering part yet so this button to hide in and unhide tasks it's not the thing she's okay if if this combined page starts with just this visual distinction between light and dark so we'll refresh this page now we've got this new the updated version back so this this problem gets slightly complicated though and it gets slightly complicated because multiple students can be in a single course so there are two ways that this can happen there one way is that you can have multiple students in a single grade level it's also possible to have multiple grade levels that contain the same course so those are the conditions that can make it so there's actually two columns here so i we might actually in order to do this properly um let's take this math3 class and we're going to break this example it's not really going to be math 3 anymore but we're going to add enough for another student here so let's let's go to the school here and right now i only have third grade and i've got one of the two students in the sample set added so we'll add a second grade level and we'll call this first grade and then so now we've got first grade and third grade and i want to add a course actually i don't want to add a course i want to go to the existing course i'm going to go to math 3 and we're going to edit the course and make it so that this actually applies to both and just to make the naming clearer we'll call it math both to indicate that it's actually for two students or two grade levels so the effect is now you can see on this this page we have third grade and first grade and for whatever reason the flag is not showing so i don't know what's going on there there we go um there's some like caching that happens with django waffle that is the flag library that i'm using that kind of keeps on that state for a little while so anyway we're back to this now but we still don't have more students here but i did make that possible to work last time so we need to return back to to that school year and you can see there's no student enrolled so we need to enroll a student and specify one of the other students so i'm going to pick this one and i'm going to pick first grade so now we've got a second student fey enrolled in first grade and you can see that math both shows up for both third grade and first grade so now we've set up a scenario where two students are enrolled in the same course and if we click on this we finally get the real representative scenario that i'm hoping to describe um in fact there's one more set of state in order to capture this that i think is that we want to get so i'm going to take i'm going to mark that this is also complete and we'll mark that as 5 5 21 and that that flag is not applying that's kind of annoying um come on now i don't know if it's something to do with sql light or what i have no idea like some some of the stuff caching stuff is weird and i'm gonna mark a second one so there this is really applies to n levels for where n is the number of students but there's there's kind of two states that i need to capture of when do i need to show that this task is totally complete versus when do i need to show it as incomplete and that's going to to matter a lot especially when i go back and add that filtering so if the filtering is turn don't show the completed tasks by default and instead hide that stuff then i really want to make sure that i'm that all the students have completed it so this is going to be the rules for this so in this this scheme that we're talking about because both mark and faye have completed this first task of year this line should show up as gray because mark has completed demo one and fey has not this should show up in its normal coloring so that's where we're at that's that's the data that we need to introduce and so there's some additional state that does not exist in the context data that is there today that we need to add as we're processing the list so that we can determine whether to show this as gray or not so i think the first step to do is go into the context data and add that extra it's essentially boolean state and that boolean state is calculated from the summation of have you done this or not have all of the students done this so that's where we have to go into the view and do that computation so we've got this shared function here and the reason it's a shared function is because there's actually multiple views that need this context one of them is dynamic so what i haven't even pointed out is that you can do certain actions like delete one of these things and the javascript library will do the call to post to delete the particular page and re-render the entire table of data and it has to re-render that whole table of data because these things are numbered if i did not if i just deleted that row then you'd suddenly like let's say deleted demo 2 then task 3 is going to go away and the number sequence would be 1 2 4. and that doesn't make sense i mean i guess it could but it's not the best experience so we're we need to re-render the the whole table of data so that is why this context function exists so we're going to spend our time actually working down here in this context function hopefully that makes sense to you if you have any questions drop them in the chat and they haven't answered all right so we're going through and we're essentially at the moment calculating for each task we're going through and saying each student has some state but that's we don't care about this particular student dictionary because we need something that applies to the whole row so we need to add some context that is to this entire task and i think i want to give it some kind of semantic meaning that is appropriate here so we can say what can we say we can say hmm what what name do i want to call this um i'm trying to think of how to do this because we have to we we don't know until we get to the bottom until we've looped through all of the students of what this task state is right so it's really a loop that looks something like this so i'm going to say something simplified of task complete and it's only complete if all of them are complete so we can actually default it so if if we default it to true is that going to do what we want to do that's the question i want to start with asking because i really you need to there's it's like we want to be able to update this state for each iteration through the student loop and i'm trying to figure out if that's gonna be the most logical i think it's not i think i think the behavior that we want to make sure that it shows up as incomplete most of the time oh welcome glad you're able to join in on your lunch break so you must be at some time far in the future or the past i'm not actually sure where you're coming from like lunch is a long time ago for me but it could you could be referring to tomorrow's lunch may the may the 6th um curious how timezones work so um i think i want to actually default to uh future yeah new zealand well welcome from new to to uh to you from from the us i guess um so we've got we want to set it to the task to be shown by default so we want the the default state to be incomplete because there's also a state here that the number of students um may be zero so that's something we have to account for so this for loop may actually never kick in and if we're making the display logic for the template show the darker version of the text only when the task is incomplete then we want to actually have this boolean state be false by default i mean conversely i could say like task incomplete and that be true but i i and my brain blows up if i try and think like that so we're going to call it complete or not because having the thinking about the negative logic is is really too challenging for for me anyway maybe you're a rock star at it but that's not how i work so we can say um what how do we update this how do we know when um when to switch it to true that's that's the interesting challenge especially for doing this as an iteration we don't actually we don't really know until the end right we don't know until we've processed all of the students so it's not like i can um go in here and say if one student saw this and and had the work done then you mark it as true because that's not good enough so it's almost like we have to keep track of um i'm gonna do this in maybe a stupid way but it will hopefully work in the end and in fact i don't think we'll actually need this that that local variable so we'll say if we say complete um statuses is a list we might not even need this we might just be able to calculate this from the student details at the end still thinking through this sorry i apologize i have not thought this all the way through this is just the process of of my brain process so we need to essentially the thing that we're looking for is the coursework is the piece of data that we need to determine if this is done or not so the if all of the students have coursework then the task is complete and so there's going to be a list of student details right here that that's what we've been populating it's actually in this task detail you can see this list and so if we can look into that inspected after the student loop has been processed then we can determine if that task is complete so there's actually two factors that come into this but we'll do the naive version first and then we'll work through the corner case and i'll actually make a to-do to what about empty no what about no students again to make sure that we account for that case where there's no students because that is an edge case so the thing that we're trying to take is we can determine task details and it's going to be all so there's a built-in in python called all which takes an iterable and the iterable is in this case going to be um we can do a generator and we can say uh student detail of coursework let's use a shorter name for detail coursework or detail in task detail student details okay that may have made zero sense to you i hope it i hope i strung it together okay but the idea is here like all of these have to be true so the the dictionary will will have a value here and you can see that ignoring like how this is built there is some some collection of data that is a lookup table that looks for a task id to see if there's coursework in there the reason that's done is for performance reasons so you don't have to fret too much about that but but you can understand this as the dictionary will either have a courseware work object or not and um so if we actually come over to the interpreter and i've got my list and i'm saying my list is none and none because the the if you call get on a dictionary and it doesn't have a value it will return none if i did all on the list that's going to return false right because none of them are true even if i had a new definition of the list and let's just pretend that this string coursework represents a coursework object it doesn't really matter but if we do this all again it's still going to be false but now if we have both of them as some some value something that is truthy then we've now got a list and all should return true so that's the case we're trying to go for so we can represent that the i don't actually oops i i see the mistake already so we want to say uh we'll just call this complete at this stage this is the boolean state that we're trying to calculate is the task complete or not okay so that's kind of step one what is it complaining about uh no overload variant of set item of list do so task detail student details is a list for why is that wrong what i'm trying to do is like a comprehension how about any uh yeah that's probably the flip the inverse of this right if that's probably better ship day love you're you're right it's probably simpler um if any of them are not done then the task is not complete so maybe i'm maybe i'm overthinking this you know sometimes it is 9 33 p.m my time and sometimes my brain is not super fresh after a day of work so what if we default oh this is coming together way nicer thank you all um so let's let's default it to complete and check this out if it's so if now if any if we go through the students and any of them don't have it complete then we can flip it over to false and i think that is going to be way simpler than calculating it later and it's also going to have the benefit of well no no it's not going to have that benefit [Music] so here's what [Music] so complete is actually going to be do we have if there are no students right remember i said i have that edge case if there are no students we want to show this so we want this to be false when there are no students right so that is is literally the bool of the list of students i think that's right so now it'll say if you have any students then default to true because a list with a size of some some size will be truthy if you're an empty list default to false so show it as as not complete and then we can come in here and if the um so we want to now flip over uh to the complete boolean status based on the value of coursework so i'm actually going to extract this into a local variable because we'll use it multiple times here i think and we'll say we'll call it work because i am running out of unfortunately coursework is a really crummy name for pluralization purposes and that's just the way it is oh my word come on now student i was trying to copy and i failed um get task id so we've got this we can change this to assignment to be this local variable and now before we leave this loop iteration um we'll do one final test here that says if if there's not work right then we want to flip it over to be false right do we want the thing to be incomplete uh so we say complete and change that to false oh man that feels so much better than the thing i was trying to do a second ago i think it's the right logic we can walk through it mentally but so no students this is going to default to false it's going to skip the for loop so this will never never go and it will come out false and then when we render it on the template side we only use the gray when complete is true so it'll show it in that darker whatever darker color we want to show okay now we've got one student so bool is the state is true by default we'll go through the for loop one time if the student hasn't done it it flips over to false and then we render it as darkened right as we would want it um i think this definitely extends to multiple students so if any of them have so we default to true to say that it's all it's all complete but if any of them haven't done it it's no longer complete so i think that's the right logic it feels pretty good it feels nice and clean too so i appreciate the suggestion about any that was a good call all right let's try it out so we need to we need to actually use this date now in the template right and then we need to actually probably write some test cases so the template we're going to go to the course detail page where is that page course detail there it is and we are only going to put it in this combined course flag area so i've i've got as you saw maybe if you start at the beginning i was able to flip the flag over or not so show either the old view of the or the new view which means i have a ton of duplicate template logic right in here right now but that's okay because when i'm done and i'm ready to roll out the feature i'll come back through and clean up the flag and just delete all the old duplicated code so i'm okay with that duplication just means that we need to make sure we put it in the right place right now so we've got the flag as combined area which is right here and now we're in the spot where we need to affect the the rendering of the font color and all that stuff and i also didn't think to check that was dumb of me um well we'll just play with i don't know which i don't remember which gray it needs to be but we can we can mess with that what gray is that i'm curious that's a gray 600 on that hover which might be it needs to be distinct enough to be noticeable but not so washed out that it's unreadable because she is and she my customer and any other customer is still going to need to be able to view the completed stuff so we don't want to completely like wash it out so i think we probably i mean that is that visually distinct enough i don't know i've got flux on so it's hard for me to tell which maybe is a sign that it's not distinct enough but if i had a list in that gray and this number wasn't that gray i know maybe what is this gray maybe that's really the color i want [Music] um so that hover gray is 600 so that's the darker one so i think i want it one one shade lighter which is the 500 gray so we're going to try with that see if that'll work uh okay so where do we need to go we need to come into the place where this stuff is numbered and the description and that's not in the resources area oh it's in a totally different template that's why i'm getting like where's this stuff so we have the this is just the header which is not the stuff we're trying to imple change i have because there's this like hd this uh javascript rendering stuff i had to separate the template because that needs to be rendered in a separate view so we actually need to go somewhere else so course tasks is the template that we really are looking to modify and here we are again here's the flag so it's in the section so we've got the counter and maybe this is a simple i wonder if we can apply this to the whole row let's try that so we've got task detail and we're going to add it let's see if we can get away with this i don't know if it's going to be work or not so if tax task detail and this is where templates are nice in in django in that this is a dictionary right we saw that in the view context but i can access it with dot with attribute access and that works so if task detail complete is the thing we want to check and then we'll say put an endif here because i think that's all we require and is it it do we want the complete or not complete so if it's complete we want it to be the color that it is right now um or i'm sorry i said that backwards if it is incomplete excuse me we want it to be the color that it is right now so that that darker the standard black color if it is complete then we want it to be in the gray color so i think this is the one we want we want to say text gray and we'll do 500. oops i stopped the server okay oh snap didn't seem to work all right let's figure out what we messed up um i'm going to turn so i'm going to turn on django debug toolbar which i have configured to turn on with an environment variable and we're going to refresh and we're going to check out the context and see what i messed up i want to check two things i want to check the is the context right and then the logic is the did i mess up the logic so we're going to get in here and we've got our list of details and complete is true oh oh yeah this is a fantastic tool it's called the django debug toolbar now it's harder to use when you're working with like if you have a javas just an api and a javascript app you can do it with some stuff on if you're using like django rest framework but on a server rendered page what this does is it gives you this little toolbar it injects some javascript and you don't want to run this on your production website your like live website but it is fantastically useful if you're doing development of you can you can use this to see what's in your template which is what i was just doing looking at this is also super useful of seeing here are all the sql queries that ran for this page so if you have any problems with your queries like you're querying something in a loop and doing that very slowly that will show up here there's a ton of stuff in here so yeah definitely it's a good solid plug for the django debug toolbar okay so we've got um this is marked as true and the rest of these are false so that that's actually the condition that we want so it seems that i maybe messed up yeah no problem um it seems that i've messed something up here or or it could be that the template syntax is perfectly fine and there's more specificity that's what it is there's more specificity applied at the individual line so it's overriding that chunk of template syntax is my bet so if we go in and actually do the inspection on the row yep look at there it is oh i typod it oh crap how embarrassing text refresh hey cool um and you can see it still has this is still good because look we're actually on either side of that text 600 gray 600 so this text must be like either 700 or 800 it's the default or maybe it's just black um what is that i know it's and let's just have the default text color all right which is i think a black um i'm looking for any specific color information yeah so it must just be black so we've got um when we are hovering over these we can see that that they're still looking lighter at the same time we've gone light enough that when we hover over it it goes darker so we can still observe this is clickable so that's really positive and just to prove out that this works let's go set a date manually for this task i'll set it to 5 6 21 and now we should have two of them that are grayed out awesome oh that's exciting okay next thing to do is write a little bit of test code this is a bit of context that is like the data contract it's the contract between what the django view says is it's going to provide and what the template on the other side expects to exist so i want to write the code because i'm not doing some end to end test that says is this text gray because that would be super flaky but i can write the checks that says when multiple students have completed this show this as complete those are that's context tests that we definitely can write so i think we should because i'm the only maintainer of this application and if i goof it up then i want a safety net so we'll go to the test views that's not the right area courses test views there we go we're on the course detail view and we probably need to set up this particular some test state sorry about that um because it's a little bit more complex and oh the other thing we should do there's another remember there's another state where a student is not enrolled so we want to check we want the test where there's no enrolled students we want the test where no students have completed anything so it defaults to showing as as truthy as well and we want to test where at least one has um not completed it i think that cover the cases that will trigger the proper boolean states it covers yeah all right so what did i just say we said um test task complete no students when there are no students a task defaults to incomplete that's one test there's another test where we want to default so task complete um one student coursework when a student has not completed the task is marked incomplete and then finally the one other test that i said was what happens when they're they're both done so task complete both students done i don't know these are best the best test names or not but they're descriptive enough for me when all students are done with a task it is marked complete so these are largely going to be very similar tests in the kind of data that they have the other bits that we need for all of them is these are only going to be true when this feature flag is on so we need to attach this decorator to all three tests right now and this is something that i'll clean up after this is all over so i'm going to start perhaps foolishly from right here we'll take all of this data for the test as our baseline because it's got a lot of the necessary setup that has to go on this particular view you have to have a grade level you have to have a course you have to have a task you have to have some student enrolled and coursework we don't need a grade in this particular test and in fact we this is the one that doesn't have students so we can take out the enrollment the enrollment is what connects a student to the school year and so if you don't have an enrollment you it's it's the scenario where you have no students so we want this is the scenario [Music] we do there is going to be a task here i'm going to run this test and show that it will fail um whoops i'm referring to stuff it's unfailing for a bunch of reasons uh so actually maybe she'll go ahead and just write so we'll get closer to passing anyway so we're expecting the context to have these task details in it but it's still gonna fail because there's this new thing that i added which that didn't show so let's try this again test nearest with some verbosity here which should show the whole the whole dictionary i think all right so the thing that's highlighting is we're missing the complete is in that dictionary right and it's it's false right now which is what what we actually care about um so really what we want to do is i'm going to instead of starting asserting on the whole structure i'm going to pull out from the task detail i expect there to be a single item in here and if there's not it should fail for other reasons so i'm just going to just pull from the index because i think that's the right thing to do and then we want to assert that detail complete and actually it's a boolean so we want to assert that it's false so assert not complete and now we don't need this anymore and the test passes cool so this is similar this is the basic structure for this these other tests so we want this to be incomplete for this particular test when there are multiple students so we need to come back up here and we're going to take the enrollment and the work and we're going to plop that right here and so we'll say we'll do two enrollments because that'll represent two separate students i think this should be the right way to do it and so now there's two enrollments means two students one of them has completed the work but one of them hasn't so this is that's what this first enrollment is so this should still be false i think this test will actually pass in theory um forgot we still need that name we're not using the work itself cool that test pass so that's that's the state hopefully that made sense to you if it didn't you know give me a holler in the chat um one more test so this test is when both of them are done so now we want to actually assert the opposite we want the the task show up as complete which means we need the coursework for both of them to be done so this is where we have to we actually have to give more precise names here um so i'm going to say enrollment 1 and enrollment 2 and here we need to come into and define them uniquely so we'll take enrollment two and then enrollment one just have to we have to wire those things together more appropriately that way so now now what the scenarios that we've concocted is that there's the student coursework is like have you done the task or not and so we're saying the student has done the task we've made the factory data so there's a model oh thanks for showing up shivan 93 i appreciate you turning in and we are now at this point where both of them are done so this task should be marked as complete logically with any luck we got it right all right neat uh and i think that actually covers the i have some requirements on my project so that all lines of code are covered so if we didn't hit this particular line these tests have certainly hit it by now all right so we should have full coverage of all of that code let's talk about what to do next because i think that checks is the box we need a visual distinction that tasks are complete versus incomplete done and i do have a limited amount of time tonight so i'm not sure actually how far we'll get into this next one but we'll start on it the next thing that i want to do is actually not this one i was talking to my wife before i started the stream and i said hey look what what do you want me to work on which one of these are more important to you and so she said yep this was number one got to be able to show the difference and the the next thing that because this distinction will be visible after this um it would be nice to get this projected state of stuff so now it's time to like i guess come back to what did the old view have that this new view is is missing now and see how we can add that back in so we're going to come back to this page we're going to turn the flag back off so the web server's still running let's turn the flag off so we can do the before and after we'll disable it and refresh this page we should see the old view so the old view but we can also click in here and see progress for one of the students i'll do that and we'll do this to expand it all right so here is the thing that's missing this column right here planned completion um as my my spouse is trying to figure out school year she's working through and determining well when is this likely to finish versus when is this likely to finish and i had thought that i naively thought when i first wrote this page that she only cared about the end date because there is a part of this school year that has a report of when's everything supposed to be done what are the last dates for the class and so here's an example of uh you know 5 5 11 and 5 10 is the projected last dates based on this what the student has already done and um that's that's useful but that's not full enough so she really needed to see this extra level of at the day-to-day task for an individual thing so there's a kind of a couple of views for this there is one view of um how much has a student done there's also what happens when there are no no students and so both of those are different aspects of projection so for just the preliminary planning for the school year before any student is enrolled it's important to be able to show how long is this going to take how long will this go through the year so this this calculation right here this planned completion stuff calculates it incorporates whenever you set vacation days when do you not do school during the week so if you take off saturday and sunday for example which is very typical in most schools at least in the us i don't know how i can't speak to all of the world of course but at least most schools are monday through friday right and um it factors in all that stuff to give accurate projections if you have this many tasks and it's projected to take you out this far so we need to be able to show that on this page it's not on this page but we need to be able to add it so let's turn the flag back on and see where it's going to go and again it's being kind of weird oh this is the other page um there we go so here we are we have to do this in two different states and this is the challenging part it's like how am i going to show this i think when there are no students what i want to show is just like this other other version where to go i have a column called plan completion and it's going to show all the dates of here's if you were able to do this school year ideally you never had any hiccups or slow downs or anything like that here's when you where when you would end and that'll replace these columns and show that as planned completion when there is um a student that gets a little harder and i had a discussion with her of like how do you want me to represent this because it's going to be a little strange like i don't want to i could instead of having set date i could have put a date a projected date here but then it loses its visual clarity of what that means and so what i think i concluded was it would be better to have a second row showing the projected date underneath it so it's going to make all of the rows double in height by default um which is you know that is what it is that's the best way to display it um but uh and the challenge with that is like there has to be um i can't just have like an extra column over here that says plan completion because it can vary per student in fact you might have even if you're super observant which i wouldn't blame you if you weren't i barely noticed it um notice this this is the same class both students are listed here but it has different forecast dates because when i was over setting the dates here i marked different dates of when this was done so i actually marked this one the for the future and so like it like she already completed this task and so it affected the forecasting so i can't have a single column because you know imagine this in the extreme where one student has done half of them half of the tasks and for some reason the other student has done a quarter of the tasks and they're very going to be very different projections so we have to show all of the projections for each student which is complex it's more complex but it's more accurate so we're going to do that we're going to include a second row that will go um it'll only show up on uh stuff that had hasn't been completed yet it doesn't make sense to show a projection on completed work and it'll exist down here and i think as an icon i'm planning to use um i talked to her about what would be a good icon to use and there's no perfect fit for this there's not like show me the future icon um but the watch icon was a reasonable approximation so that's what we're going to go for um i don't like i said i don't think i have a lot of time i probably have another 10 minutes to get started on this but we're going to walk down this path and i think to start maybe we'll focus on instead of having the completions for each student um actually maybe that's easier yeah that's probably actually easier because um this current plan completion stuff is based on a student already so we just there's some logic that calculates this and we just need to call that logic twice if you have i mean you need to call it end times for the number of enrolled students whereas the case where there is no student is actually some new case i think that i didn't anticipate um and probably don't have an extra actual forecasting for so we're going to try and get it for one student add that extra bit of data and try and insert them into the rows here and if we can do it for one it should just do it for the second one um uh yeah le rezende leo resende is that am i getting that close to right um yeah i think you're i think you're spot on there's probably there's some level of of django waffle caching that i think happens um and i suspect it's because it is backed by a database table but if if waffle is trying to cache it for a little bit then the different workers might might have different state so yeah yeah that's pretty it's a good observation you're probably right um so we'll put some plan date stuff here we'll use the watch icon and hopefully get something that matches up appropriately i'm not sure how we'll blend the data into the actual task rows that might be the challenge although if if it's a forecast that has that spits out the dates i i just don't remember i think i i think i built a forecaster class but i don't remember how if it was meant to be iterated over or if it was meant to be queried by a date and just i just don't recall and we'll have to actually look i think maybe the best starting place to go look is at the old view because that's going to be the one that will show how i did this because i had to refactor it i had to i had to make this logic work for this page but it also need to be it was the same logic that's used for this page so the way that did the way i built this page was kind of dumb in a sense of i cranked through all of the forecasting logic and then just pulled the last date that's what's showing up here so there is a forecaster class that builds some stuff and i don't remember if it's a list or what it is um where is it where did i put that thing i think i even called it a forecaster it's in the schools area okay all right um let's close the test case let's take a look at this so the way this works is it takes a student and the course and it provides this big list of tasks and it's doing all the logic so it's pretty self-contained on for how to use it which is nice and it has all these edge cases that i'm not even describing and are not worth really talking too much about we just know that we can we're going to take it on faith right now that this is builds the right thing it's just a matter of can i use this appropriately after i've got the data out and that's the trickier part is that this tasks item is a list but i need to convert it into a lookup table i think let me think through this for a moment i think that's gonna be the way to go let's go to the students views we'll see where the forecaster is used there's a forecaster right here and it's past the the things that needs to calculate and gets back this list and then it cranks through that okay so that's going to be kind of close to what we're looking for but not quite the same so actually before i do this i'm going to take whatever um what i've done already in homeschool and templates that's the this the test code this is the modifications that we just worked on turned out to be really simple that's nice it's only a handful of lines i really like that um so we'll add that to the stage and we'll also add the template code i want to see we made one change in the template it's crazy sometimes you get these changes down to something pretty minimal so we'll add those two things to the stage the other files that i've you can see there in my git status don't worry about them those for other work that i just haven't committed but this at least gives us a kind of a clean place for the to hack on to spike on this code change and then know that if i've messed it up i can just sort of back it out if there's a problem um so we're at let's get up the course view we're back at the detail view or back at that function i should say and like i said um this thing goes through the tasks and does a bunch of lookup tables in fact this is probably the most accurate example of what we are looking for is um i need to do lookups of like grades and things to see if you look if you have the right grade but i didn't want to query the grades table every time it looped through every single task so i what i did was i took all of the grades and i put them in a data structure into a dictionary here that's actually like keyed by a student's id and i was able to get out if they had a grade or not so it's going to be similar for asking what is the forecast date for [Music] for the the particular task for the particular student those two things those two pieces of information need to go together and where did the forecaster go oh that's interesting it's not even as com as simple as i would like it to be so the items coming out of this needs a planned date attribute that's the one that actually has when it's it's a calculable so the data structure isn't even super straightforward of us because it's complicated it's like if the the date might be coming from the coursework it might be coming from something else so this gets kind of brain bending so i think what i'm going to do because i really am i have other things going on tonight so i i'm limited in time so i'm gonna put in some to-do's and basically set this up for the next stream how about that um and then we'll call it so what what needs to happen um we need to set up a lookup table of forecast dates all right and then each to do so each task well this we're considering the simplified case where you actually have students so each task per student needs to pull the forecast date from the table then on the template side we're going to render the forecast date if it's available in the student context so those are the things that we're going to do on the next stream frankly actually we might not actually do them on the next stream these are the things that i'm going to do um my my spouse is looking for this stuff to be in there so i might want to do this ahead of time but we'll see um dja birth the mac bertha mix i i'm hoping i'm getting your handle somewhat close you're new to django what's the best road trip you need um are you asking like how do you get into it like our resources for getting started is that kind of what you're looking for because if so i have some suggestions and it sort of depends on what your learning style is um if you like by doing and i i love by doing and i think is a great way to learn there are some hands-on ways to go um the if you go to djangoproject.com and then you go to the documentation section there's actually going to be oh here it is it's right my face and i'm looking right over it there's a django tutorial the django tutorial so go to here and this will walk you through and it's pretty well documented it'll walk you through the basics of of django it's going to introduce you to the orm which is for models in the database it'll walk you through [Music] uh views which is how you run the python code that extracts data from the database it'll walk you through templates which is how you render that stuff to actually write out the html to display to a webpage all of those things go in here i'm trying to remember what else let's look back at this list oh yeah i mean you can see from the docs it kind of lists out the parts oh right talks about how to do web forms so if you want to have users interact with your site and send you data and respond to data that goes in there um then it gets into more esoteric parts of of django i'm not actually sure static files i guess is something that people should know early i don't know so the tutorial is pretty good so that's one route the other uh there's another tutorial that um there's a an organization it's called django girls and they have a tutorial as well uh and it's not specifically gendered or anything they just have done a good job of putting a tutorial together they as an organization try to help they focus on women and those sort of things but uh this is the tutorial you could use from them and i i honestly i i did not learn django this way um this did not exist when i was learning django i believe but i've heard good things about this tutorial so that's that's another place you could go it's the django girls tutorial and i lost the link for you for the here's the django project tutorial um if books are more your style there's learning django is that it learning django learn django learn learn django oh man the person i'm trying to find is is someone named will vincent uh will has a lot of good resources um that are specific to django a bunch of different tutorials for different kinds of things he has got some django specific books that i think i've heard again i have not actually read these myself but i've heard really good things about them so if you have funds to go buy a book you could check out one of those his content is usually very very descriptive of here's how you would do this so kind of holds your hand pretty well i think he has another site i'm struggling to find where it is i thought it was i thought it was lauren django but i'm maybe i'm miss remembering the name of it now uh sorry will i i don't really remember at the moment um i also write a ton about django so if you want to check out my stuff i have an entire series called understand django that i'm actually in progress of writing it is not complete but i have a lot of articles here they are not short articles they're they're meant to be pretty exhaustive on a topic and i've structured it from a point of view at least from my viewpoint to say like you don't actually know how to program or or do web stuff in general what what can you do to get in into that so it starts it the my pedagogy i guess uh in in building this particular course series is different from the tutorial the tutorial starts you down with the data they start you at the base of dealing with the database and my series starts you from the browser and works you down into the stuff so explaining how url routing works and understanding all the pieces and slowly layers in more more complexity as you go so those are different ways that you might want to learn about django um i have i take all of these streams so if you want to it's a probably more more advanced but if you just want to stew in django development i do this stream and have done the stream for well over uh two years now and and i always get questions about where should i start because i have multiple projects but starting at like stream number 39 on my youtube channel is where i start this particular homeschool application uh before that i was i had a different app going and uh you know you i would i would recommend starting from this application the other one was a bit more involved and uh covered some really kind of deep deep corners of things so um my that's that's where i was suggesting um what other resources are there there's the django forum the django forum is a group of folks that will answer django questions this is a discourse site there's a good way to get your answer your questions answered there so if you have questions you know i mean obviously recognize that these people are volunteers they're not going to do your project for you and so you got to put in some some of your own work but this is a good place to go to um other resources that i might suggest i don't know i think i feel like that's a pretty good list hopefully that kind of answers your question about where can you go um if you have any questions i can hang on for another minute or two but if you don't i'm gonna i'm gonna wrap up so let's look at revisit this what do we do today we actually so we made something visually distinct we took a feature that was over in an old page that i'm trying to get rid of because it was a confusing page and it wasn't confusing because the functionality on that page was confusing it was confusing because there were two pages that were doing basically the same thing trying to understand your comment there just reading through it just make sure i can see all of it uh if you can make this okay yeah good luck on that project that sounds like interesting stuff like there's probably a you know people that could benefit from that kind of stuff it certainly would help um i guess if there was a piece of advice and that i would have for you is try some make sure you before you commit to a big project and i'm not trying to dissuade you from doing a big project of course but before you do that try something small something very very well scoped of can i make pages can i get views together can i render something can i make a form can i just go through the motions of getting an app going because i think uh that will help i'm also a big fan of having projects and going after the stuff that is important to you because i think that that is a fantastic way to have the motivation because a lot of people um let me what contact should i add so i i am a meetup organizer in my town so i run the python meetup here in frederick and prior to covet 19 i we met every month and i would meet all sorts of people who are wanting to get into python wanting to get into web development and they would say how do you do it what can i do and the bit of advice that i would give is pretty consistent is that find a project that you care about and it sounds like you have one which is cool and the reason that that is actually to your benefit to have a project is you are going to absolutely run into walls run into barriers that are going to be hard whether it's like conceptually or just technically difficult and having a project that you're trying to make available to people and getting real users to use is the motivation at least in my experience is the motivation to get you over and continue on um because if you do it purely from an academic point of view just to say hey i just want to learn this thing then as soon as it gets hard where's your motivation to keep going i think a lot of people at that point just say yeah you know it doesn't matter i'm not really doing anything with this so i'm just going to stop and so i think that's great if that's if you're working on a school management project um and where students can or children parents can check out their kids marks and stuff that sounds cool um try that out and see how it goes i'm sure you'll learn a ton all right so we are working on this combining this page for this homeschool application and um we're extracting little pieces out of the old page putting them into the new page this uh where this needs to go now is to get more advanced and this is the tricky part about working on this app is one of the things that i pitch for school dust in particular and i'll show you right on the the main marketing page that i have for the site is the headline feature of this particular application is that it's meant to be simple i've i'm out there actively reviewing a lot of the competitors in the space and these tools in this space get really complicated so how maintaining that simplicity is paramount for what this application needs to be in order to succeed with with the market that i'm going after people who are have tried other tools and have complained that they are too hard and so that means that this view that i'm working on this course page needs to be really it it can't be an airplane cockpit it can't have too many knobs and buttons and and toggles and widgets and features it needs to be very clear and so that's what i'm trying to balance here of this i need to actually put in a ton of actual like user experience design and product thinking to make a simple experience and hide the complexity and let the application do the heavy lifting so that what comes out the other side when a user is using this is it just feels natural that's an iterative process where i put the features in there and i get customer feedback and say hey does this actually make sense do you like this is it simple enough what can i get rid of what what's not working what what's confusing that's why i'm combining these pages it's like it was it was already starting to get into that trap of being too complex so that's why i'm doing this whole project and that's where we'll go um in the future i don't know if next week i will be um still on this particular page trying to refine this or if we'll be moving on to something else but i have a lot of other stuff to go go into um i do want to thank you all for joining in this stream tonight i do take this content and i post it to uh youtube so if there's anything you missed that you want to go back and check you can go find me i'm matt lehmann on youtube and i'm pretty easy to find um and if you're over there you give me a thumbs up or subscribe that really would help uh help me a lot anyway oh you did some awesome work here there was a day um oh cool cool yeah i i'm actually i need to go read that i'm going to take that link and go read it after the stream because that sounds like it might be uh explaining what was going on with the behavior some caching or something so i appreciate that um so thank you all again for tuning in uh go check out that stuff if you haven't subscribed here on twitch or what is it follow on twitch i'll never get those straight um please please do that and i hope you have a great evening until then i'll see you next week take care
Info
Channel: Matt Layman
Views: 361
Rating: 5 out of 5
Keywords: twitch, Python, Django, SaaS
Id: DQCg6iZG55E
Channel Id: undefined
Length: 77min 53sec (4673 seconds)
Published: Thu May 06 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.