[HN Gopher] Migrating to SQLAlchemy 2.0 ___________________________________________________________________ Migrating to SQLAlchemy 2.0 Author : brainless Score : 138 points Date : 2021-02-18 17:28 UTC (5 hours ago) (HTM) web link (docs.sqlalchemy.org) (TXT) w3m dump (docs.sqlalchemy.org) | parhamn wrote: | I've seen quite a few shops which effectively hit every python | db/networking/pooling foot gun you could possibly encounter while | using SQLAlchemy. | | People cargo cult the flask intro tutorial and have no clue how | session binding works, where the transactions are, how committing | works, etc because it's all tucked away in magical middleware and | singletons. As the code base grows so does the mess of blocking | txns, accidental cross joins, pool exhaustion, and so on. | | It's a great tool from a technical expressiveness perspective but | terribly full of operational foot guns. Beware and use Django | until you're sure you AND your team know what you're doing. | nodamage wrote: | Do you mind elaborating on these what these foot guns are and | how to avoid them? | ergo14 wrote: | We are running sqlalchemy in a giant environment - hundreds of | millions of users. SQLAlchemy has been a blessing for us. Blame | users that use flask-alchemy or whatever else is cool. This is | exactly the same type of comment that blames ORM-s for | ineffective SQL being used because people don't know how to | write the queries in the first place. | parhamn wrote: | > Blame users that use... | | I am, and I'm warning them, whats wrong with that? | TomBombadildoze wrote: | You put it better than I could. There are certainly naive | examples of how to use it out in the wild but that's not | SQLAlchemy's fault. It's a sophisticated tool that accurately | reflects how a database works. | | I caution people _against_ using Django because the ORM makes | so many weak, simplified assumptions about how a database | works that don 't bear out in practice. It's fine for a blog. | It falls apart when you're working with Real Data. | kennydude wrote: | I've used Django with "real data", as in accountancy | software for multiple years of transactions across 200+ | fairly large clients and it's absolutely fine. | | Whereas I've used Sqlalchemy and getting it to do a basic | join, turns out there's 3 different ways of doing it all | with an insane amount of crap to find the right way of | doing things. I actually left my old job in part due to | Sqlalchemy being too painful to work with. | ergo14 wrote: | Like... Query.join(), https://docs.sqlalchemy.org/en/13/o | rm/tutorial.html#querying... . | BiteCode_dev wrote: | There is absolutely a lack of a decent SQLA tutorial for | IRL code. | | The doc is very formal, and if you want to make a | website, a quick script or a data migration, you are left | on your own to find the proper setup. | orf wrote: | What weak assumptions does it make? | Topgamer7 wrote: | Yeah our org should really move away from flask-sqlalchemy | and be more declarative about what session changes should | actually be made on. | | Being more hands on with sqlalchemy is probably the right | approach. | danjac wrote: | Not having touched this stack in a while: what is best | current practice for wiring together sqlalchemy and flask | (including unit tests)? | returningfory2 wrote: | Potentially don't wire them together? That is, isolate | them in separate parts of the code. | | I always found Flask-SQLAlchemy a strange approach | because it ties opposite and somewhat orthogonal parts of | the request lifecycle together. When requests-to-data- | transactions is a 1-1 relationship it's a convenience, | but once you step out of that I think it's better to do | things by hand. | | My main app has a simple layer structure of "request > | business logic > data layer". All of the business logic | functions start a SQLAlchemy transaction using a Python | decorator that is ~10 lines of SQLAlchemy code. | ergo14 wrote: | Check out how things are wired with in this Pyramid | cookie cutter. | | https://github.com/Pylons/pyramid-cookiecutter- | starter/blob/... | | I think same approach should work well for flask - just | tie the session to the request object on first access. | | Side note: I think we met on IRC few years ago ;-) | luhn wrote: | There is a _lot_ going on in that cookie cutter. The | "transaction" library for transaction management, wired | into Pyramid with pyramid_tm, wired into SQLAlchemy with | zope.sqlalchemy. Works nicely for Pyramid, but I don't | know how that translates to Flask. | ergo14 wrote: | Doesn't, I wanted to show how it can be wired to request. | jononor wrote: | I passed on flask-sqlalchemy because it was not obvious to | me how it worked together, and I did not see the value over | just using Flask and SQLAlchemy with no special | integration. Has worked now a couple of years in, will see | how it is in a few years more. | msluyter wrote: | Example: a team I was on was using SQLAlchemy and we had a | couple of services, one that did read only queries, and another | that did writes and occasionally DDL (rebuilding the table on | the fly, (which is unwise but that's a topic for another | post.)) Because we didn't understand SQLAlchemy's default | semantics, the read side would effectively open a transaction | and leave it open, meaning that subsequent DDL statements would | block, then causing the entire table to lock. (I think our | solution was to use `autocommit=True`, which iirc is now | deprecated.) | | That said, I really like SQLAlchemy. | ergo14 wrote: | The trick is to always auto close transactions at the end of | the request. | You-Are-Right wrote: | Please describe footguns and how to avoid. Thanks! | BiteCode_dev wrote: | > Beware and use Django until you're sure you AND your team | know what you're doing. | | That's one of my pet peeve in the Python world: people thinks | Flask is for beginners and Django for advanced users. The Flask | API is simple, the hello world is 5 lines. By the time you | render your first Django ViewModel, you have read and tried out | the full Flask doc. | | So it's easy to say, "I'll start with Flask, and check out this | Django thing later". | | But in reality, it's exactly the opposite. Flask requires you | to know a lot of things and make a lot of decisions, not to | mention select/write additional libraries for features Django | packs. | | So if you use Flask for anything non trivial, you should show | your trade or you are going to mess up, big time. | | If you are a beginner, you should always start with Django. | Yes, it's more work up front, but it will give you an idea of | how important concepts work, plug in to each others, and can be | organized in a code base. | | Django is not perfect, and its ORM is really far from | SQLAlachemy, but it's good enough for a loads of thing. And it | will be mostly secure and extensible by default. | mrRandomGuy wrote: | 100% | | The upfront cost of Django makes people thing it's much more | complicated than a micro-framework like Flask. | | I like Flask, but not because it's a simple easy to use | framework, especially once you chuck SQLAlchemy into the mix. | Shit, even now if I don't touch it for a while I end up | trying to remember how things work | zzzeek wrote: | SQLAlchemy author here. | | Your comment states the problem space addressed by SQLAlchemy | 2.0, which is what the above document is about, really well! So | for your comment to have value, what did you think of | SQLAlchemy 2.0's direction in how it seeks to vastly improve | the very issues you speak of, "where the transactions are", | "how committing works", etc.? | | For example: "accidental cross joins" - SQLAlchemy 1.4 now | warns/ raises for these: | https://docs.sqlalchemy.org/en/14/changelog/migration_14.htm... | cool huh? The new docs are worth a read before commenting. | | It sounds like you were relying on flask-sqlalchemy in any case | which unfortunately makes some poor decisions in these areas, | but in SQLAlchemy 2.0 these things are brought forward | unconditionally in all cases so you really can't talk to the | database without having your transaction and its scope front | and center. | parhamn wrote: | I'm sorry if my comment struck negatively with you. The | library has been very useful to me and teams Ive worked with | in the past. In fact, I've lobbied for corporate sponsorship | of your work a few times. Thank you. | | The problem I'm describing isn't really the ORM libraries' | fault as its outside the scope (hah). Your library is great. | Most of the trouble I see is where the ORM meets the web | framework. I think that gets tricky for lower experience | developers because it's fundamentally tricky in Python. What | the scheduler (e.g. gunicorn) does and how it forks and how | sessions are handled at the wsgi layer are where you have to | be very careful. Django has brought that in scope and you | haven't -- which is why thats a better wholistic webdev | experience and SQLAlchemy is the more powerful ORM. | | With that said I stand by my comment having read the full | changelog (commendably thorough btw). Unless you can afford | to figure those things out as a team, it would behoove most | web devs to reach for Django first. | zzzeek wrote: | no worries, I'm pretty known for being reactive to comments | of all kinds, it's both a feature and a bug. SQLAlchemy was | never meant to be as "simple" as django but I just dont | want people to be scared off of it; that said, I'm super | glad everyone who uses django sticks with django because | they would be very grumpy SQLAlchemy users. the idea is | supposed to be, make a larger investment upfront, get a | bigger payoff. it's a tough balloon to float which is why | I'm always nosing around people's twitter threads. | luord wrote: | I'm particularly interested in the support for dataclasses. It's | going to make modeling the application while decoupling from the | data layer itself easier, I think. | stilisstuk wrote: | Why is nobody ever writing raw SQL? I've never understood why | ORMs are sine qua min. | oblio wrote: | Do you mean "sine qua non"? | | People don't generally like writing raw SQL because you have to | map the results to and from your programming language. So at a | minimum, you need a query builder that does some minimal and | flexible mapping. | stilisstuk wrote: | Ha. Yes. I apologise for the auto correct. | | Building basic CRUD apps as a hobbyist, I've just never had | that problem. My app needs some data. I fire of a query af | psocopg2 gives me back my data. | | I know I'm the least experienced. So I'm not arguing. I just | don't understand it | | (I work mostly be with data / BI, so I'm familiar with SQL) | ergo14 wrote: | Imagine be you build a "search users" page with many | filters, you will end up inventing query builder at one | point. The more dynamic data you need, you will end up | reinventing those systems. The worst that can happen is | when you start concatenating sql queries together.ORM/query | builders save you that headache. | stilisstuk wrote: | Yes..i have concatenated SQL i must admit. | scrollaway wrote: | It's easy to write raw SQL queries. It's a lot harder to | generate SQL programmatically, correctly, based on a variety of | requirements your app may have. ORMs do this well. | baq wrote: | Raw sql is not composable. | bityard wrote: | There is a middle-ground between writing SQL statement | strings in your code, and a full-blown ORM: query builders. | At least in my experience with small to medium projects, | these have far fewer footguns while keeping the code | composable and readable. Here's one for Python: | https://github.com/kayak/pypika | nrmitchi wrote: | I'll just say that SQLAlchemy can also be used effectively | as just a query builder in places that you need it. | evgen wrote: | You can write direct SQL queries using SQLAlchemy Core without | engaging the ORM layer at all. It protects you from a few of | the footguns associated with raw SQL but still provides most of | the power and features you would want from raw SQL. If you | decide that some part of your system could use the ORM then it | is easy to integrate it into your existing Core work or visa | versa. | Hamuko wrote: | If you want to use an SQL database with an OOP language like | Python, you will end up using an ORM library, or writing one. | asah wrote: | For record/object-at-a-time, an ORM saves tons of code. | | SQL's design is optimized for processing unordered sets of | records. | nodamage wrote: | How do people who prefer to write raw SQL usually deal with: | | 1. Query building, particularly when the query needs to be | dynamic based on user input? Do you end up concatenating | strings together or do you use a separate query builder? | | 2. Coalescing result sets produced by JOINs back into object | form? Example: if you want to fetch users along with all their | posts your query will return multiple rows per user, but when | working with objects in your app you want each user to have a | list of posts so you can simply say _users.posts_. | | 3. Property change tracking? Example: different parts of your | app might update different properties for each user. If the | user's _email_ and _last_login_ changes you need to write one | query. If the user 's _password_ changes you need to write a | different query. If the user 's _email_ , _name_ , and | _location_ changes you need to write another query. An ORM with | change tracking will figure out exactly which properties have | been modified and issue the correct SQL to update only the | changed properties. When working with raw SQL do you simply end | up writing different queries for each possible permutation of | changes? | bagol wrote: | Because you won't use raw SQL on any serious project forever. | You'll end up building an ORM yourself or at least a query | builder. | [deleted] | radus wrote: | The description of the new direction for 2.0 sounds great, but as | someone who isn't using SQLAlchemy currently (I prefer peewee) | I'd be curious to see what it looks like without the assumption | that I'm migrating from a previous version. I guess that's not | yet fully settled? | bratao wrote: | My company is migrating from peewee to SQLAlchemy because the | missing async support and we faced many bugs related to multi- | threading/multi-processing. | zzzeek wrote: | that's what the tutorial is for - assumes 2.0 style usage and | nothing else: | | https://docs.sqlalchemy.org/en/14/tutorial/index.html | aidos wrote: | OT: but I'm seeing a weird layout issue on the new docs on | mobile (iOS) where the main content is dropping below the | bottom of the sidebar position. | | https://imgur.com/a/U4AbEOZ | zzzeek wrote: | i would _LOVE_ if someone could help us get the site to | work on mobile. I can point folks to our scss and all of | that and get it all going if someone can help. agree mobile | is mostly unusable and new layout has probably some more | problems since I started using flex layout for which I am | unqualified to be touching. | hambos22 wrote: | Please drop me an email (you can find it on my profile | here). SQLA is my go-to library for lots of stuff, I | would love to help :) | zzzeek wrote: | I'm not seeing an email address can you tweet me on | twitter? | | Basically if someone can show me how to make the sidebar | vanish on a mobile browser i think that's the main thing. | i might have looked at this some time ago and given up. | aidos wrote: | Happy to help with this. Will take a look tomorrow. | hambos22 wrote: | Indeed, I must removed it a while ago. Please ping me at | me[at]cpoul.dev and I'll check it asap | 1337shadow wrote: | This is documentation for 1.4: | | https://docs.sqlalchemy.org/en/14/contents.html | | If I understand correctly, 2.0 will basically be 1.4 but | without the DeprecationWarnings, and without the deprecated | APIs - at least, that's how I've been coding for 2.0 so far, | initially to benefit from asyncio support. | avolcano wrote: | One of the most interesting 1.4/2.0 changes is first-class | asyncio support, not just for core (the query builder) but for | the ORM layer as well: | https://docs.sqlalchemy.org/en/14/changelog/migration_14.htm... | | As this notes, there's several changes you have to make to your | assumptions around the ORM interface. SQLAlchemy, for better or | worse, supports "lazy loading" of relationships on attribute | access - that is, simply accessing `user.friends` would trigger a | query to select a user's friends. This kind of magic is at odds | with async/await execution models, where you would instead need | to run something like `await user.get_friends()` for non-blocking | i/o. | | It looks like they've done some good work in making the ORM layer | work reasonably well with these limitations (https://docs.sqlalch | emy.org/en/14/orm/extensions/asyncio.htm...), but I wonder if | removing "helpful magic" like this will push more people to stick | with the query-builder, rather than the ORM. | aidos wrote: | It was really interesting. I saw the discussions about it where | zzzeek was like, "oh, what, I could kinda just make this | wrapper thing. Wait, what am I missing here? Nope, it works" | | It was a late entry into the transition rather than a planned | thing from what I could tell. | | Edit: post is here | https://gist.github.com/zzzeek/2a8d94b03e46b8676a063a32f7814... | orf wrote: | So the secret sauce was just greenlet? | psychometry wrote: | I kind of wish some of the SQLAlchemy core devs spent a bit of | time using ActiveRecord to appreciate how an ORM can make | defining and querying relations straightforward and easy. | | Right now, using SQLAlchemy creates a "now you have two problems" | kind of workflow: first you figure out the SQL need, then you | spend at least that long figuring out how to write it with the | ORM. I never felt this way about ActiveRecord. | [deleted] | luhn wrote: | Honestly that's my favorite part about SQLAlchemy--you need to | think in SQL. It doesn't try to hide anything behind leaky | abstractions, it's WYSIWYG. Just gives us the good parts of an | ORM while sidestepping the whole "ORMs are the Vietnam of | Computer Science" problem. | sirn wrote: | I think this is fundamental design difference between | SQLAlchemy and ActiveRecord in general. SQLAlchemy uses Data | Mapper pattern which does not necessary map 1:1 to the row in | the database, so you have to deal with the whole (Object, | Mapper, Data) tuple instead of just Object in case of Active | Record pattern (of which Rails' ActiveRecord were based on). | | This means SQLAlchemy does not try to hide away SQL, which is | beneficial in dealing with complex queries. In Rails | ActiveRecord you could use arel in such case but being a query | builder it lose the benefit of ActiveRecord, whereas in | SQLAlchemy it could be done relatively easily within the ORM | layer (arel equivalent in SQLAlchemy would be its Expression | Language). On the other hand, some things that are complicated | in ActiveRecord can also be trivial to implement in SQLAlchemy | (e.g., column_property[1]) | | [1]: https://docs.sqlalchemy.org/en/13/orm/mapped_sql_expr.html | michelpp wrote: | > I kind of wish some of the SQLAlchemy core devs spent a bit | of time using ActiveRecord to appreciate how an ORM can make | defining and querying relations straightforward and easy. | | The main SQLA developer, and the whole team, has been doing | this now for almost 3 decades, has presented on and had | thousands of serious detailed technical discussions on the | subject with a diverse range of industry participants, and I | can assure you is WELL aware of how ActiveRecord works and all | of the patterns around it. | qbasic_forever wrote: | And? Is it a documentation problem then, that the SQL alchemy | devs don't think it's worth the time to explain to devs | familiar with active record what they gain using SQLA? | zzzeek wrote: | you get to think in terms of SQL and relational algebra is | the basic idea. Here's one of my talks that discusses this: | https://www.sqlalchemy.org/library.html#handcodedapplicatio | n... | | as for "it's hard to translate from SQL to ORM" that's a | huge part of what 1.4/2.0 is trying to make more obvious. | But to be fair I get very few "how do I write this in SQL" | questions these days as things are pretty 1-1 in any case | now; the remaining weak spots (awkwardness with unions, | support for table-valued expressions) are addressed in | 1.4/2.0 and the relatively awkward "session.query()" model | is now legacy. | michelpp wrote: | Search "sqlalchemy activerecord" and you will find | tutorials, compare and contrast posts, pros and cons, and | several implementations for sqlalchemy and many other | languages and libraries using the activerecord pattern. | | SQLAlchemy, and Python in general, is highly extensible, it | can do the ActiveRecord pattern and many other patterns | depending on the data, not just the needs of a content | publication system. | | Here's a couple random AR/SQLA implementations I plucked | from DDG: | | https://pypi.org/project/sqlalchemy-mixins/ | | https://pypi.org/project/Flask-ActiveRecord/ | qbasic_forever wrote: | Modeling their migration off the Python 2 -> 3 migration. Bold | move, let's see how that works out for them. | grouseway wrote: | Lots of major changes, so I hope it doesn't create a schism. | | Do SQLAlchemy users appreciate how lucky they are? I generally | prefer to use c#/.net but the 3 Microsoft ORMs (linq-to-sql, ef, | ef.core) are all half baked. I don't know much about | ActiveRecord, Django or other ORMs. | | I wish I could have this sort of feature set and dynamic | abilities that I get in sqlalchemy on the .net side. I say that | as someone who loves SQL but appreciates the conveniences of a | powerful ORM. | sirn wrote: | There have been so many times where I started a new project in | a new shiny language and ended up coming back to Python because | I love SQLAlchemy (and Pyramid) way too much. It's one of the | few ORMs out there that doesn't hate you for liking SQL. | ergo14 wrote: | Same here, I'd like to dive into golang. But there is nothing | as good as SQLAlchemy. Maybe with generics we will start | seeing some projects that can fill the gap. | enjeyw wrote: | Mmm yeah I had the same experience. My end conclusion for | Golang was "don't use an ORM". | nrmitchi wrote: | > doesn't hate you for liking SQL | | This, just 100% this. I'm not a major fan of SQL or anything, | however I get very hesitant to use any ORM that tries to | imply that you don't need to understand how SQL or the | underlying database actually works. | | Any time I hear someone say that "SQL won't scale for my | app", I assume that some rudimentary query analysis would | solve 99% of problems. | bitexploder wrote: | Django ORM has grown on me. I think it isn't quite as powerful | as SQLAlchemy, but it is really quite decent. SQLAlchemy lets | me think closer to SQL if I want to, and that is nice as well. | I tend to use the Django ORM the most lately... but all 3 of | those are rather full featured and accomplish the average | user's needs. SQLA is still my favorite ORM anywhere. | fernandotakai wrote: | same! i like that SQLAlchemy made me actually learn SQL. | | but for like, boilerplate stuff, Django's ORM works so well. | also, because it's all within the same "framework", every | single library can adapt super well to it and more a shitton | of dumb code from your hands. | liquidify wrote: | I used their ORM library in a medium sized project. As the | project grew, it turned a nightmare scenario. After that | experience, I stick to core and raw SQL queries. I hope 2.0 | brings some meaningful changes. | swagonomixxx wrote: | Agreed. I will never recommend an ORM, things simply spiraled | out of control for medium to large-ish projects that had more | than 2 developers. Even with "best practices", code ended up | having a mix of raw SQL and ORM-style queries, and it was hard | to reason about the code. | | Since switching to asyncpg [0] these problems have vanished. It | commands a deeper knowledge of actual SQL, but I would argue | this knowledge is absolutely necessary and one of the | disadvantages of an ORM is that it makes the SQL that is | eventually run opaque. | | Not sure if there are equivalents to asyncpg for other RDBMS's. | | [0]: https://github.com/MagicStack/asyncpg | gigatexal wrote: | I got my start in IT as a DBA. SQL and good table design come | naturally. So when it came time to join a company as a developer | I sprang for raw SQL only to find this SQLalchemy ORM. I couldn't | wrap my head around it at first. All the ceremony to get to what | I wanted to do just got in the way. I felt trapped. But it's | ubiquitous and I have to adapt. So I'm learning. And there's a | whole lot of benefit being able to define a model and have it | render on any database. Paired with Alembic migrations can be | pretty simple. | | I miss having 100% control over the queries, knowing exactly how | they looked and analyzing each before committing them to main. | But nobody has the time to hand craft artisanal queries and | leverage every intricate detail of a database when they're trying | to move ever faster and ship features. ___________________________________________________________________ (page generated 2021-02-18 23:00 UTC)