You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

339 lines
15 KiB
Plaintext

00:00 So, we have cages.
00:02 We have available dates in cages, and we have snakes.
00:05 Time to book a snake into a cage
00:07 on one of those available dates.
00:08 This turns out to be one of the more complicated things
00:10 we're going to do in this application.
00:12 And there's a lot of input, and juggling, and stuff.
00:15 So I'm going to paste a few things here
00:17 just about asking questions about the dates and stuff.
00:21 And then we're going to go and write
00:22 the database queries from scratch.
00:25 So let's start here.
00:26 We're going to start by making sure you have an account.
00:29 And then we're going to get all the snakes
00:31 and make sure you have a snake,
00:32 because having an account is not enough.
00:34 You also have to have a snake you can put into there.
00:36 We're going to ask some questions
00:38 about when do you want to do this.
00:39 We're going to use Python "dateutil" to parse that.
00:43 So just like before, we're going to do a little error handling
00:45 to make sure you're not trying to book some sort of
00:48 reverse thing like I check out before I check in,
00:53 something like this, right?
00:54 Okay, so then the next thing we need to do
00:56 is find out the available cages.
00:58 And this is where it gets interesting.
01:00 So we're going to write a function called get available cages.
01:02 We're going to take the check in, the check out, and the snake.
01:06 We also need to figure out which snake you want.
01:09 So first of all, let's do an enumerate,
01:11 lift out your snakes,
01:13 and we'll say snake one this, snake two is not,
01:16 and you'll pick the snake, okay.
01:18 So, take our snakes, pick that, got our time
01:22 and then we're going to go to the database
01:23 and find particular cage that we can work with.
01:28 Now, that's not all there is to it.
01:29 So this is just going to get us the cages
01:31 that could be booked, and then we have to ask,
01:34 that's this little section right here,
01:35 and we have to let the user pick a cage,
01:37 and we'll find the underlying booking behind it.
01:40 So let's write this function.
01:41 So this can be a date-time and a snake.
01:51 You, of course, don't have to put the tie pins.
01:53 But I find at the data access layer,
01:56 it's really helpful, maybe through,
01:58 you can see it through the rest of the application,
01:59 we're not doing this.
02:00 But at the data access layer,
02:02 I find it really helpful to say
02:03 these are the things that go in,
02:04 these are the things that go out.
02:05 This is how we're working with the database.
02:08 Okay, so here's where we get down to business.
02:11 We're going to come in here. Let me move this up for you.
02:13 So we need to do a couple of things.
02:15 We need to find all the cages that have bookings,
02:19 that are not booked between this time and that time.
02:23 All right?
02:24 And we need the snake information,
02:25 because not all cages allow poisonous snakes,
02:29 and they don't all necessarily fit.
02:31 If I have a 20 foot snake, I can't put into a two foot cage.
02:35 So let's just do a little quick rule of thumb to say,
02:40 if your snake is four times longer or more than the cage,
02:45 then the snake can't go into it, right?
02:46 Snakes can curl up, but they can only curl up so much.
02:48 So we'll say something like, the minimum size of the cage
02:51 that we're going to get is "snake.length / 4"
02:55 This is going to be part of our query.
02:58 The date's going to be part of the query,
02:59 and whether it's venomous or not.
03:02 We're going to do a few interesting things here.
03:03 This is definitely part of the more complicated queries.
03:06 So I'm going to go to the cage, and we'll say objects.
03:08 And when you have these compact queries,
03:11 I find it's nice to spread this across multiple lines.
03:13 Well, I'll say ".filter"
03:15 And on multiple filters the are effectively and
03:18 I'll say square meters.
03:21 Now, I'd like to say, let's say
03:23 "=min_size" or greater, right?
03:25 Just like we saw with the operators about in,
03:28 there's one for greater than or equal.
03:30 And we can say, the square meters
03:31 are greater than or equal to this minimum size.
03:34 But that's not the only thing that we need.
03:36 We also need to go and do another pretty wild thing.
03:39 We want to go to the bookings.
03:41 Now, remember, refresh, over here we have a cage.
03:44 The cage has a bookings field.
03:46 We go to the definition for bookings.
03:48 Bookings have a check-in date and a check-out date.
03:51 We want to work with that.
03:53 How do we do that in MongoEngine?
03:56 We come over here and we can traverse
03:57 that hierarchy with underscores as well.
03:59 So we can say bookings.check_in_date,
04:02 and we want to have the check in date
04:06 before or equal to the check in that those passed, right?
04:10 So the time you can check in has to precede
04:13 the time this person is checking in.
04:16 And then we'll do something similar for check-out.
04:22 Okay, so this is part of the query.
04:24 Now, if the snake is poisonous,
04:27 we also want to say that they allow poisonous snakes.
04:30 So we'll say this, we'll say if "snake.is_venomous"
04:33 we need to augment this query.
04:35 So we can do that because it hasn't executed yet.
04:38 It's like the potential to be executed.
04:40 So we can say "query = query.filter"
04:43 and is thing "allow_dangerous_snakes"
04:47 That's what we want to work with.
04:51 "=True"
04:52 Because non-dangerous ones can stay
04:54 in cages that will either allow
04:56 or not allow dangerous snakes.
04:57 But if it's venomous, we have to
04:59 have this additional criteria.
05:02 And maybe we want to have some kind of order by,
05:04 like we'd like to show them the cheaper ones.
05:06 So let's go like this.
05:07 We'll say "cages = "
05:09 and we'll finalize the query like this.
05:11 We'll say "query.order_by"
05:16 Now, you don't do this sort of default
05:19 of this named parameter type thing for this.
05:22 We want to order by price.
05:24 And default is ascending, so cheapest ones first,
05:27 and maybe you want to see the biggest ones first as well.
05:29 So we'll say square meters, like this.
05:33 So we're going to say, first order by price, lowest to highest,
05:37 and then show us, if the price is the same,
05:40 show us the largest ones at that price level
05:44 down to the smallest ones.
05:46 Excellent.
05:47 So this is pretty much working.
05:50 It turns out it looks like it's going to completely work,
05:53 but it turns out that there's a challenge
05:55 we're going to run into.
05:56 And in PyMongo this is straightforward to solve,
05:59 although, you have to use a lot of operators,
06:00 these dollar operators to make it work.
06:02 But I haven't found a good way in MongoEngine.
06:04 And so I still find the on balance
06:06 that work with MongoEngine, even for this query, is better.
06:09 But here's the problem.
06:10 What this query is asking.
06:11 You're probably thinking it looks right.
06:14 It takes a moment to realize
06:16 the challenge we're hitting here.
06:18 What this query says is, go to the cage,
06:21 and find me the cage where the square meter is
06:22 at least minimum size.
06:24 That's totally fine, that works perfectly.
06:26 And it says, show me where there's a booking
06:29 query within check out.
06:30 And there's a booking, oops, this should be greater than.
06:36 That was almost an error.
06:37 So where there's a check-out date passed,
06:41 equal to or passed where I'm willing
06:42 to check-out for my snake.
06:45 The problem is if I have, let's say,
06:47 20 bookings in this cage, right,
06:51 I probably want to check one more thing,
06:54 but I can just check it.
06:55 Damn, we're going to have to do one more bit at the bottom.
06:57 But the problem is, what if, there's two bookings?
07:03 One that starts way in the past,
07:05 but the check-out is one day later.
07:08 And then there's another one where
07:10 the check-out date is way in the future,
07:12 but you can only check-in one day before.
07:14 And these are not the same bookings, right?
07:16 There's a booking where the check-in date
07:17 is before the check-in,
07:18 and there's a booking where the check-out date
07:20 is after the check-out,
07:21 but those are not the same.
07:23 You need to say, there's an individual booking,
07:26 not like some set of bookings where one matches one clause,
07:31 and the other matches the other.
07:32 So the way you do that in Mongo,
07:35 is you say, dollar element match.
07:37 I think it's "$elemmatch"
07:39 So element match is the description of the thing.
07:43 So you can say, it must have both of these.
07:46 But I don't see how to do that in MongoEngine.
07:48 It seems like it should be possible,
07:49 it certainly is possible for equality.
07:53 But for these operators plus element match,
07:56 didn't seem to work for me.
07:57 Anyway, you figure it out, feel free to use element match.
08:00 I didn't, so I've got to add one more line here.
08:04 And I'm just going to copy that over real quick,
08:06 and we'll talk about it.
08:07 So what we're going to do is we're going to say,
08:09 let's go and actually, these are the cages we care about.
08:13 I'm going to iterate over the query, which executes it here.
08:16 And remember, the cage,
08:18 each cage contains a number of bookings.
08:19 For each booking, I want to check that both
08:23 the check-in is before and the check-in is after,
08:26 and that the snake ID is none.
08:29 So it's not already booked during that time.
08:32 Though if it's both available,
08:34 and the check-in check-out date matches,
08:38 then we can make that part of our final cage there,
08:41 the final cage list.
08:42 Okay, so, and it says it returns this,
08:45 but actually, what it returns is a list of cages.
08:49 There we go.
08:50 Okay, so that's what we got to do.
08:52 If I could get element match to work with
08:54 greater than less than in MongoEngine,
08:56 this would not be necessary.
08:58 You could just straight up run that query.
09:01 But anyway, it's not a huge deal.
09:03 Remember, this set is already filtered down to where,
09:06 significantly, right, where the check-in and check-outs
09:09 do match, it just happens to be
09:11 maybe one more thing is missing there.
09:13 Okay, so we're getting available dates.
09:15 So let's come back to our guest here.
09:17 We've got our available cages.
09:19 Now, we just have to like show them to the user,
09:22 and let them pick it.
09:25 All right, so this just takes some
09:26 pre-written code for this.
09:27 There are a certain number of cages available,
09:29 and we're going to enumerate over them.
09:31 And don't need the average radian right now.
09:42 Do it like this.
09:43 We're just going to print out the name, the square meters,
09:44 whether it's carpeted, and whether or not it has toys.
09:47 We want that to be true-false.
09:48 So let's put that "yes and no," more friendly, right?
09:51 And if there's no cages, "sorry, there's no cages."
09:54 But if there are, we'll ask you which one,
09:56 and we'll pick that out in a zero based, of course.
10:00 And finally, the final thing to do is going to be book a cage.
10:03 And then actually, we'll just give out
10:05 this nice little success message saying,
10:08 "Hey, you booked it for this time."
10:10 So last thing to do with this booking a cage
10:12 is to actually book it.
10:17 So let's go over here.
10:18 Put my term, write it one more time here.
10:21 And now, what we're going to do is
10:23 we're going to loop over that cages booking.
10:27 So the way it works is, they've selected a cage.
10:31 They haven't selected the individual booking.
10:33 So we just have to go one more time over the bookings,
10:35 and go, let's find a booking within this cage,
10:38 which we know exists because it's in the list,
10:40 and let's assign it to the snake.
10:43 So we'll do something like this.
10:44 We'll come down here, and we'll start up by
10:46 sending this little booking to nothing
10:49 just in case for some odd reason we don't find one.
10:52 I'm going to go through and, again,
10:53 do a similar test as we did right there, right?
10:57 We got to find the available booking within the cage.
10:59 We know it exists, but we got to find it.
11:01 Then down here we're going to just set a few things.
11:04 Say the "booking.guest"
11:08 and get a little telesense auto-completion if you want.
11:14 Set the guest owner ID.
11:18 I guess we probably got to pass the account as well.
11:23 We'll say "account.ID"
11:27 Say booking dot
11:34 Set the booked date.
11:36 It was booked right now, regardless of when the booking was.
11:40 Then we also need to set the snake.
11:47 There we go.
11:48 And then we got to go back and save it,
11:51 but remember, we don't call save there.
11:53 We call a "cage.save()"
11:55 Okay, excellent.
11:56 Now, I think it just believes that's a misspelling,
11:59 but I'm going to say it's not.
12:01 All right, so that should let us book a cage.
12:04 That was a tough one, right?
12:05 So pretty interesting query.
12:08 We're using the operators, greater than less than.
12:11 We're traversing the hierarchy.
12:13 And like I said, that we're sort of effectively
12:16 in memory applying this element match.
12:18 Element match works in MongoEngine,
12:20 but I couldn't get it to work with both
12:22 element match and the operators.
12:24 So anyway, this will be fine.
12:27 Come down here and given a cage, we'll pull out the booking.
12:31 We probably could structure it slightly differently,
12:33 so we could skip this step and somehow
12:35 capture the booking directly, but this is fine.
12:37 It works plenty fast forwarded.
12:39 Set the, hey you booked it, values of the booking,
12:43 and call save.
12:44 All right, I think it's time for us to test our book a cage.
12:49 And I notice I almost forgot to add this here,
12:52 "state.active_account" I added it below.
12:55 So let's go ahead and run this.
12:57 And we'll come in here, and we'll be, oops, be a guest.
13:01 And let's go ahead and log in.
13:06 And let's see our snakes.
13:08 So we have these two snakes, neither of them are venomous.
13:10 Let's book a cage.
13:12 I'm going to start by booking this.
13:13 Now, how do I know that date?
13:15 Cuz over here, we have two available bookings
13:20 for the large boa cage,
13:21 and these times one to six in January.
13:25 So we'll go two, let's say two to four.
13:27 It should be fine.
13:29 This four.
13:32 And it says which snake, remember,
13:34 it matters the size of the cage and snake,
13:37 as well as whether it's venomous.
13:38 So we'll pick slither.
13:40 And hey, look, the one cage is here.
13:41 So let's say, all right, let's book it.
13:44 We've successfully booked the large boa.
13:48 All right, now we haven't written view your bookings,
13:52 but we do have that, I believe,
13:55 we might have that for the other one.
13:57 Go over here as a host, and we log in as Michael.
14:01 I think we might not have implemented this as well.
14:04 But we can list our cages.
14:06 Yes, there we go.
14:07 We can see that we have two cages,
14:10 Bully's cage and large boa.
14:12 And look at this, somebody has booked this one,
14:16 this slot, for the large boa cage.
14:18 Yes, so it looks like that worked successfully
14:21 just like we expected.