Filter Tirekickers - Building SaaS with Python and Django #109

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi welcome to building sas with python and django my name is matt lehman and on the stream we work on django apps we're going to continue on my homeschool application tonight we're going to specifically focus on dealing with tire kickers in admin tooling and how to filter them out and and make the views that i have more useful so that's the plan we'll get into some tools and how i'm going to do all that so hopefully you'll stick around before we get into that though i do want to let people know that you can stay in touch with me on youtube or follow me on twitch here uh so please like comment subscribe all that good stuff i also want to thank my patrons who support me financially and you can do that too if you want to you can go to patreon.com mb layman if you're finding the content valuable but i want to thank rupert andrew dragos patrick eric phillip miguel and peter for their um contributions it really helps me put out material related to django on podcasts and all that other stuff and and just kind of um compensates me a bit for my time which is just a nice little touch too so thank you all i appreciate that all right what are we gonna work on tonight we're going to uh deal with uh tire kickers and um maybe you've never heard the term before but this is a um not an uncommon term but it's specifically about people when you're talking about a software as a service it's about people who like try out the service and then they kind of abandon it and have no plan to come back and my service has a very um generous 60-day free trial for it so there are people that try it out and decide it's not a good fit for them but there are some that are more obvious than others that clearly they're they're coming in there just to poke around maybe it's from this stream maybe it's from other avenues but they they really clearly invest no time into the application and um never come back and so i have some tooling that looks at who has signed up and who's in trialing and all that sort of stuff but i want to be able to to filter on the people that are like real trials that are actually trying the the app out and um distinguish between both the the brand new people that have just signed up that maybe haven't gotten all their data in yet and the people that are really trialing and then this third category of of tire kickers who are just there's there's no chance that or it's extremely unlikely that they will convert into real paying users so that's the plan tonight uh to go over that i'll show you my onboarding tooling what i'm actually doing to track information i'm trying to avoid tracking too much like i don't have any google analytics on the site that's an intentional decision i'm just not interested in seeing that much information about people and nor am i interested in giving google all that information about people who use my site so the metrics that i do use is actual usage of the the application and so that's what we're going to look into so i'm going to start up the local web server and we'll fire things up and i'll show you exactly the kind of problem that i'm facing i think i have some examples in my local dev database we might have to create that but it should be okay we'll see um it's been a while since i've logged in so i've got to remember my test account uh did i okay good so um in the user interface of school desk which is the homeschooling app that i'm building there are a couple links up at the top here that no one else sees on the site if you signed up for school decks today and became a tire kicker yourself you would not see these links at the top they're only available to me as the administrator of the site and they take me to a couple different places one of them takes me to the django admin which is this one right here which i've renamed to office for my app so that the script kitties can't find it as easily and so that's where i would do that stuff and i'm logged in as the as an admin user and i can see that stuff the other area is this dashboard which is a set of a small set of custom tools that i've i've written in order to help me with a couple of different scenarios and we're not going to get into what these tools are but we're going to focus our attention on this onboarding funnel and oh good there's some there's some data in here so here's here's the view that i have and i can't show you my real onboarding page because it has real people's information and i just don't want to disclose that stuff it's none of y'all's business and i don't think you care anyway um but this is representative of the kind of stuff that i see when i'm looking at the production site and the the difference is that this list is a fair about a fair bit longer but it is kind of representative of the the behaviors that i see in there and so what i've got with this onboarding dashboard and what this thing tells me is how much usage someone is actually using the tool if we were to go look at the app actually we can jump straight to the onboarding flow at any time by going to this start page there's a set of start steps that i guide people through and it's um they follow along and you know i've already completed this so most of these are going to be not very interesting because it's going to give the messages of you've already finished the steps because i'm coming back here after an account has been completed but a new user after they've signed up will go through these steps and it's going to create certain pieces of data it will create a school year a grade level a course and a task as you can see so if we look at this onboarding information you can see when the user account is created and you can see a school year a grade level a course and a task you know logical right the other two pieces of information that are critical in order for my home schooling app to work is a student who's actually going to be in the grade level and then an enrollment which is what the piece of information that connects the planning information for the home school school here with the student and basically he says you're now enrolled as a third grader in in this home school so once all of these pieces of information are filled in it's a it's a better indicator to me that someone is actually trying out the app but here's here's a good example of something i actually see quite often where this will be zeros across the board so what we see in this test data of slack test stripe trial and notify these are all things that i've made in my local dev database but i think they are good representations of what i would call a tire kicker in fact say the same with this no grade level if you haven't made all of at least one of all of these things it means you're not actually serious about the app you're because the whole point of of school desk is to provide scheduling information and generate a schedule automatically for a homeschool family and so if you you're not putting any tasks in here and all of these things before tasks are prerequisites for it then what are you doing um similarly if you're only building a school year and you never actually create a student and never connect it to the school year also what are you doing you're kind of playing around with the scheduler but you're not really in my opinion going to be a serious candidate for the app and this is true of the people that have actually signed up and paid for them there's really clear candidates of okay you're putting a lot of information into the app it's it's much more likely that you're going to sign up and actually start paying for the service so what i want to do is take this page and this information and i want to go the data behind it and actually filter on some of it and make this page a lot more concise because what i see like i said the the production site that i see has dozens of of these um over the the 60 day window that people can have for their trials and of those dozens only a handful are actually at this stage of the app really serious contenders for possibly signing up and people that i might want to reach out to and say hey is there anything i can do is there anything that the product is missing i want to highlight those people and not the ones that have just come in and abandoned the app so what we're going to do is go over this this code that is generating this data table and um we'll we'll annotate it and we'll put on um a bit of context data that will say you know who is a tire kicker and not i'm going to make that determination based on two factors it'll be you have to have at least one of all of these numbers the other thing that i want to consider as a tire kicker is how long they've had the chance so if someone has only been in the app for a day it's possible that they might still be a tire kicker or they might not maybe they just haven't had the time to enter the data in yet so i think i want to give people who are in the app for the first week the benefit of the doubts say like now there's still a chance you might actually put some stuff in here and become a real interesting person to follow um so i think those are the two kind of criterion that i want to use and what we'll do is we'll add that data the context it'll help us to show whether to render this information or not um success on this particular view is only this high i onboard account is the one that should remain after we're done and then we can add in i think we can probably also sign up with a new account testing for tire kickers and put in one that is recent because you can see all of these are quite old this is from april march like this this data in here is is rather old because i um on the stream i'm often using this the same testing account and i don't need to create a whole lot of accounts so um why don't we create that test data first and then jump over to the code and and take a look so i'm going to log out and i'm going to start a free trial here and scr create a maybe tire kicker and give that a password and this is the experience that you get when you first sign up with the app i make sure that you have an email confirmation when i'm doing local web testing though i don't send real emails which is hopefully evident but i do dump it out to the console so what we should be able to do is take this link and then go over back to the app and follow this and good it does the experience that i want people to have i want them to be dumped right into the start onboarding flow and then they can get going okay so that's it for this account we can now go back to the um the admin account and and take a look at it and we should see the new um account that we just created we'll go back to whoops not the office we want to go to the dashboard and come back to the phone funnel and we've got the maybe tire kicker here so this is the 28th as of this stream and so we've got someone who's just today which is a good kind of baseline for what we have so now we have representative data of the three major scenarios um well i guess this this scenario is really just a subset anyway i'm getting a little wrapped around the axle and semantics we have examples of people that we want to save and show and people that we want to ignore so let's go over to the actual code now and start working on this we're going to go to hold on well shoot don't worry about that that's some other code i was working on earlier let's go over to the core views i think is where i put this stuff and in here this is not a terribly complicated view so here's the whole view that we've got and i i didn't even optimize it in any way shape or form as you can see i've got a bunch of count queries or filtering on all this data and i know that this data is correct so we don't want to change any of that what we want to do is then these are user stats and it's got users so what i really want to do is i want to add a boolean here of if this is a tire kicker or not so what what constitutes a tire kicker um well we said i said that it needs to be someone who is beyond a certain um a certain age of their account so that could be someone who's like let's say more than a week so if you're more than a week and you still have an input all the data it's a pretty good chance you've you've abandoned the app at this point so we want that as to be like our threshold so in fact let's give it that name let's call it the tire kicker threshold and we want that to be time zone dot now um plus date time time delta of seven days so that's seven days in the future well really is that going to be the right thing are we really counting the past um well we'll fiddle with this this math i might be have i might have this logically backwards in my head but we'll see so we want to compare we only want to consider if someone is a tire kicker if their account is uh more than seven days old so we need to actually consider [Music] really okay i'm getting this this comparison backwards so we have got now and we've got when the um the person joined and my language is getting i'm trying to think of the variable name that i want to call this is not coming it's not obviously coming to me so the the cutoff we want to consider is the and that's that's what i want to call it tire kicker cutoff is probably a better name is and it's relative to the user so the user has a date um date joined timestamp i believe it is let me see if we get other examples in the app yep date joined is an attribute that the django user model adds when someone signs up the first time so that's the created date it's what actually shows up in the template we can also bring up the onboarding template it's probably in here yeah you can see it right there so it was one of the pieces of information that i was showing you on this page anywhere so this created column it's not the the name of the field is not created it's date joined so we've got date joined and then we can say um the cutoff is uh now the rest of this stuff so it's really what we wanted to put here so now we've got this cut off and this is not really the variable that we want to keep anymore so we want to compare if the current time is how that compares to the cutoff so let's calculate the current time outside of the for loop because there's no reason to calculate that every on every iteration of the loop and so we can say now is equal to time zone dot now so now we've got access to that variable and we want to say if now is greater than i think that's right i probably have i might have the less than or or greater than backwards but we'll try it and this is this is one of the things that's like i could figure out the time zone math and but it'd be easier to see it so if it's in this category then then this is something that we want to consider like you're now an old enough account that we should calculate are you a tire kicker or not and for the moment we'll actually assume we'll take the default stance that tire kicker i want to put it in here for all of them so it's it's something that we can always depend upon in the context so we'll say tire kicker and that's going to be a boolean and we'll say it's false by default okay so now we have this information and what do we need we need the we need all of these values to be greater than zero it's not i can't i was thinking we could just sum them but there could be like the one that is a for example there's the tasks one you or any of them if i in fact could have multiple of you so somebody could go in there and for some reason create a bunch of school years or create a bunch of grades but not do the rest so really it is about having at least one of each of these rather than just some summation of all of them which makes the makes this a little bit annoying to calculate i think and i'm going to think through if this is if there's a cleaner way to do this but i think what i want to do is try and put in the stupid version and get it working and then we can come back and think like is there a cleaner way to do this so we want to say um let's just do it all it's going to be if if user stats school year i want to actually see all this information there it is school years okay i was automatically going to get that wrong is um equal to zero and so this is where it's going to be it's just going to be a bunch of and kind of conditions in fact we can preempt and you reuse a bunch of code here and put a pass and do a bunch of these and so this is the format that it's going to look like and like i said there's probably smarter ways to do this and we'll get to that in a second like i'm already seeing a way that we could simplify this this is a lot of repetition as you might notice um so we want grade levels courses tasks [Music] students and enrollments and really it's not about being zero that's not right it's about um you have to be greater than zero no no no no getting this logic wrong we want the we want to identify a tire kicker so a tire kicker is where any of those is zero right so really it's if it's it's not and it's or if any of those is zero and you're past the time then you're tire clicker i think so at that point we want to say the user stats we can set tire kicker is equal to true uh oh shoot this was a list okay we need to give this a local variable phooey so we'll call this whole thing stats yep all right we'll call this stats we will out dent that change this to be appending the stats and now we'll change these user stats to just be stats okay all right now we've got the the data for an individual i didn't realize i thought the user stats was stats is one of these bad variable names that it could mean a group of things recommend individual because the statistics about one person anyway so we've got the stats for an individual now has this tire kicker and we should be able to go back in here and i'm going to start this with the debug toolbar this time because we want to take a look at the context data because i haven't done any work on the template yet so if we come back in here re refresh this page might take a while nope not as long as i thought and let's see if we were even close with the logic so our maybe tire kicker is false even though they're all zeros this one is marked as a tire kicker because it has one that has zero courses and zero tasks that's a tire kicker so the only one i think we got it cool so that's good and then um so let's let's uh let's continue to get like the context data right and we'll go modify the template and then we'll come back to the view and make sure that the view is accurate um and then we need to run the test suite with coverage to see that if i actually because i added a new if guard here and i we might need to write a test for it i don't know okay so coming back to the code the other thing that i want to be able to do is i do want to know how many tire kickers there there were like it's it is valuable to see like what is the how many what is the ratio of like real to not real people right now so now that we've calculated tire kickers we can say um we can add to this context dictionary we'll add the tire kickers tire kicker count and that's going to be the we can do a sum [Music] what's the easiest way to do this there's a length call yeah yeah okay let's do a length call on this for you in user stats if you tire kicker um what's the wrong with syntax oh closing okay so that should say like anybody that's a tire kicker we're gonna do a list comprehension and then by the time we're done with that we can do a length call there's probably a way that i could do this with a a generator and maybe a sum yeah i don't think we needed though so let's return over here try refreshing it and the count that i expect is one two three four five should be the tire kicker count that should be in the context well four why is it four oh oh no sorry this this first one was a maybe target they're two new so yeah four is right okay so let's set the view aside for a minute and let's come back to the onboarding template itself and just add any extra information so we'll say um after the table of stats we'll say a paragraph tag and um is there any real good-sized text in here yeah let's try it with what this is plus um tire tire kicker count tire kickers okay so that's the um that's the count there and that's good now we can give it some uh let's give it a little bit of padding so we'll say margin y of 4 that way it's just not right up to that table and that's all i will really need i think and then the other thing we need to do is we only want to show this [Music] if stats if not stats tire kicker okay that should just show the two cool so now we have our code and our template they're done now i could say that that's good enough and just stop um i don't what here's what i don't really care about this is that this is a like two nested if statements so we probably simplify that right away so let's do that first so let's change this to an and like that is this semantically equivalent the other bit we could do is what would be fun to do here um i could make this could be an any on a list comprehension so we could say it doesn't matter at this point no but it's just kind of fun to think about like can we make this simpler um let's say uh data what should this be data categories is equal to the keys now let's not call it categories let's just call it keys call it closer to what it is let's make a list of keys that is the things that we want to compare because what i'm looking at here is like the repetition between this is is very high so i'm trying to see if we can eliminate some of that repetition so if we put all of the things that we want to compare into a list and then then we do an operation that says for the moment let's comment this out because we know that works in case this doesn't work so if any of these comparisons of stats key for key in data keys so i think this is going to be like equivalent because we're com oops almost is equal to zero so if any of those are true then that's going to be the same as doing all of these or comparisons or or or because the or operator are short circuits right so i think we can get rid of this we'll just we'll continue to have it here just in case i'm wrong for some reason but i think what this does is it does pretty nicely clean up the comparison and i believe it should be the equivalent whoops um school well i said school keys that's not right school years so the keys still have to be correct all right so it's still the same logic right which is good uh and now we can delete this and black still made this longer maybe than i wanted it to be um i wonder if i shorten this with will it go nope all right so i'm not going to fight it so black just sometimes will take a list and it's better for a diff but i think in this case it would have been nice to have it on a single line but i guess it does make it easy like in the future if i do add more pieces of data that i want to constitute what's a tire kicker then perhaps perhaps that's a good structure anyway so we've got this simplified expression so if any of the things are equal to zero for all of these things in the statistics and the person has been around longer than the cut-off period of when they join plus sometime in the future then we want to consider them a tire kicker and then we've recorded that we've shown it in here the last thing to do on this before we can file this piece away is to make sure that there is appropriate test coverage i have a feeling that this particular line is not going to be touched for the tests that are there so we might have to write a test because in my app i make it so that i require 100 test coverage so while we're waiting for the test to actually run let's go ahead and go over there i probably have one called onboarding yeah there's no way there's there's enough data for any of these things so we have to we want to find we basically need to write a test that proves that there's a tire kicker will appear and i'm almost positive that'll fail it'll say like one line is missing yep 604 which is this line right here the x exactly the one we thought it would be so test [Music] marks tire kicker a tire kicker that is not using the app is marked for the context okay so now we need to come in here and we need to use this view and we've got our user this is the the user that's actually going to do the logging in and we need to create um what's going to be the fastest way to do this the fastest way to do this is going to be to create an enrollment because the enrollment is going to create a student and it's also going to create a grade level and a school year and then from the enrollment we can create a task and which will create the course and the task that's just that's from my knowledge of how the modeling is done for this app so we'll say enrollment is equal to the enrollment factory we don't care about the specifics of who it is and then we can say the course task factory has [Music] we this is where we do have to connect it it has to go to the course has the grade levels which is expects a list and then we can wire it together by saying the enrollment grade level so that's going to create a task and in the process because there's no course it's going the factory is going to create a course and that course is going to be wired to the grade level that's associated with the enrollment and then we want to i guess assert on some context and i guess the easiest way to do this will is going to be assert that the tire kicker count is one it's gonna be zero because i missed something which i'll get to in a second but we'll just write the assertion first assert that self get context tire kicker count is equal to one yeah it's zero okay here's what i missed um thanks stevens i appreciate that appreciate you tuning in too um i missed the fact that in remember in this calculation i said you you can't be someone that's already in this first week is not going to be considered a tire kicker so um what we need to do is then in the enrollment um make sure that the user that we create with these at the proper level has a date join that is in the past by a week so we need um uh let's say tire kicker cut off time zone now so we want to put this in the past um what is the vim add that creates the line where which line which line are you talking about uh shivens the pep the pep line i got a lot of lines on here you're gonna have to be a little bit more specific sorry the vertical line okay i'm seeing like black line black line yellow line um gotcha the that was something i added to my vim rc i'll get i'll show you in just a second let me let me get this bit of code put down let's just say days equal 8 just because that'll be a good time frame for someone that i i know is there and we'll use that variable in a second if we go to my vim rc so let's do a vertical split on my mrc and here we are my my vimrc and the line thing that i put in here is what do they call it i i do use you complete me for suggestions that's correct um here it is so it's the combination of these two things it's the let color column so i'm marking a column 81 as the so this is like pure like really hardcore uh python semantics i guess some people like although black you might notice black actually goes over this i don't know if i have any examples in this file like here's an example so the black code formatter actually picks picked 88 um and the 88 number apparently comes from some bunch of research at facebook that says um they looked at all their code all their python code and did did some comparison on when stuff would wrap when you had the black formatting and versus like wouldn't it be too long i don't really know if it was a really truly scientific process but the black formatter long and short of it is they picked 88 as the true maximum so i have some lines that will go past this column count but in a more um strict setting which some projects are they expect you to be like 79 characters or 80 characters probably 79. um so i i put mine technically at 81. so really this is i've got one one one characters worth of um gutter i guess and you can see that with color column here and then i changed i had to fiddle with the actual color then the color that i wanted to use for my color column um i could i could do this right now but i don't really feel like it right now um but you could you could find this if you want to look at this stuff and look at my specific vim rc you totally can i have this all online at my dot files and you can look at this so here i'll drop the link in the chat too so you have quick access to it um this is all the plugins that i use i am not super great about commenting everyone so this is kind of it's buried into this this is probably like if you did some archaeology on what is my um what is my vim rc like this is the oldest stuff this is the core right here because um a bit of history about me once upon a time i did not work in well i vote i guess i've always worked in the in in what's considered the private sector but i i used to work for a defense contractor um lockheed martin i didn't make bombs or anything i was working on satellite software like gps and stuff like that and in those environments um you wouldn't really have especially with like i had to go into some classified labs and nothing crazy it's just stuff that you know there are different classifications of stuff and naturally when you go into a classified lab lab uh you don't have connection to the internet or maybe this is not natural to you i don't know what country i think you're coming from afro somewhere like south africa or something so this may be not natural for you at all in the us in a classified lab which which is just a signifier for where programming can be done on classified materials you don't have access to the internet or you do but it's like really separated ah new zealand sorry i think there was someone or someone else something that was in south africa um but at any rate so there was like a the regular machines that were doing coding in the classified labs you you couldn't connect the internet which meant that um uh as a vim user i couldn't bring in all of my plugins and all of my stuff so back then i memorized basically what lines um 81 to 85. i memorized those lines those are my original vim lines and i didn't bother commenting it because i committed adult memory at some point though i left defense contracting and and got into like education technology for a site called storybird which was like teaching kids to write and write english and i started to expand my mrc and at some point i realized i should probably like start commenting and documenting and i got much much better about this in the future so there's this dark spot that i don't know why i've never gone back and actually made this readable to anybody but the rest of this is pretty well commented if you want to use it okay that was a little tangent hopefully that was helpful for you um all right cool very good um all right so what i was missing is the the kick cut off so we want to go into this enrollment now and dig into um the student and no not the student the actual user the admin of the school year so this is going to be a funky factory path to follow so the enrollment tears up and it has a grade level that's the thing above it let's just look at the model diagram so we call i'll see so you're not just taking my word for it um come on zoom zoom zoom there we go so at the base of this all oh i was gonna miss one anyway is the user this is the thing we want to care about to say like are you a tire kicker or not the enrollment though that we created to have all the necessary data is way up here so there's a quite a tree that has to traverse to get down to the actual user so we need to go user to school to school year to grade level to enrollment okay so at the factory level that's going to translate to user grade level school year school thankfully my autocomplete is filling in this for us and then we can say [Music] admin and then date joined is tire kicker cut off hopefully all that works there's a chance that the date join field is an auto ad now we might have to save it after the fact but we'll try this first hey he passed cool so that was right so we're the factory we're taking deep deep advanced knowledge of this structure to make this shorter than it might otherwise be so we've got an assertion that we're going here that gives me confidence that we've hit this true line and now we can do one last test of coverage and that should prove that we got the line so i think this will be pretty useful for me um as a as like the administrator to know who to reach out to because i have gone out and just as a way to engage with potential customers looked at folks that have said that i've clearly seen indicators of you have used the app quite a bit and sent them a cold email saying like hey i'm the actual person this is not some big corporate site just i'm a guy that's making a service for my family that i'm extending to other people and um that's been pretty well received from some of the people that i've seen so that it's a it's a good way to potentially help them convert into actual paying users ah sweet everything's working and 500 tests i've got one failed so the the thing that i worked on last week i don't know if you if any of you saw the stream um we're working through a weird scheduling bug i have the test that proved proves the weird scheduling bug but i haven't had time to fix it and so i i committed that as an x fail to say i'll come back to it but i didn't want to delete the test and i didn't want to have to deal with that in my git diffs for this stream so it's committed we've got our new test that proves that there's a tire kicker we refactored the stats to pull it out out of the list directly and so we have per user and then we do a comparison on the cutoff period and if any of these are do not have data then we add that to our stats and then we get the count as well in the template we only dump out the user if they're not a tire kicker and then we list the count of tire kickers so that's the feature and i will say filter tire kickers all right let's see we got 52 minutes according to my stream manager although i started a little earlier than that so that timing's a little different what else can we do i was talking to um my spouse who is the primary customer of my app and the next thing i think i want to work on is going to be more involved and this is one where it's kind of like changing you know making changes to the engine mid-flight which is always fun so let's look at the model diagram for a second i modeled so getting back to like the core of how the app works there is a schedule whoops let's actually look at it there's a schedule and the schedule is dynamically created and i've described in the past that it goes by indices of like what to look up for the table within the different database tables to pull out tasks to display part of that though is with this model of always dynamically building you have to be able to fill in the holes so if you go on christmas or pick your holiday hanukkah i don't i don't know whatever your religion is or if you're not religious just your your patriotic independence day for your country i don't care um there are days where your family would take days off and um if you i didn't want it to force tasks onto that day and for the users not to be able to do anything so one of the features of the application is to set your holidays or set your break days it doesn't have to be for a holiday it could be for any reason maybe you have to go to the dentist and your kids aren't going to do school whatever and here's an example of one of these break days the breaks are in here as a start and end so it can be multiple and you know they can optionally put in a description one of the features requested by my spouse is an ability to put in field trips and as i was thinking about what a field trip really is it in a bunch of circumstances most circumstances maybe is really just a break day with a different coat of paint on it to say like it's for it's for school but it's still not doing school in the same kind of way not doing traditional classroom work i guess but there was a problem with my current modeling of school breaks and that problem is that the school breaks assume that it's for your entire school so i've got two children in my house this week is actually a a great example um my daughter happens to be going to dance camp this week my son uh went to tennis camp a few weeks ago and while one of them is away at one of these particular camps the other one's actually doing school so the way that this is currently modeled in the system as a break i can't my my spouse can't actually put this in as a break because it would prevent my son from doing any work because it just kind of filled up the schedule for both students and so that brings about the need to be able to make breaks specific to the actual students and in practice that's it would it's it's very natural to want to split them out this way because if we go back to the week schedule it there's always there's always a separation in how i'm displaying the schedules for the week there's so there's one student and then there's another so this is my son this is my daughter and um so it could sen it makes sense that i could say all of these could be marked as a break for my daughter and then my son could still continue to do his work this isn't my son's real school work this is junk data this is but those are my kids names um so i need to update the modeling of this school break to factor in students and i think what that's going to do is going back to that school year page and looking at the particular break there's going to be some interesting implications here if i model with a student then what does it mean to do to edit a break here it what's going to have to change about this form in particular is we're at minimum going to have to show here all your students um the other thing that we would have to do is well there's a bunch of there's a bunch of things that scenarios that pop up with this actually um yeah let's let's go let's start writing down like the different use cases for this so the the core goal is make it possible to schedule breaks per student that's that's the goal and then we can write down the different kind of use cases that we can think of of what we'll have to fix so make school breaks work per student now what i don't want to do is if my family goes on vacation i don't want to make it so that my wife has to put in the same break twice once for each student you can imagine an even bigger family and there are lots of large homeschooling families out there a family with eight kids that would be horrible if like you're going on a family vacation and whoever is the educator in the house has to put in the breaks for each of their kids that that would be terrible so one of the requirements is that it has to be a unified view of school break editing which translates to some check boxes so check boxes per student um the other thing that's going to have to happen so that that's at the like the user layer that's what the user will have to experience the implementation layer is different or well there are a couple ways we could do this let's let's think through some options um the option i'm most likely leaning towards is a foreign key to the student model for a school break that's that's what i'm most that was the the default path that popped into my head but as i am sitting here thinking there are other ways to do this another way to do this would be to use kind of some kind of unstructured data and we could say that how else can we do this because the implication of this is of having a foreign key is to school break is like if you have a unified model then you'd get even on a shared so a shared break would create two school breaks one for each student one um i'm assuming two students here in my example would create x school breaks one for each student with x total that's horribly stated but i think you get the idea that it would multiply that way that's one kind of modeling the other way we could do this is and i don't know if it's any better i could be better would be to have a many to many relationship here let's let's talk it out many to many what would that look like so that would give you the ability to create um this is actually sounding better to me as i'm writing it out it would be one school break so you'd still get that single interface but if you had the check boxes you could have um [Music] i don't know what the other things would be called um a school break student um or a student school break maybe the advantage of that is that if you did that you only have to update a single instance so let's say you the standard case where you're going on family vacation and both both of my kids are going on on vacation we want to mark one school break and um you know my wife adds a description and says going to the beach something we don't we're actually big beach people but um we're going somewhere and then um just trying to think about the the editing case of what that would look like if we had just this this modeling right here with a foreign key then if she changed it so we're going to a beach in new jersey or something like that um then like it would have to go in and create and modify the text the description text of each school break with the many-to-many relationship instead then there would be one place to edit it's more uh normalized and that's a good thing but there are some downsides to this approach so like so in sedan so to its credit this is more it's a more normalized than a foreign key there's only one place to edit a description for instance the downside of this is that i think it's going to be a little harder to query so i'm gonna have to change like a bunch of the apis in my app right now so right now i'm checking i go in the code let's let's look at some code rather than me talking through it let's look at the school models i think that's where it is attached to the school year is this method right now is break and his break is great when breaks are global to an entire school or an entire school year as they are currently modeled right now what this does is you can see this is the interface returning a boolean and it checks if the school year has a break for that day and this school breaks by day is a filter where it goes and looks at all the school breaks on the school year because breaks are attached to a school year specifically now you can see where this is going to break break down because what is a break to my son versus my daughter might vary and in a future where um where we have this this ability to split on a student the part that i'm i'm a little hesitant on is the the many to many might complicate this is like we might have to not only look up the breaks for the school year but also have a separate lookup table onto all the many to many maybe that's not so bad maybe that's actually very handleable because what's going to have to change about this at minimum is the the is break method is going to have to like expect a student and it either will have to expect a student or just assume that any break will suffice which i think is going to be a pretty bad assumption a lot of times maybe not so this this api is going to have to change in some way so that when the schedule is being built because it does calculate and factor in this is break stuff um that that student is part of that calculation so i think i think this might be where i want to leave this tonight but so this is what we're going to be working on and frankly i haven't had a lot of time to work on school desk outside of the stream so it's very likely that we'll pick right up here uh next time on the stream i will give a good think on whether i prefer this this pure foreign key approach or the many to many um now that i've kind of talked it through i might be convincing myself of a more normalized approach with the many to many because that might be [Music] easier to manage in the long run and just better database modeling overall um outside of this particular database modeling so what are some other challenges that come about because of this um this is a modeling that if at minimum we went with a foreign key attach attaching a student foreign key to the school break model in that scenario we would actually want to have the student be a mandatory key you would not want that to be nullable you would expect there always to be a break associated with at least one student and you'd ha because the site is already live and there already are existing breaks you can't just add that as a non-nullable and expect it to work because the the migration would not have the necessary data to fill that in i mean i could go in there and write a data migration that pulls the first student but that wouldn't be accurate because you know right now the assumption is that breaks apply to a whole family so i would have to go in there and make the migration um do a data migration that would include all of uh one one school break per student at that time and so that's possible but there's there's just migration considerations that that would have to be considered for this kind of change and it's the kind of challenging stuff that happens when you have real data thinking through how to migrate safely is actually a pretty big problem um and this is not a unique problem to django just just to be clear this is a problem for any any web application but knowing some of the patterns and things you have to consider as you go through that process is is useful and something that i've done a fair amount of so we'll have to consider a plan here and and work through that the interesting part about this as well if i go to the menu to many handling is going to be i think there's fewer database modeling constraints there and and migration constraints but there will be interesting stuff for you know what do you do when somebody unchecks all of the students can can they do that can't they be allowed to do that or are they going to have is an expectation that they will always have one at least one checked and and also all sorts of stuff like that so we're going to work through that and and make this happen and from there so once we get school breaks this is kind of the phase one is make it possible to make school breaks um appropriate for per student and then the next phase beyond that is to put that new coat of paint on there and make it possible to identify those as a field trip um maybe that that might mean like connecting it to a particular course i'm not really sure what my spouse is looking for she's the one kind of as my a product uh representative or my customer who's driving that so once i have this capability and cut return to this conversation with her about what does it look like to be a field trip and how's that going to work so i think that's kind of the the next half of this project is is making that that all work and and fit into the product and fit nicely and and give um nice places to add in field trips and and make that something that can be reported on and a really interesting part of this whole process that's my plan um i will take this content and post it up on youtube like i usually do in case you missed anything and want to check it out appreciate you tuning in uh if you haven't already please um follow uh follow is that the right word on here on twit twitch i can never remember like subscribe comment follow whatever the thing is you're doing wherever you're catching this i appreciate that and with that i want to wish you all good night take care
Info
Channel: Matt Layman
Views: 180
Rating: 5 out of 5
Keywords: twitch, Python, Django, SaaS
Id: brUXxtIhaOc
Channel Id: undefined
Length: 67min 27sec (4047 seconds)
Published: Thu Jul 29 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.