Full Web Apps with FastAPI Transcripts
Chapter: Appendix: Modeling data with SQLAlchemy classes
Lecture: Connecting to our 'database'
0:00 Before we can interact with our packages
0:02 and query any or save them to the database
0:04 or anything like that, we're going to need to
0:06 well, connect to the database.
0:09 And a lot of the connections and interactions
0:11 with the database in SQLAlchemy
0:14 they operate around this concept
0:15 of the unit of work.
0:17 Construct inside SQLAlchemy that represents the unit of work
0:20 is called a session
0:21 and it internally manages the connection.
0:24 So with that in mind, let's go and add a new Python file
0:27 called db_session.py.
0:30 So in this file, we're going to get all the stuff set up
0:33 so that you can ask it for one of these sessions
0:35 and commit or rollback the session and so on.
0:37 So we need to create two basic things.
0:40 We need a factory, and I'll just say None for the moment
0:44 and we need an engine.
0:45 Now the engine I don't believe we need to share
0:47 but this factory we're going to need
0:49 to somehow keep this around right
0:51 this is kind of we'll use the engine
0:53 to get the factory and so on.
0:54 So let's go and let's create a little function here called
0:58 global_init(db_file: str) and we're going to use SQLite.
1:02 It's the simplest of all the databases
1:04 that are actual relational, you don't have
1:06 to set up a server, it just works with a file
1:08 but it's a proper relational database.
1:10 The way we do that is we pass in a db_file
1:13 which is a string.
1:15 So what we want to do is work with this
1:17 and see if, this has been called before
1:19 we don't need to run it twice
1:21 so we'll do something like this.
1:23 We'll say first let's just make sure
1:24 that's global factory - we'll say
1:25 if factory: return.
1:27 No need to call it twice, right?
1:29 But, if it hasn't been called
1:31 let's do maybe some validation here.
1:33 We'll say if not db_file or not db_file.strip()
1:42 it'll raise some kind of exception here, like
1:48 right, something pretty obvious.
1:49 You have to pass as a database file
1:51 otherwise we can't work with it.
1:53 Then we're going to get an engine here.
1:55 The way we get the engine is from SQLAlchemy
1:57 so we're going to have to import sqlalchemy.
2:00 Maybe we'll stick with this as sa
2:03 so here we just say sa.create_engine.
2:05 Super simple. Notice the signature here though
2:09 *args, **kwargs". I utterly hate this pattern
2:12 it means, you can pass anything and we're not going to help you
2:15 or tell you what could possibly go in there.
2:17 In fact, there is a known set of things you can pass
2:20 in here, so they should just be keyword arguments.
2:23 Well, anyway, that's the way it goes.
2:25 So, we're going to pass a couple of things.
2:27 We need to come up with a connection string
2:31 and when you're working with SQLAlchemy
2:33 what you do is you specify the database schema
2:36 or the type of database that's part
2:37 of the connection string.
2:38 So we'll say sqlite:///
2:41 and then we just add on the DB file like this.
2:43 Maybe just to be safe we'll say "strip", just in case.
2:48 That seems like that's a pretty good one
2:50 and then here we'll just pass the connection string
2:51 as a positional parameter, and then we
2:53 also may want to set this, so I'll go ahead
2:55 and like prime the pump for you.
2:57 I'll say "echo=false".
3:00 If you want to see what SQLAlchemy is doing
3:03 what queries it's sending, what table create statements
3:06 it's sending, stuff like that
3:08 you set this to "true", all the SQL commands sent
3:11 to the database are also echoed out
3:13 both just standard out, and standard error, I believe.
3:18 But I'm not going to show that, but just having this here
3:20 so you know you can flip that and really see what's going
3:21 on here. So we're going to set the factory here
3:24 but what we need is we actually need
3:26 import sqlalchemy.orm as orm
3:31 So we come in here and we say orm.sessionmaker
3:35 session... maker.
3:37 So this is a little bit funky, but you call this function
3:40 and it creates a callable which itself
3:43 when you call it, will create these units of work
3:46 or these sessions.
3:48 So we got this little bit of a funky thing going
3:50 on here, but then we also come in here
3:52 and we say "bind=engine".
3:55 So when the session is created
3:58 it's going to use the engine which knows the database type
4:01 and the database connection, and all that kind of stuff.
4:04 And that's pretty much it!
4:05 We're going to use this factory after everything's
4:08 been initialized.
4:09 We're actually going to do a couple of iterations
4:10 on this file to make it a little bit better and better
4:12 as we go, but let's not get ahead of ourselves.
4:15 I think this pretty much does it
4:17 so let's go ahead and call this over here.
4:21 Let's go - here we are, register_blueprints
4:23 like, setup_db(), let's have just a function down here...
4:29 So let's go ahead and create a data folder
4:33 not a data data, but a DB folder.
4:35 In here is where we're going to put our database file.
4:39 So what we need to do is work with the OS module
4:42 and we're going to actually figure out where this is.
4:44 So we want to say "durname", "pathoutdurname"
4:48 and we're going to give it the dunder file for apps.
4:51 So that's going to be the directory that we're working in
4:55 so right now we're this one, and then we need
4:57 to join it with DB and some file name.
5:00 Let's say "DBFile" it's going to be "OS.path.join"
5:06 this directory with "db" with some database file.
5:10 Let's just call it "pypi.sqlite".
5:14 The extension doesn't matter but, you know
5:15 maybe it'll kind of tell you what's going on there.
5:18 And then we can just go up here.
5:22 import pypi_org.data.db_session as db_session
5:26 and come down here and just call our global_init().
5:30 Pass the db_file, and that's it
5:32 we should be golden.
5:33 Let's go ahead and run it just to make sure
5:34 everything's hanging together.
5:36 Ha ha, it did, it worked! Off it goes.
5:39 There it is up and running.
5:41 Super super cool. Did anything happen here?
5:43 Probably not yet, no, nothing yet.
5:46 But pretty soon when we ask SQLAlchemy
5:49 to do something, like even just verify
5:51 that the tables are there, you'll see SQLite
5:54 will automatically create a file there for us.
5:57 Okay, great, looks like our database connection is
5:59 all set up and ready to go.