RESTful and HTTP APIs in Pyramid Transcripts
Chapter: Adding a database backend with SQLAlchemy
Lecture: Concept: SQLAlchemy building blocks
0:01 Let's round out this database section
0:04 by focusing on some core concepts around sqlalchemy ORM.
0:07 The first thing that we did was we created a declarative base,
0:10 remember this is a factory function that will create a type
0:13 and this type will then be used for all of the base classes
0:17 of all the models that we want, all the objects we want to store in our database.
0:21 So, we come over here and we say
0:23 sqlalchemy.ext.declarative.declarative_base (),
0:26 call that function it will generate a type,
0:29 now this single base type when you derive from it
0:31 will register that hey here's another type that I'm going to manage
0:34 so for example, if we have a class car
0:37 that derives from sqlalchemy base and service record and
0:40 owner we can go to sqlalchemy base this type we just generated
0:43 and say create the database structure to deal with
0:46 and manage and store all the things that you are derived from.
0:50 So this is usually the first step in the modeling side of things.
0:54 Now, once we want to create these individual classes
0:57 that model the data in our database,
1:00 we're going to of course as we saw it derive from sqlalchemy base
1:03 and then add a bunch of columns here
1:05 and these column types are both at runtime instances of the value they represent,
1:10 so at run time the id will be an integer, but at design time or query time
1:15 they will act more like schema descriptors, ok.
1:20 So the way it works is we name all the fields,
1:22 so id, name, year, price, image and so on,
1:26 each one of those is a column and then we can configure that column
1:29 like the id is an integer, the name is a string, the price is a float and so on,
1:33 we also should indicate which one is the primary key, so id is a primary key,
1:37 and since it's an integer, we might want it to just be managed in the database
1:41 so we can say auto increment equals true,
1:43 as soon as we save it a new id will be stored there for that record.
1:47 Notice also we didn't talk about it in this chapter
1:50 but sqlalchemy represents and models relationships with cascading deletes,
1:56 lazy loading, all sorts of stuff, so if you need to model relationships
2:00 be sure to use the sqlalchemy structures to do that.
2:03 Now, sometimes we would explicitly set the values
2:06 and sometimes we would like the system to just generate them;
2:10 an example we already saw was that auto incrementing primary key
2:13 the default values, you know, whatever the database decides
2:16 the next id number it's going to be but, what if we have some other type,
2:20 for example, what if we want to have a last seen field
2:23 and if we're updating the car in the database,
2:27 maybe we want to manually set this last seen
2:29 but the very first time it's totally reasonable to say
2:32 well we just put it in the database so we're seeing it now
2:35 we shouldn't have to explicitly set the last seen value
2:37 which is if you create a new one, its value is when it gets inserted,
2:40 so how do we do that in sqlalchemy, we can set a default on the column
2:43 and that is going to be a function that returns the right type of value.
2:47 So here we have our last seen, it's a datetime
2:50 and we're going to pass the new function,
2:53 so remember, don't call the function don't say datetime.datetime.now ()
2:57 that will actually just basically give you
3:00 a default value of whatever the time the program was run,
3:03 you would like this function now to be called during inserts
3:06 so make sure you leave off the parenthesis,
3:09 you can see that it doesn't have to be a built in function
3:11 it could be like some kind of lambda,
3:13 so what if we want an interesting primary key that it is basically the uuid4
3:16 32 characters or something like that without the dashes
3:19 so we can specify a specific lambda expression
3:22 it takes no arguments and returns the right types,
3:26 here we're returning a string into our id column
3:28 which we've now adapted to be a string.
3:30 We also should add indexes and keys,
3:32 we've already seen primary key that makes a lot of sense
3:35 so primary keys automatically have indexes
3:38 but if we would like to say go to our database and say show me all the cars
3:42 and show me the ones that are last seen latest,
3:44 so some kind of sort on the last seen field;
3:47 or show me the cars that have only been seen in the last week,
3:51 then we want to make sure we add an index here
3:53 and all we have to do is say index = true and sqlalchemy will manage that for us
3:57 but indexes dramatically improve performance when you have lots of data
4:02 so it's very very important if you want your database to be responsive
4:05 you have indexes for anything you're going to sort by, or you're going to filter by.
4:12 Now we can also enforce uniqueness constraints
4:15 so we didn't do this in this sample because I'm not sure about the data set
4:18 but imagine the name of the car somehow had to be unique, right
4:21 we could have an index that is also a uniqueness constraint by saying unique = true,
4:26 then if we try to insert a car that has the name that already is in the database
4:30 it will crash and say no, no, no, you're going to conflict with this, things like that.
4:34 The common use case might be e mail address for a user's table.
4:37 Right, now once we have it all modeled,
4:40 how do we create the tables in the database,
4:42 so one thing that we didn't have to do, it's kind of strange
4:46 sometimes you have to do this sometimes you don't,
4:48 it just depends on how you interact with your code
4:51 before you run this create all step here,
4:53 sometimes it's important that you explicitly import the types
4:56 that are going to be modeled in the database,
4:59 so here we're doing import car, import owner, a bunch of other imports potentially,
5:03 because if for whatever reason those modules
5:06 have not been loaded by the time you call sqlalchemy base metadata.create_all
5:10 you are not going to have that table, it's not going to create it,
5:12 so you have to kind of show the sqlalchemy base type those things
5:16 and the most reliable way to do that is just to explicitly import them in this particular file.
5:21 Then we need to create a connection string
5:24 our example use sqlight so we use sqlite:/// some file
5:27 and if it doesn't exist it will automatically create that, and then we create an engine
5:31 and the engine is a thing that does connection pulling and things like that;
5:34 you can say echo = false which makes it quiet,
5:37 or echo = true and it will spit out all kinds of information
5:40 about what it's doing, that's good when you're getting started,
5:43 you're not really sure what happens when,
5:45 flip that to true, watch it for a while get tired of it, turn it back off.
5:48 Once it's all ready to go, you can say sqlalchemy base,
5:51 go to the metadata and say create all,
5:53 pass it to the engine so it can find the database
5:55 and it will go and create all the tables, indexes, columns etc.
5:58 And then, you're off to the races,
6:01 you have a database that maps exactly to your schema.
6:04 Now, remember create all only makes new things it does not update
6:07 so if you make a change to car after the table exists,
6:11 that change will not be moved to the database,
6:14 you got to manage that directly in the database.
6:17 Finally, if we want to talk to the database,
6:19 we're going to need to use this concept of a unit of work,
6:23 in sqlalchemy, the unit of work is manifesting this thing called the session factory
6:28 so we're going to need to create a session factory
6:31 and that is created by calling this function session maker
6:36 and passing the engine, so this is basically where the session factory
6:40 it will behind the scenes manage the connections and the unit of work
6:45 and the transactions and all that kind of stuff,
6:47 so we give it the engine that we just work with these sessions.
6:50 So once we have this, we have one of these in the entire program
6:52 one instance a session factory basically per connection string.
6:55 Then, every time we want to do a unit work,
6:59 a couple of queries and insert an update, and delete
7:02 and put that all together and commit or don't commit that
7:05 we need to use this session factory, so we'll say session of factory and call it,
7:08 it's a callable, and it's going to create an instance of this session
7:11 we'll do things like ads and stuff, do some queries, maybe add some more things,
7:16 change some of the items that came back from the query
7:19 and then when we're ready to push to the database, we just call commit.
7:21 If you don't want to commit this work, right
7:24 if you only did a query there's no reason to commit it back, there's nothing to save
7:26 you might as well just call session.close,
7:29 so that's a pretty quick whirlwind tour of sqlalchemy,
7:32 but it shows you the vast majority of the moving parts
7:34 and I think you're ready to get started with sqlalchemy.