SQLModel: The New ORM for FastAPI and Beyond - Talk Pythonto Me Ep.353

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
- Sebastian, welcome back to Talk Python to Me. - Thank you very much. Thank you for inviting me. - Yeah, it's great to have you back. When you were on the show, we were talking about fast API and it seemed like so much had happened. You've done so much and now there's like all these other frameworks that you've built and all sorts of exciting things, right? - Yeah, very, very exciting stuff. It's like very exciting because Python is getting so excited. - Well, it's very exciting, has always been exciting, but there's so many new things that it's great to build things with them. - It's interesting, I feel like your frameworks more than many take advantage of and almost depend upon the latest aspects of Python. - Yeah, yeah, absolutely. Like someone made a meme at some point on Twitter about this guy that was like, pen pineapple apple pen, and it was like type annotations and another library and just put them together and that's what I'm building. Yeah, it's pretty accurate. - Yeah, absolutely. You know, there's, as a community, we sort of muddled our way through the Python two to three transition and it took a lot longer than even Guido and everyone, many other people expected it to take. But now that we're on the other side of it, stuff like what you're creating and other people are creating, that's what would have been possible had we gone sooner, right? But now it's like, no, everyone's putting their effort into these new ideas and these new aspects that are now possible. - Yeah, yeah. - I think it's great. - Yeah, absolutely. And I feel like the way Python is growing and improving is amazing. Like, you know, there are some growing pains, like as with any project or with anything, but like, so like it's been able to grow in the directions that are needed and to support all the things that users are needing. And like, we can do very cool stuff that will not even be possible in other languages. And it's, I don't know, for me, it's pretty exciting. - Yeah. Same as for me as well. It just gets more exciting. I think, you know, you could see it, you just keep working the same thing and it just keeps, ah, well, I've been doing that for a long time. I need to change, but I don't feel that way at all. I feel like every day there's something new and amazing and still the possibility for more incredible things to come is certainly out there, right? I don't feel like we've hit the limit of what it's possible for framework authors like you to build or for the core devs to make Python do. You know, there's the whole performance resurgence thing that Guido van Rossum and Mark Shannon are doing, that Sam Gill did, that Anthony Shaw is doing, and others. Yeah, I think there's-- it's good, right? - Yeah, it's amazing. And I feel like how the energy between the community and the core developers and like editors and all the tooling, like all growing together and all supporting each other, like helps each other part to grow more and better. And it's so exciting. - Yeah, absolutely. - You know, to get like, for example, like support for very recent things and have been able to use them right away in editors. It's like, ah, so cool. - It is absolutely cool. And yeah, the editors are definitely coming along as well. Now, before we get into your latest project, SQL Model, which is very exciting, let's just get a quick update on you. You know, you told us the story how you got in programming Python before, so we're not gonna ask you that again, but what have you been up to since you were on the show last? So when I was on the show last, we were talking about FastAPI, right? - Yes. - And Typer already existed, if I'm not wrong, right? - Yeah, I think those were the two things you had built in FastAPI. - Okay, okay, yeah. - Had FastAPI made it to the top three web frameworks yet? I'm not sure if it had, but it was right around that time. Yeah, that's incredible. - I think it was very close to that point. That was mind-blowing that people were being able to use it so much and adopt it so much, and when it came out in the surveys like that, it was super cool. - Yeah. - Yeah, super exciting. And yeah, I don't know, I have been trying to focus, I have always been trying to focus on whatever is the next thing that I can work on that will have the biggest impact, that can help the most. And I end up just changing areas and trying to improve different areas and different things. And recently that I was working with SQL databases, well, recently, I don't know, some months ago, that I was working with SQL databases and I was working some of the existing libraries and I wanted to have like all the benefits of the new features of Python. But I wasn't able to have like as much things as I could because most of these libraries were built before we had all these new features. So I wanted to be able to get that and I figured that the best way to build it was applying the ideas that I had and the learnings that I had from the other tools and from the other things and just like put the thing together because there were some libraries that were trying to do similar things, but like I feel like there was still a bit more that could be done. So yeah, I was just like trying to get that and that's how it ended up starting. - Yeah, fantastic. Now I feel like SQL model, I don't know for sure, I'm asking you, but it seems to me looking in from the outside that SQL model was something like, I need a good ORM for fast API. And the things out there didn't click for you in the way that you wanted it to. So you're like, I'm gonna build something that fits with this, right? - Yeah, so it's like, the good thing with fast API is that it doesn't have any need for a tightly coupling it with any ORM, with any database, or it can be used with anything. But still, there are some things that might not be as convenient in the ORM itself, like if you use it alone. And for example, with FastAPI, that you use it to declare all the data models, all the shapes of the data that you want to receive and that you want to send back, and to do like all the data validation, documentation serialization. Then you declare a bunch of those data models with Bidantic. but at the same time, you will end up declaring, duplicating a lot of that information in a separate ORM, just to connect to the database and to handle the database stuff with Python objects. But then you have to duplicate the information in two different ways. And that's what was like, it was not the best developer experience, I guess. And I was trying to make it a bit more user-friendly, a bit more developer-friendly, I guess would be the word, to work with databases and data models and avoid all that duplication information. And at the same time, make it as easy as possible to write the code just using the same standard type annotations and just using the same intuitive things that we can already use. And that's the point that I was trying to hit. - For people to see how that clicks together, I know 12% of the community who builds web APIs and frameworks is using FastAPI, but there's a decent person out there who maybe haven't heard or looked into FastAPI. Maybe they've heard about it, but they don't know the pieces. Maybe given that that's some of the motivation, maybe give us a sense of how do you build data models that match your APIs and how do you do things like generate the open, the swagger documentation and stuff like that? set the stage for why just straight SQL alchemy or some other standard, you know, pony ORM or something like that didn't just directly map over to how fast API works. - Awesome. So like just a very quick intro to fast API, it's a web framework, but it's focused a lot on building web APIs. And the main idea is that using the standard type annotations or type hints. So the way that you in a function, you declare what is the type of some particular variable. Using that same information, that same information by default will give you some certainty that the code is correct and will give you the completion and inline errors in the editor. FastAPI uses that same information to do data validation of the data that you receive in the web API and to do data serialization of the data that you are returning back and to do automatic documentation. This is all based on a bunch of standards, OpenAPI, JSON schema, and a bunch of other things. And because it's based on these open standards, then it can generate and it can also provide a Swagger UI, as you were saying, which is this web user interface that shows all the information of the API, all the end points, what are the data shapes that you can send, and you can actually interact with the API directly from the browser without having to go to some documentation site and then update and the wiki gets updated and things like that. - Yeah, absolutely. I built a weather service API for one of my courses. This has limited data. People don't try to use this for actual weather service. But it's a fast API, and in addition to all the other cool things it does, like quickly generates the stuff it needs to, you can just go to slash docs and it'll give you the schemas, it'll give you the API endpoints, the values that go in, the return value, all of this. I guess the most important aspect of this is probably Pydantic, correct? - Yes, absolutely. - Like the most important part. You define your stuff in Pydantic models and then that drives so many of these things. - Yeah, so FastAPI is built on top of two tools. Pydantic does all the data stuff, data validation, serialization, documentation, and Stableit does all the web stuff. And FastAPI just puts them together in a way that they work together and adds some extra things on top. But Pydantic is the thing that powers all these data validation and all these automatic documentation. Pydantic is also based on the same type annotations, the standard Python type annotations. So you can just like use the same intuition that you will have for a standard Python and then get all these data processing with Pydantic. - Yeah. And FastAPI does several things with the Pydantic models. It does model binding. I guess I'll call it, that term's not super common in the Python world, but you can just say, my API function or web function takes this model and then fastAPI will create the Pydantic model and set the values and do the validation. And then also the return value, you can say will drive this documentation and so on. So the reason I wanted to set the stage so much around Pydantic is that's one of the core elements of SQL model, right? And not just using that library, but so that it can be used as the models in FastAPI, right? - Yes, exactly. So SQL model is a library, what they usually call an ORM. And if you don't know what an ORM is, it's just a library to connect a SQL database with Python objects and classes. I don't know why we use the term ORM. I feel it's a bit abstract. But it's just a library to connect SQL databases with Python objects and classes. And the thing with SQL model is that it does a lot of work inside so that each model that you create is already a Pydantic model. It's not that it internally uses a Pydantic model or internally creates some additional Pydantic model, is that each model is itself a Pydantic model. - Yeah. - And at the same time, so SQL models is built on top of Pydantic for again, data processing, validation, all this stuff. and another library that does all the work to communicate with SQL databases, which is called SQLAlchemy. And each one of these models is both Pydantic and SQLAlchemy. - Yeah, it's an interesting marriage between Pydantic and SQLAlchemy. Much of the way that you work with it would be very familiar to people who do SQLAlchemy today, right? - Yes, that's the idea, that it will be very familiar for people that is already working with by that tick probably because they are using fast API. But at the same time, you will be very familiar for people working with SQL model because it's just the same look and feel. Yeah, and it's indeed a strange marriage because these two libraries are so different that getting them to connect and work together in the very different ways they are built, it was very, very strange. But they actually ended up like working quite well. - Yeah, I imagine that it was pretty tricky. Anytime that you get in the middle of an ORM and its model, I've tried to do that with other frameworks and said, oh, it would be great if I could say, use inheritance in this way on my model so that there's not duplication. Like, oh no, no, no, you can't do that because the thing really depends upon the exact class that derives from it's sort of like ORM base class. that's what it uses for its determining what columns are there and so on, right? - Yeah, it was so crazy. I spent so much time in the movie and trying to figure out what was happening underneath and studying so much about like the black magic in Python, the stuff that I always feared, like all the meta classes and stuff and all that weird stuff. I studied so much of that to be able to mix these things together. But yeah, like, because they do things in a very different way. At the same time, that's facilitated, allowing one thing to do its job and the other thing to do its own job in their own particular ways. So yeah, it was fun. - Yeah, very cool. Whenever I think about an ORM, the thing that I first go to focus on is the Python classes. Because for me, the whole point of the ORM is to let me talk to my database through those classes and model my application through those classes, right? So let's maybe get started by talking about how do I create a class, a model, a SQL model model here that is both a Pydantic model and a SQLAlchemy-like model. I'm gonna talk us through what does it look like? - Cool. So from SQL model, you will import this class SQL model. And SQL model, you inherit from this class. You can, for example, create a class hero. And then let's jump to the internal parts of that. Then you will define some attributes for this class hero. For example, you could say that it has an ID and that this ID will be an integer. The way you declare that is with standard Python type annotations. You could say that it has a name and it's a string. - If you are familiar with Pydantic, it basically could exactly be a Pydantic model. - Yeah, yeah. - In the simple case, right? In the... - Yeah, yeah, exactly. In the... - It really is just an integer and it just has a number. You don't have to make it auto increment or any weird stuff like that, right? - Exactly. In the simplest cases, it will look just exactly like a Pydantic model. And in fact, it will be a Pydantic model. And then for some particular cases where you need to add a little bit of extra information to tell SQL model and SQL alchemy underneath to tell it, hey, this does this thing with the database, then you can pass additional parameters and additional configurations. So for example, when you create the ID of this class, this will be the ID of the table and it has to be a primary key. So then you can use the function field to say, hey, this is still has a default value of none, but I need this particular field or this particular attribute or this particular column, however you wanna call it. I need this to be the primary key. And then that information is passed through to SQL alchemy underneath, which is the one that does all the work. And there's something particularly interesting here is that you are saying, hey, this has a default value of none and that none default value will be used by Pydantic in the Pydantic side of things. but at the same time it will be used in the SQL side of things. So in the database, this will have also a particular default value. In the case of the primary key, it's just because when you create a model you still don't know what the primary key is. - Most of the time the database generates that. You could say your primary key could be your email address, but it's common to have it just auto-generated by the database, a UUID or auto-increment integer or something like that. - Exactly. So for those cases, you want to have the type annotations very precise so that your code can tell you, hey, this could be known at some point. That's just a particular detail. But the thing is, important thing is that you use standard type annotations to declare attributes. And then these will be mapped to the data model in PyDantic, but at the same time will be mapped to the table in the SQL database. - Nice, so it kind of behaves in the two ways. And that means that what you put into your database is pretty much what your API model is as well, right? - Exactly, exactly. That's the idea. Like in the most basic situation, the cool thing is that with this approach and with this tool, you can then create additional models that don't map to one particular table in the database, but are just for handling data in the API. For example, if you have an API that receives data to create a user, it will probably receive a password from the user. You will have the username and the password. And you want to be able to have that information in the model that you want to receive in the API, but you don't want to save the password as plain text in the database. - You don't, isn't that the easiest way? I get these warnings from these various sites, like, oh, your password can't be more than eight characters long, because, no, yeah, please don't save it in the database. That's a really interesting scenario, right? You need to receive it on one end, but you must not put it into the database. - Exactly. - You must not carry on. - And for example, and then, in that same situation, you create the user and you want to return the information of the user back to whatever is the client. you don't want to return the plain text password. You want to say, "Hey, this is the username," but like, that's it. - Yeah, probably not. It's very unlikely that you want to return the hash as well. You just, you don't want it to return at all, right? - Yeah, exactly. - How do you handle that? - So for these particular cases is where SQL model will shine because you can create one base model that will have like all the base attributes. For example, it could have the name, the last name, the address, the email, blah, blah, blah. And then you can inherit from that model and then have different models for the particular use cases. For example, for creating data, so you will have a plain text password and for a returning data, you will have no password at all. But then one of these models will be the actual model that's facing the database. The one that reflects the information in the database. And this one is the one that will have the hashed password. But you didn't have to duplicate all the information for the model because they all inherit from the same base model. - Is that the section that I got on the screen here that says multiple models with fast API? Like how you do that? Okay. - Yes, exactly. - Yeah, so the idea is obviously you have got some shared information about the user, like the email and their name and stuff. You wanna share that, probably their ID, but you don't wanna share, say, their, like you said, the password or whether or not they're an admin on the site or those kinds of things you probably don't want to exchange over the API, right? - Exactly, and if you need to duplicate all the information for each one of these particular models, there's a high chance that at some point, whenever you refactoring the code, some part will be out of sync. And then you will have a bunch of errors and a bunch of bugs that are very difficult to detect. When you have duplication of code and you have to synchronize it by hand, it creates a lot of potential bugs that are very difficult to detect. So in the way you do your models, this is pretty neat. One of the things that you do is you've got your model hierarchy, you've got SQL model, which is the base class of all the things that interact with SQL model. And those are typically the classes that you create that would be like SQLAlchemy or Django or M models. But in your world, you can have inheritance. And then somewhere in that hierarchy, you set table equals true as you create the class. So it's not necessarily that just, oh, you derive from this class, so that's a table. It gives you more flexibility and go, this part is a table, that part is a table. Like in the scenario we were talking about, you have a base user where there's a name and a password, a hash password and stuff. No, sorry. You wouldn't want to put that, but you would put like your shared stuff into the base class. - Yeah, like name, last name, address, email, I don't know. - And then the thing that derives from it, user would derive from like user base, which would say like, "Typical is true," and it could have its secrets there. - Exactly, exactly. - Okay. - We don't have this private bit. - So that makes a lot of sense inbound. What about outbound? So I've got a fast API endpoint, it could even be Flask or whatever, right? And I've done a query to the database and I get the table version that has the secrets. I can easily go to fast API and say the response model is the base thing. So the documentation is right. But if I go to the object that I got from the database and I say as dictionary or to dictionary, I forgot exactly what the right term is, but the thing that sends it back, it's gonna include everything in it, isn't it? So this is one of those particular details of FastAPI that I think people in many cases miss. And is that in FastAPI, you can say, hey, this is the response model. So this is the model that I want you to use for the data that I'm sending back. The most obvious result of that is that in the automatic documentation, you will get the schema of what is the response data. And that is like the most obvious and visible. But FastAPI will also use that same model to filter out the data. So if you say, - Okay. - If you say the response model is a user out, for example, and the class user out, which is a pedantic class or something like that, this class user out doesn't include the hashed password. From the function, you can return an object that includes the hashed password or a dictionary that includes the hashed password, but FastAPI will omit that field and FastAPI will only return the particular fields that were defined in the response model that you say that will be returned. - Okay, I did not know that that also affected the outbound data, not just the documentation. That's pretty interesting. - Yeah, and in fact, that's, in many cases, people ask why does FastAPI use this parameter, response model instead of using the return type annotation. Because in Python, when you create a function, you can define what are the types of the parameters that the function receives, and you can also define what is the return of that particular function. If FastAPI use the return value and say, "Hey, the return value is this user out," but then the object that you were returning from that particular function was a different object, then the editor will complain, the tooling and the tools that detect those typing errors, like mypy, will complain and they will detect, "Hey, you're saying that you're returning something, but you're returning a completely different thing." So that's the reason why the return type is not what is used to extract that information. And instead it uses this particular configuration response model because it's used for filtering data. Right, okay, interesting. So for people who don't know, haven't seen this in action, you put a decorator like an app.orapi.get, for example, just like you would say in Flask or something, and you say, here's the URL, but then you also may put response model equals some Pydantic type in fastAPI, and that drives the Swagger documentation. And I am learning now, drives the filtering of the allowed return values as well, which is pretty excellent. - Yeah, in fact, it will also validate the data. So if you're saying, hey, this will return this data, and then whatever you're returning doesn't include that, that will actually be an error on the server because you are saying that the contract is that I will return this data, but then suddenly you are not returning it. Then it will raise an error inside of the server and it will tell you, "Hey, the data that you're sending is incorrect. So there's something going on here. There's something wrong with your code because you're sending something invalid from what you say that you are going to send." - That's pretty fantastic. Okay, I didn't realize it made such great, and I think that's a really important point. And I think that's a really important point. And I think that's a really important point. And I think that's a really important point. And I think that's a really important point. And I think that's a really important point. And I think that's a really important point. And I think that's a really important point. And I think that's a really important point. And I think that's a really important point. And I think that's a really important point. And I think that's a really important point. And I think that's a really important point. And I think that's a really important point. on FastAPI, I think FastAPI is absolutely a great thing. - And Sandy. - Yeah, also very much. Poppin says, I have a question, if the data schema is complex and has nested JSON structure, in what case would you validate? It's pretty straightforward to just nest the Pydantic, but this brings us, if you're gonna be in a world where you're nesting Pydantic things, you may wanna save them to the database. What's the story on relationships? And this basically, I've received some data that is like nested related data. What do I do in SQL model? - So if you need to receive some complex data structure and you need to extract the information, you can declare models with Pydantic or with SQLAlchemy, sorry, with SQL model saying that, hey, this is just a data model and then you can manually extract the sub components and then just add them to the database independently or something like that. There wouldn't be a straightforward way to say like, hey, I received this giant JSON and automatically generate a bunch of different models that don't exist yet or something like that. Or to automatically infer where to put each information, it wouldn't be as straightforward. Like it will have a lot of different design possibilities. So it will be easy to get it wrong. So the way that you will do it is that you define the complex data ship that you want to receive. And then once you take it, you just extract each part of the information and each particular object or each particular data point that you want to then say to the database. Now to return data to the user, with SQL model, you can have relationships and relationships between different tables and have like automatic joins and all that stuff. This is all thanks again to SQLAlchemy, which is the thing that works underneath. - It already models that, yeah. - Yeah, exactly. But then you can use that information and you can just like declare the models. And this again works well with this idea of having narratives to be able to declare, hey, I want to return this model and I want it to include this particular relationship model. So it will include the information from all our tables and it will just extract that information and return it to the client. - That's really cool. What about lazy loading? I'll ask this in two aspects. If I've got a relationship, I can do a join or a subquery load on it in SQLAlchemy so that if I know I'm gonna be traversing that relationship, I don't end up with a dreaded N plus one performance problem where I thought I was doing one query I'm doing 51 queries if I got a, - Yeah. - 51 or 50 results back, something like that. Is that support flow through SQL model as well, the joins? - Yeah, so the thing is that SQL model actually just like exposes the same interface as SQLAlchemy because it's actually just using SQLAlchemy underneath. And SQLAlchemy supports everything, including like a lazy loading. SQLAlchemy actually supports things that are not supported by many other ORMs, like I forgot the name, having primary keys that are composed of different, of several columns. - Composite indexes and composite keys, yeah. - Composite keys, yeah. There's a bunch of things that SQLAlchemy supports, and if SQLAlchemy supports them, then the SQL model automatically supports them, because SQL model is just inheriting directly from SQLAlchemy. - Yeah, that's really cool. Now, the question I was thinking about is, if I have a result from the database that has relationships, a relationship, and I return it from a fast API endpoint, is that going to go and start iterating the relationship? Do I need to be worried about N plus one problems by returning these models that then are getting serialized in eager ways. - Yeah. - It's like tracing through all the relationships so it can build a whole JSON to pull back out. - Yeah, and then return the whole database in a single file. - Yes, exactly. Wow, that took a while. That's so long. - That was so painful. Yeah, now by default, a FastAPI and SQL model won't include relationships in models, won't include them in the data that is returned back. But if you need to include some of those, you can declare again, using inheritance, you can declare a different model that defines, hey, this relationship, this particular attribute, this should be included. And that way you can define that particular one in the specific endpoints that you want to include the information in the resulting value. That will work to a force SQL model and to force a fast API SQL model to do all the N plus one queries and to just extract information and send it back. But if you are returning that data including the relationships, you will probably want to eagerly load that information, which is something that is supported by SQL model and via SQL. So you will load the information that you need including the relationships, and then you just return that object directly and you define the model, hey, I want this to include the relationships. So it will just like include the information that is already there. - I can see that this N plus one issue is without the join or eager load is happening through a profiler. If I was doing this in something like Django or Pyramid, I could look into the debug toolbar and it'll actually show me the SQL alchemy statements that are running. It'll be like, why are there 50 queries on this page? That's harder I suspect in fast API, especially if it's operating in API mode where it doesn't have debug toolbars and stuff like that. Probably one way you could see it is to say echo equals true on the engine. - Yeah, exactly, exactly. Because FastAPI is not integrated with any database and SQL Model just makes it super easy to work with FastAPI but SQL Model could be used with any other framework. And that was the intention. SQL Model doesn't depend on FastAPI, FastAPI doesn't depend on SQL Model. They just integrate very well. But then you could just enable the, the little thing with SQL alchemy that will then show all the particular SQL statements and show you, hey, this is what is running. This is what is happening. - Right, yeah. So if you're connecting to the database, then this is a SQL alchemy thing, but obviously it'll flow through, right? You just say, when you create the engine, you give it the connection string, you can say echo equals true. And if you are doing queries that are doing a bunch of indirect behind the scene, lazy queries for you, your console window, your terminal, whatever, is just gonna blow up with query. You're like, why is so much SQL screaming by, right? - Yeah, exactly. - Yeah. - Exactly. That's how it'll work. - Let's talk about editor support really quick. So one of the things that's really nice about Pydantic is it requires you to state the types, whether those are fundamental types, whether those are nullable types like optional of int, or they're nested types like a user contains an address, identic model. All of those scenarios result in really good editor support, right? - Yeah, yeah, exactly. - What's the story for editors in SQL model? That's something you specifically call out about how that has good support there. So if you check the source code for SQL model, it's actually super short, but it's just like a bunch of a lot of tricks together. And many of those tricks are actually about type annotations, because the thing that allows your editor to provide you auto-completion and the inline errors are the declarations of these types, the type annotations or type hints. And SQL model does a lot of internal work so that whenever you use any part of SQL model, you will get that type information in your editor. For example, if you query some model, query some table to get data from the database, the result that you get back, the object that you get back, will have internally all that type information. So the editor will be able to provide you with all the active completion and all the inline errors and all those things. SQL model, in fact, sacrifices some of the more advanced or obscure or sophisticated use cases that SQLAlchemy supports, and sacrifices those to instead get like very good auto-completion and inline errors everywhere in the code. And this is another thing that includes in SQL is that it uses some draft standards that are not even implemented yet, that are not even like, I don't know, are not part of the standards, official standards yet, but they are already supported by some editors. For example, Visual Studio Code already supports providing auto-completion when you are creating a new instance of a particular class, for the particular class of a mode. Having this auto-completion is not very, very easy to do with other tools because the editor doesn't have any information about what are the parameters that you can pass, what are the arguments - Right, when you create a Pydantic model, it doesn't in any way indicate, here is the constructor or initializer, and here are the keyword arguments that happen to be all the, what look like static values, static fields, yeah. - We'll just say like, keyword arguments, or like data, star, star, something like that. - Yeah. I always think, thanks for nothing when I see that. - Yeah, exactly. Well, actually, Pydantic 1.9 includes this same trick. So now you get auto completion in Visual Studio Code. In PyCharm, you already have the auto completion with PyDantic because they have a plugin for PyDantic to provide the auto completion for those things, but it requires this particular plugin. Now with this extension, you can get also auto completion in VS Code. And with the same extension without needing any plugin, you get auto completion for SQL model in Visual Studio Code. I think the people from PyCharm were also checking out to maybe support the same standard, which will allow PyCharm to provide automatic auto-completion for SQL model and other libraries like Pydantic and others. - Sure, yeah, that's great. Definitely the widespread use of Pydantic effectively is forcing everyone to go like, all right, how can we make this work better on the creation side? So RJL out there has a comment, which then leads me to an interesting question. I'm old fashioned, I use direct SQL statements, no ORM, I really need to take the time to go down this route. Indeed, I do think so. It's certainly worthwhile. Maybe, what are your thoughts on using straight SQL versus not, then I'll ask my question. So I think, you know, like it just, it's a lot about taste and how people prefer to code. There's a lot of people that are so comfortable with SQL and that can do so many things with SQL very easily that it's just more efficient to just use SQL directly. For me, some of the advantages with ORMs is that I get inline errors, that I get auto-completion for what is the name of the attribute. If I forget that I say secret_name, the editor will auto-complete that for me. But if I'm typing that inside of just a long string in Python using SQL, then I have to remember because no one will tell me that I have a syntax error in my SQL or that I'm using an attribute that doesn't exist. - Yeah, one of the things that actually blew my mind is PyCharm, if you set it up to, if you basically connect the database to your project, it'll give you autocomplete and error checking inside strings inside Python for your schema. - That's super cool. - Which is amazing. That said, I never do that because to me, one of the things that is super valuable, one is this auto-complete, the other is refactoring as well. Like, oh, did we change the name of that? Well, oh, there was that one query we didn't update and now it crashes in production, but only sometimes when it hits this case. And, you know, it's just the way it sticks together and stays consistent to me seems a lot stronger if you're using models as well. And also the ability to swap backends, right? the way you do parameterized queries is different across different database backends. - Yeah. - Right. - Also, if you write SQL by hand, then you have to be super careful and probably you have to be a SQL wizard and know how to sanitize all the data that you're putting or otherwise you could end up in nasty situations. But given that, and saying that, there's a lot of people that prefer, really prefer writing SQL directly. The same author of Pydantic, which SQL model is based on, prefers to write SQL directly. Unlike he's using FastAPI and everything, but it's just more comfortable to him. And the author of "Py and Psycopg," the driver for PostgreSQL, he just uses SQL directly. It's just like more comfortable for him. He uses FastAPI a lot, but still, like it's just more comfortable. So I guess like it depends a lot on like the taste. For me, I depend a lot on the tooling and editor support and refactoring as you were saying, like if I change a name, I know that it's changed everywhere because I won't remember, I won't remember where did I made this mistake, so yeah. - Yeah, absolutely. So Martin in the audience asked an interesting question, down here is a better example. One of the challenges of ORMs is to make set-based operations apply back to the database. Like I wanna change this field. Like I want to set a is on sale flag to true for all products where the price is less than $10. Right, where I'm not going to pull, I don't wanna go, let me query all products whose price are less than $10, change it on the object and then push those changes. I wanna push the, I just wanna say, update where this set that, you know what I mean? - Yeah, yeah. - What's the story about that with SQL model? 'Cause that's one of the things that can really just hammer productivity or speed, I guess, is that you've got to like pull back a whole bunch of stuff to just make sort of consistent changes across them. You know what I'm saying? - Yeah, yeah. Like this is one of the use cases where you will want to interact directly with SQL alchemy. And you can do that through SQL model, but you can write like queries as complex as you want through SQL model, but just using pure SQLAlchemy underneath and you can use very advanced things with SQL. SQL model focuses a lot on the simplest and most common use cases and providing the best developer experience and certainty that the code is as error-free as possible because you have all these type annotations and all these type checks. But for any case that is a little bit more advanced, you can just drop down directly to SQLAlchemy. And because SQLModel is just pure SQLAlchemy, the models are themselves just SQLAlchemy. So you can just use SQLAlchemy directly with it. In fact, you could use one of these models with a SQLAlchemy engine directly, and it would work. - Interesting, okay. Sky points out in the audience that you were too humble to call out. The PR that got that autocomplete for VS Code was actually for Bitandic, but it was by you. So well done, way to keep moving forward on both fronts. Let's see, so what about performance? There's extra goodness in the validation and the type conversions and stuff like that of say, Pydantic, but is there a large overhead for using this say over SQLAlchemy over say, raw SQL? - Yeah, well, so when you use, when you use, when you declare a model and you say, hey, this is a table model. So this is like the equivalent of a SQLAlchemy model. Then a lot of the validation and that stuff with PyDantic is overwritten. So when you create a model, it will not be validated on creation for that particular table because this will be handled directly by SQLAlchemy. And for example, with SQLAlchemy, you can create an instance of a model without setting all the attributes. And then you can set the attributes manually afterwards. If Pydantic was doing validation for that, like that will explode and that will say, hey, this is invalid. So when you are working with SQLAlchemy alone, well, like with the SQL parts alone through SQL model, then it's just like using SQLAlchemy directly. When you are using-- - Okay, so it's not really any different in terms of, whatever SQLAlchemy does, this does in terms of performance. - Exactly, exactly. - Okay, got it. It just has like... And actually, the code is so slim, it's so little that whatever is the overhead, I will think it will be negligible. At the same time, I'm not optimizing for squeezing the maximum performance, but for getting the maximum correctness in the code and the best developer experience, because I feel it helps a lot more to be a lot faster as a developer, building the tool and making sure that it's all correct than having the code super fast, but very difficult to debug and to understand and to write correctly. So I guess you just got to decide, is an ORM the right fit at all? And if yes, then this is a pretty good choice if you like this API. Yeah, exactly. And yeah, absolutely. If you were needing the maximum performance that you can get, you will probably end up just getting an async drive directly and just writing SQL directly for the particular endpoint that needs this extra boost in performance. But for most of the other cases, this will probably help making sure that the code is correct and making sure that you can write code quickly and be done with the feature that you're implementing. Right on. I've got one more thing I want to talk to you about. And then I've got, I did a Twitter, hey, I'm talking to Sebastian. Let's, what are the questions we should be asking? And I got a bunch of great ones on Twitter. So I do want to touch on those as well. - Nice. - One of the things though that you spoke about is the ability of having, this is just generally true for SQLAlchemy. These models, they are tied back to a, what's called a session or a unit of work to do with the database. and you can't do a query, get a record, and then go from a separate situation and try to jam it back into, it's gotta be stuck to the session that it comes from, right? So you don't share the models across sessions, but one of the things that would be nice is just to have a single one. And so FastAPI has a dependency injection system that you talked about can be used for basically always providing one and only one session to an API endpoint or a web endpoint that then could be the database management unit, like creating a unit of work that is the lifetime of the request, basically. Wanna talk about that? - Yeah, exactly. I think you described it perfectly. I don't know what else can I add on top of this, right? So this is the dependency injection system. It's just like you declare some function and FastAPI will make sure to run that function and provide the value to all the things that need that value. for one particular request. - Right, this has nothing to do with the database, by the way, this could be anything. It could be a logging framework, whatever, right? - Exactly, so this is very useful for doing logging, for doing authentication, for doing authorization, withdrawals, and like whatnot. For doing logging, for setting up things that log stuff to remote servers, like Sentry or like Datalog, or I don't know, for all those things that you need to do, And that can be-- and there is some logic that needs to be shared and that could run before the request is handled and maybe after the request is done. And then you can share this information. So in many frameworks, there is a concept of a middleware, which is something that runs before the request and after the request. But then you have to run this thing for every request. With dependencies, with this dependency injection system, you can define exactly where you want it to run. And you can define, I want this to be run with a group of endpoints or with a group of operations as I used to call them, or for just one particular endpoint or for a bunch of endpoints. And with this system, you can extract and you can generate whatever it is that you need to generate for the particular request. And the good thing about the independence injection system is that if you're extracting information from the request, for example, from a header, then this information will be also extracted and included with FastAPI, with all the open API and all these standards. So you will get that information in the automatically generated user interface to explore the API. - Yeah, very cool. So what steps do I have to take to do dependency injection to get that session to show up? I remember you had it in the documentation, but I don't remember where it is right now. - So I think for the particular case of SQL model, even though FastAPI and SQL model are independent, are made to be very compatible with that independent, I have a lot of documentation about writing applications with FastAPI and SQL model in the SQL model docs. The way that you will, the way that we will do it, the way that you will handle a FastAPI dependency in general is that from FastAPI, you import this special function depends, to start with that. And then you create some function that will return some value. This function will have the same style as any other function that handles a particular request. So it can have some parameters with some types and those that information will be extracted from the request. And it just returns something. This is just plain old function. And then you pass this, this function is, this is what will be the dependency. Then you pass that function as a parameter to depends. and then you put depends as the default value of some parameter in your main function that is handling the request. - I see, so you could say session equals, like depends here's some function that I'll call to create the session. - Session equals depends, I'm calling depends with the function that is named get session or something like that. - Do you have a way to see both sides of that with dependency injection? So does it just return the value or can you like create a session and then yield the value and then keep processing or something along those lines. - Exactly like that. You can create a session that you can yield the value. And then after the request is done, you can continue doing more stuff after yielding that particular session. So you can create a session, give the session from the dependency, and then the main code that will handle the request will have that session. And then the same dependency can take care of closing the session after. - Right, exactly, try yield session, finally close it, maybe like if there's no exception, commit it, something like that. - Exactly. - Okay, that's pretty flexible. - Yeah, and in the main code that you have, you don't have to take care about creating the session or closing it or making sure that there are no exceptions because you can do all that stuff in the dependency and share that logic throughout your code. And the other thing is that dependencies can themselves depend on other dependencies. So you can create a dependency that gets the session for the database. And then you can use that in another dependency that gets the current user and extracts from the header from the authentication token or whatever, extract the user ID, then gets the user ID from the database and then returns the current user. So that you have a whole dependency that just takes care of returning the current user and making sure that it's authenticated. And then in all your, and you can reuse that code in all your endpoints or in all the main functions that handle the requests. And all those functions will be able to just get the current user right away without having to have all the logic to extract the information, process the token, all that stuff. - Sure, this is very neat. I haven't used this enough during my work with FastAPI, so I gotta check this out. All right, now let's do a bit of a lightning round here of the Twitter questions, because I've seen some of these questions come up in the live chat, but I also think I pulled out these ones that I thought people put on Twitter that were pretty good. So, Lemat Webster says, "Any plans to ramp or replace Alembic "to make migrations more developer friendly?" So, first of all, migrations, you've got to keep your database in sync with your models, otherwise, SQLAlchemy and hence SQL model will freak out about that 'cause it's gonna be a problem. But Alembic is, while it works, is a little bit hard to say like, here's all the models you need to pay attention to, and here's the scenario where you run. It's a little bit clunky. It works well, but it's not super smooth. And I think that's what Matt's asking here. - Yeah, so Alembic is the official tool from SQLAlchemy to do the migrations. And because SQL model is itself also just SQLAlchemy underneath, Alembic works with it perfectly. Alembic is a great tool. It's super advanced and helps a lot. It can even generate automatic migration, some things like that. I think the main problem with Alembic is that in some cases it's not as intuitive. So yes, what I want to do at some point is to wrap a bit of Alembic. I will replace it because it's already doing a magnificent job, but, and it will be super difficult to write all that logic and all that work that my buddy has been doing for a very long time with SQL Model and Lemmick. I will wrap it and I will try to add a bit more of documentation to explain how to handle the simplest cases which is the same that I'm doing with SQL Model. If you need something more complex then you will probably just go to a Lemmick directly or to SQLAlchemy directly. - Related to this, not Twitter question, Michael question. What about, do you have any thoughts about testing code using these models and stuff like fake data or mocking out the database beyond just the standard stuff you would do to SQLAlchemy. Like, is there anything special about SQL model that makes testing it easier or different than SQLAlchemy? - No, the testing will be pretty similar to SQLAlchemy. Yes, I just have like a bunch of documentation of how to do testing and even how to do testing with fast API applications using SQLAlchemy and how to, for example, use a SQLite database for testing that could be run on memory instead of the production database that could be PostgreSQL or MySQL or whatever. - Just change the connection string to the engine and let it go. - Exactly. - Yeah, okay. - And then make it run with a database in memory and then make it work correctly with-- - So something like a pytest fixture that initializes the database, but you just use colon memory colon for the connection string so that it just goes away. - Yes, exactly like that. It's documented exactly like that. - All right, right on. All right, Ricky Lim says, "Would SQL model be part of, maybe should, "could be part of the standard Python library?" I have some thoughts on this, but I wanna hear your thoughts first. I have some historical perspective on this, but I wanna hear your thoughts on this first. - Okay, so no, it will not be part of the standard library. Ideally, it will not be part of the standard library because if it was part of the standard library, it will mean that it will be available in Python 3.13 or something. And then users of Python 3.10 right now will not be able to use it on one side. On the other side, having more stuff in the Python standard library adds more inconvenience and more burden to the core maintainers, to the core developers of Python, which makes it even more difficult for them to continue supporting Python and all the different versions. And it will also complicate things for Bread Cannon that is trying to figure out a way to slim down Python so that you can, for example, run it directly on the web browser. - How do we build it in WebAssembly? This doesn't help. - Yes, WebAssembly. And you know, Bread Cannon and Kristen Haines have been doing a very cool job. It's very exciting. But a lot of that will probably require, actually is leaning down a bit, the standard library. As far as I understand, but I'm not, no explanation. I imagine a world where we have, I don't know what the right word for it is, but there's like a standard cross environment Python, minimum set of language features of standard library where things like, you know, stuff that talks on the network or does UI things or whatever, just that is not part of this like minimum subset of Python that we're guaranteed to have so that we can put it on WebAssembly, we can put it on mobile devices, we can put it on servers. And as long as you program to this minimum set, your place where your Python can exist is broader, you know, like MicroPython potentially. I think that that's the trend, not the trend towards putting more stuff there. - Yeah, exactly. Absolutely, absolutely. And it's fun that it's already happening. MicroPython is already that, It's just that it cannot say it's a standard Python because it has to link down a bunch of things. But being able to have a microcontroller and write code in Python that is running the microcontroller, that's amazing, that's mind-blowing. - Yeah, the most mind-blowing thing for me is that you can hook a Lambda expression directly to a hardware interrupt. (both laughing) It's like, what, you can do what? That's amazing. The historical perspective that I wanted to bring up here I believe the core developers actually considered this for requests, and they decided that no, they're not going to put it request in the standard library to replace URL lib, because it would limit requests ability to grow. Like changes could only come once a year. It couldn't come three times a week if there was important changes, right? Like the speed of development would be hindered. So they said, you know what? No, we don't want that. Yeah. - Yep, all right. Next, Dimitri Figo says, "Are you considering working on generating TypeScript declaration files based on what's defined on the fast API backend?" That was that documentation I showed where it has the schema and all that, and like the endpoints. - Yeah, so to make it, to explain it a little more, when you go to the automatic interactive documentation for the API, that is all based on this standard schema of the API called OpenAPI. This is just a huge JSON that defines all the data shapes that you're using, all the endpoints, everything. But that same thing, because it's a standard, then you can use that same thing to generate code for clients that communicate with your backend. And in fact, there's a bunch of client generators for many languages, including TypeScript. And I have used them, I have used some of them, and they are actually very, very good. Like you can achieve things like defining in the backend, where are the data shapes that you're using? Then you update something, and then you regenerate the client in the frontend. And now after that, the frontend team will be able to have access to this new API endpoint without the completion in their editor and everything. It works very well. It's super exciting. I just haven't had the time to document like the whole recipe to make it work. But it's already there, it's already working and it already does a great job. - Yeah, maybe somebody wanted to contribute a PR or do some help there, they could, right? - Yeah, and you know, like even a blog post will just like, that will be a lot faster to get out and that will help a lot and a lot of people. - Indeed. Zach Code says, "I'd love to hear how you approach figuring out the integration with SQLAlchemy. I mean, we talked a bit about this, but yeah. Any other lessons you've learned from basically getting in the middle of SQLAlchemy and all of that it does? - Yeah, it's very interesting that SQLAlchemy was created at a time where like, it was, I don't know, Python 2.something, there were no context managers. So that thing that you do in a with block, that you say with something, something, as blah, blah, blah. And then inside of that, you pull code that was not available in Python. That didn't exist. SQLAlchemy was made before that. So SQLAlchemy had to do a lot of. Eh, sophisticated tricks to make everything work and then getting down inside of it and trying to understand that. And it's like, why is this thing doing this? I'm working like this. And it's because of those, all those things. Eh, I think I ended up like learning a lot about those little details. and a lot about how classes work internally and how a class is an instance of what and all those things and how you can configure all that. But the idea with SQL model is to make it super easy for you to use it without having to deal with all the internal complexity. - Yeah, you don't have to know, only you had to know and go through it. So I think it's worth pointing out, I did have Mike Bayer on the show recently to talk about SQLAlchemy 2.0 and how they're moving to have basically the client side view of that be everything as a context manager and sort of change that up a bit. So how close is this to the 2.0 model or is it the 1.0 model API? - Yeah, so Mike Bayer did a lot of work to make the compatibility transition as easy as possible. And SQLAlchemy, the latest available version, which is 1.4, it's compatible with the previous style and with the new style. So code that is written with the new style will be compatible with SQLAlchemy 2. whatever and above. SQL model is based on this new style. So if you, for example, if you have an old application with SQLAlchemy, the first thing that you will want to do is to migrate to SQLAlchemy 1.4 and make sure that it's compatible with the new style and make sure that you don't have any warnings. That's the main thing that you will do to make sure that it's compatible. And then after that, you can migrate to SQL mode. The migration is also super simple. It's just like changing some classes for type annotations, but yeah. - Yeah, absolutely. There was a question. So the question by Python at Night was, what would the level of effort or benefit, if any, of converting SQL alchemy models and schemas to SQL model? Sounds like the effort is small And the benefit is all the features we spoke about, right? - Yeah, exactly. - Yeah, okay. Would you recommend it? I mean, people are using SQLAlchemy, they're like, you know, I'd really would like to have some of that Pydantic magic. Like, when would you say, okay, the trouble of making a change is sufficient? - So right now-- - The benefit is sufficient. - Yeah, like, so if it was me, I would just use it right away. Right now, it's in version 0.0 point something. I will release 0.1.0 once I have 100% of test coverage. Right now is 97%, just because I'm not freak out about that. But like most of it should already work. It's actually very simple. And if anything, like the work that it does is actually very small because underneath it's all done by Atlantic and SQLAlchemy. If anything went wrong, you could also just like switch back to SQLAlchemy directly. It's just that-- - Basically change your class back to derive from SQLAlchemyBase and you're good to go. - Yeah. The benefit that you will get is out of completion and inline errors everywhere where you are using these classes that you will normally not get. - And the integration with response model. - Yes, of course, integration with response models. Yeah, actually that's a lot of code that you will save if you can share that with Pydantic and with SQLModel. Just make sure that you follow all the information about how to pin and how to upgrade versions because it's very detailed how you should go about that because as things are still changing and it still has like a little bit of extra testing to do, you should be careful about how to pin. Just not install like whatever version comes, just make sure that you pin the right version, you have tests, and then when you upgrade, you make sure that the tests are pausing and then you can upgrade the version. - Yeah, good advice. Already talked about that one. So Lado asks, "Are you going to stretch modern Python conventions from the backend part?" Which you already did. We talked about using the types and stuff for model binding. "To Python challenging front end as well, Should we expect something like ReactyPy, like React, but in Python? Do you care about the frontend in the sense that you have any intention to build stuff for it? - Yes, I care a lot about frontend, and I have actually, I think I started in that, and I have worked with Angular, UI, Vue.js, and like all the stuff. I think it will be amazing to be able to write Python to write Python for frontend, but if someone is gonna make that happen at some point, they're probably Brett Tanner and Christian Haynes making WebAssembly work for Python. - Yeah, you need the runtime there first and then it'll go much more easily. I absolutely think that it is, it's not quite negligence, but it's close that the browser makers don't package other runtimes that are WebAssembly compatible, right? Like they should go to Ruby, they should go to Java, they should go to .NET, and they should go to Python and say, are you willing to provide us a runtime that does X, Y, and Z that we can integrate in a generic way that we can include in our browser so you don't have to say, oh, well, you can't use these other advanced things 'cause the WebAssembly download is 10 megs. Well, if Firefox, Chrome, and Safari all shipped five of those, the five most common languages as binaries, like you would just have it and it would just be this website. Why does this not happen? So, but that's the real problem to ReactyPy is that that's not there, right? - Yeah. - All right, Quazi says, what is he doing to address the bus factor? That is if you get hit by a bus and then related to that in the audience, Prashant Rana says, will you include a moderator to the project so it can become a community driven project and there's less burden on you? I think those are kind of similar questions from a different perspective. - Yeah, so the thing is, for most of these projects, like most of the work can already be done a lot by the community. It's not that the work cannot be done. I just want to simply enable a bunch of permissions to a lot of people to just go and merge pull requests very quickly because I like to make sure that everything works. For example, yesterday, for yesterday's fast API release, it had like four approvals, the pull request, but still it had a couple of bugs and a couple of things that needed to be solved. And like, I need to be able, I need to make sure that the code quality is still kept and that everything is working correctly. So for now, I'm still like making sure that I review each one of the pull requests. But if people went and checked those pull requests and review the code and it tested it and like made sure, hey, this is working and I'm using it and it's working in my application or things like that. That will of course help a lot. Yeah, like of course that will help a lot. - That's great. I mean, obviously it's open source, people can fork it. They can run with it. If you actually got hit by a bus, I think FastAPI would keep going. There would just be a figuring out of like, all right, well, where's it gonna send her back around before it settles down? - Yeah, exactly. - Not that everyone's, I think, obviously, these questions are a reflection of how significant the impact you're having on the community is, right? - Yeah, and you know, like, I find the boss factor fun. I have been wanting to write a blog post about that for a while, because I think the boss factor is something that works a lot for investors, or for founders that are not developers, and they are like associating with someone is the only one that knows the product, but they want to be the owners of half of it. And if this person dies, they just lose all their investment. But when you're working with one of these people. - They can't keep it going, yeah, absolutely. - Yeah, like, you know, like, for example, many of the projects from Encode is mainly Tom Christie, which is one person. The maintainer of Flask, which is huge, is mainly David Lord. And he's just like, suffering through all of this and through all the abuse from the developers and and doing like a lot of the work. And probably like, I don't know, I think he has like another contributor or something like that. In the case of FastAPI, there's people like Marcelo that is helping a lot. And even Samuel Coping is also helping. That helps a lot with keeping the community, maintaining it and like doing all the work that is needed to be done underneath. But that doesn't really affect how it's working. how it's working, you know? Like the fact that the repository is not in another GitHub owner, in a GitHub organization or something like that, it's just because it's easier to handle. But at the same time, there's a lot of people that are already contributing and that's the work that actually makes a-- - That's the stuff that matters, yeah. - Exactly. - Absolutely. Lupi, just by the way, out there also says, Just want to say thanks to you. So your work is so important and just great. So yeah, definitely a lot of people out there loving it. Okay, let's keep going. Back to SQL model, roadmap for the future. What are the plans? - So migrations, I want to have a small wrapper to have a common line interface built on top of Typer so that you can get a good completion in the terminal as well. to have migrations based on Alembic to a documentation for using async with SQL mode. Async is already supported by SQLAlchemy. - Yeah, and that's a new thing, right? That is, you've got to create now an async client or an async session rather. So I think it is sort of a regular session in SQLAlchemy, but that's one of the 2.0 big changes that Mike just pushed out. So that flows through for you? - Yeah, yeah. Like you can already use it. In fact, there's people using it in applications, in production applications right now. But it's just that I don't have it documented yet. SQLAlchemy already supports both the normal, the blocking interface, the regular interface, and the async interface. And you can already use it with SQL model as well. I want to document all that. - Right. So what you should do is you should just change your dependency injection based on whether you have a def method or an async def method in FastAPI, and either create an async client or async session rather, or regular session, and then boom, off you go, right? - And that is one of the things that I think is so smart about the design of SQLAlchemy, that SQL model inheritance, is that the thing that handles if it's async or not is the engine, not the models themselves. So you can use the same models even if it's async or not. - Yeah, I agree, very nice. Good question by Lars, but I'm gonna keep going 'cause we're short. David Smith asks, "Are there plans to add async?" I think the question is, are there plans to document async? - Yeah, exactly. - That's probably right. We kind of touched on this one about whether you should use it for an existing, like should you be migrating, and we touched on that one. I think Brandon Brainer, who I think I saw on the audience, yeah, earlier. Hey, Brandon, asks, "Could you go ahead and make no SQL model?" This is a chance for me to mention Beanie out there. I wanted to kind of ask you if you'd had a chance to look at this. What's my best link for this? There it is. So Roman Wright also was out in the audience. I saw them. So Beanie is a ODM like for MongoDB, but also basically very similar based on PyDantic. And so I thought it was a, this immediately came to mind when I thought about SQL model is like, well, here's the MongoDB version that also tries to do the same thing. Have you thought about a NoSQL story? Have you looked at Beanie? What are your thoughts here? - Yeah, I really like both. There are two alternatives for MongoDB with Bidantic. One is Beanie, the other one is Oathmantic. I think they are both doing a great job. I like this particular thing about Oathmantic is that it uses the same style, the interface of SQLAlchemy that the thing that decides if it's async or not is the engine and not the model, which means that it will probably be easier to implement because both Beanie and Automatic, both are async. But having the engine being the one that is async or not will allow implementing a regular or blocking version of it so that you could have MongoDB models that are shared and reused for async code and for blocking code in the same application. So you can migrate more slowly or things like that. But I think both are doing a great job and have a very nice interface that is very close to Pythonic. - Yeah, just as a sidebar, I do wish it was easier in Python to convert an async call to a synchronous call, knowing that it would block. just go like, okay, here's a async method. If I could just go dot wait or dot result or something and just make it execute and basically stop the async running from there. Then you could just do the query like dot, like give me the answer, right? Whereas it's a little more tricky. You've got to get it like in the loop and run the loop to completion and stuff like that. - Yeah, but you know, like that's why I just built a asyncer which is built on top of any IO. And the idea is that you have this function asyncify and the function syncify just to do that. So you can pass one function that is async, and it will be run inside of the main event loop in async way. Or you can say, asyncify this thing, and it will run the blocking function in a thread pool so that it's not blocking the main event loop and all this stuff. But it's actually, the work is actually all done by Any.io. It's again, just doing the same thing of getting type annotations and auto completion and all the stuff on top of the thing that is actually doing the work. - Yeah, I definitely came across this not long ago and it looks very exciting. And I wanted to talk to you about it, but as you can see, we're way over time already for just our main things. Let's go back to it, but maybe next time you're on, we could just talk about async stuff all day. Mike out there asks, "What is the risk of using it in production?" The risk is the risk that you have for using any software in production. - Maybe rephrase it. So what is the readiness for production, I guess, is probably what he was thinking. - Yeah, so the thing is, most of the work is done by Pagliantic and SQLAlchemy, and they have been used for years, and they are doing an amazing job, and they are already used by a lot of tools. SQLModel only does a little bit of extra stuff on top, just so that you're gonna need all the type annotations. Most of the work is done by those. The other thing is that the test coverage is at 97%. So you have some certainty that it's working as intended at least. I want to have it at 100% and I want to have tests in continuous integration with several databases, because right now the tests are only run in SQLite. But you know that all the SQL stuff is actually done by SQLAlchemy, which is already tested in all the databases. So, you know, like there's this trade-off of trying this thing that still has a little bit of extra stuff to do. But most of the extra things that I will do on top of SQL model are actually documentation. Not that much code changes. - And the ability to flip from one to the other pretty quickly means if you had to say, "Oh no, this isn't working out, we're switching back." It's not like, "Oh, well, you're completely rewriting it." - Yeah. - It's not that much work. - You just have to make sure that you pin the versions and you upgrade correctly, but otherwise it should work. And you will get more certainty about the code correctness because you have all the type help. So yeah. - Yep. All right, we got one question left. You have this ability to take what are often somewhat existing APIs and then improve them in ways that people really connect with, right? Like fast API didn't start from open TCP socket and let's start from there. It started on top of Starlet, right? Like you already mentioned Tom Christie. This is on top of two very important libraries that they should go together, but didn't. So the question Pierre asks is, how did you learn to sort of come up with APIs like you have? Like what's your recipe for building this? - I think the thing is that I have been always trying to solve a problem. And I have always trying to improve my own developer experience and to improve the way that things work for me. And like, I have ended up just like trying to understand what is the best way to achieve those things. And at some point I ended up learning a little bit of type annotations. And I realized that, hey, this can be super powerful. I can reuse it for different things. And after looking and looking for different frameworks that did what I wanted, I ended up like saying like, OK, I just have to build this because it doesn't exist yet. But it was just like trying to achieve getting the thing that I want. For example, I wouldn't go and build a NoSQL model for MongoDB because there's already Beanie and Nodemantic. They are already solving the problem. I tried to avoid building new things. But when there's the case that nothing is really solving the thing that I want to have, I go and try to build it. The other thing is, I think one of the main features about these tools is just the documentation. And I guess like the only thing about that is that I write it as I will have liked to learn those things when I was just starting, I'm not struggling to understand where all these things. And I always have in mind like, how will the newbie learn the thing and understand it? I guess that's probably the main thing that I'm trying to, to make it as easy to use as possible. - Yeah, I feel there's a strong blend of like, let's take the new things that are really useful that maybe not everyone's using and make them very accessible, make them very easy and default and so on, yeah. - Yeah, that's the value spirit, I think. - Yeah, absolutely. All right, well, that's all the questions. We've been going a little bit long, but I really appreciate the time. Let's just real quickly ask you the final two questions and let you get out of here. All right. - Awesome. So if you're gonna write some Python code, work on SQL model or something else, what editor do you use these days? - I think the both main editors, Visual Studio Code and Python are doing an amazing job at supporting all these tools. Right now my main one is Visual Studio Code, but yeah, I will just-- - Yeah, right on. Okay, very good, very good. And then notable PyPI packages, I feel like we touched on these a little bit, but-- - Yeah, we just mentioned them, Oathmantic and Beanie for doing the same SQL model stuff, but for MongoDB. - Yeah, right on. I agree, those are both great. All right, Sebastian, it was great to have you back and congratulations on SQL model. Maybe next time we'll talk async. What do you think? - Awesome, sounds great. Thank you very much, Michael, for inviting me. Thank you everyone for staying this long.
Info
Channel: Talk Python
Views: 34,894
Rating: undefined out of 5
Keywords:
Id: BTCtKWpNoRI
Channel Id: undefined
Length: 82min 10sec (4930 seconds)
Published: Tue Jan 18 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.