I'm not a fan of SQLAlchemy because of the Data Mapper pattern, and abstractions that force you to still think in terms of SQL tables and expressions.
For example, in Django I can have a User object. I want a update the user's first name:
my_user.first_name = "Joe"
my_user.save()
In SQLALchemy:
my_user.first_name = "Joe"
session.add(my_user)
session.commit()
Users can leave comments, so I want a query that aggregates comments for each user. In Django:
users = User.objects.all().prefetch_related("comments").annotate(comment_count=Count("comments"))
Each user will now have a `comment_count` property that contains the number of comments they left.
In SQLAlchemy:
session.query(User, func.count(Comment.id).label("comment_count"))
.outerjoin(User.comments)
.group_by(User.id)
.all()
However, each User won't have the `comment_count` property. You have to manually associate them from the returned tuple.
I feel like SQLAlchemy wants to force you to do more work, whereas the Django ORM wants to provide you with the data you asked without forcing to you think about how to actually get the data from the database nor how to optimize the query. In Django, session management is done automatically, but it SQLAlchemy, you need to be aware of the session most times.
It's good to know SQL but you can use the Django ORM without knowing it. Not the same with SQLAlchemy. Could be a pro or a con depending on the situation. Definitely a pro for me because I don't like SQL.