DEV Community

Cover image for I wish I knew this before mixing SQLAlchemy ORM with raw SQL: Python Database Access, Two Ways
Negitama
Negitama

Posted on

I wish I knew this before mixing SQLAlchemy ORM with raw SQL: Python Database Access, Two Ways

I wish I knew this before mixing SQLAlchemy ORM with raw SQL: Python Database Access, Two Ways\n\nWorking with databases in Python? You’ve probably used SQLAlchemy, but did you know there are two powerful approaches: the ORM layer and the raw SQL layer? Here’s a deep dive into both, including code, pros & cons, and when to use each.\n\n## 1. Setup: Define Models with SQLAlchemy ORM\nFirst, we create our ORM models. This file (e.g., orm_models.py) defines the schema using SQLAlchemy’s declarative base.\n\n


python\nfrom sqlalchemy import Column, Integer, String, Text, create_engine\nfrom sqlalchemy.ext.declarative import declarative_base\nfrom sqlalchemy.orm import sessionmaker\n\nBase = declarative_base()\n\nclass JobDescription(Base):\n __tablename__ = 'job_description'\n id = Column(Integer, primary_key=True)\n company_id = Column(String, nullable=False)\n company_name = Column(Text, nullable=False)\n job_description = Column(Text, nullable=False)\n\nclass CandidateResume(Base):\n __tablename__ = 'candidate_resume'\n id = Column(Integer, primary_key=True)\n candidate_id = Column(String, nullable=False)\n candidate_name = Column(Text, nullable=False)\n resume = Column(Text, nullable=False)\n\nengine = create_engine('postgresql://user:password@localhost/dbname')\nSession = sessionmaker(bind=engine)\n\nif __name__ == '__main__':\n Base.metadata.create_all(engine)\n

\n\n## 2. Bit-ORM Layer: Repository Using the ORM\nUse Python objects instead of SQL!\n\n

python\nfrom orm_models import JobDescription, Session\n\ndef get_job_descriptions_by_company_orm(company_id: str):\n session = Session()\n try:\n results = session.query(JobDescription)\n .filter(JobDescription.company_id == company_id)\n .all()\n return results\n finally:\n session.close()\n\nif __name__ == '__main__':\n jobs = get_job_descriptions_by_company_orm('COMPANY_123')\n for job in jobs:\n print(f"{job.company_name}: {job.job_description}")\n

\n\n*Advantages:\n- Abstraction & Simplicity: Deal with Python objects, not SQL.\n- Maintainability: Model changes update all queries.\n- Safety: Built-in SQL injection protection.\n- Relationship Handling: Easier joins and associations.\n\nDisadvantages:\n- Overhead: Less efficient for fine-tuned queries.\n- Complexity: Advanced queries can get tricky.\n\n## 3. Bit-Out-ORM Layer: Repository Using Raw SQL\nControl and performance!\n\n

python\nfrom orm_models import engine\n\ndef get_job_descriptions_by_company_raw(company_id: str):\n with engine.connect() as connection:\n result = connection.execute(\n "SELECT id, company_id, company_name, job_description FROM job_description WHERE company_id = :company_id",\n {"company_id": company_id}\n )\n return result.fetchall()\n\nif __name__ == '__main__':\n rows = get_job_descriptions_by_company_raw('COMPANY_123')\n for row in rows:\n print(f"{row['company_name']}: {row['job_description']}")\n

\n\n
Advantages:\n- Fine-Grained Control: Optimize complex queries.\n- Transparency: See the real SQL sent.\n- Flexibility: Use database-specific features.\n\nDisadvantages:\n- Manual Mapping: More code, more risk.\n- Error-Prone: Easy to make mistakes.\n- Repetition: CRUD operations are verbose.\n\n## 4. Summary\nFor most use-cases, use the ORM. For performance-heavy or database-specific tasks, write raw SQL. Combine both for the best of both worlds!\n\nWhich approach do you prefer? Let me know in the comments!*

Build seamlessly, securely, and flexibly with MongoDB Atlas. Try free.

Build seamlessly, securely, and flexibly with MongoDB Atlas. Try free.

MongoDB Atlas lets you build and run modern apps in 125+ regions across AWS, Azure, and Google Cloud. Multi-cloud clusters distribute data seamlessly and auto-failover between providers for high availability and flexibility. Start free!

Learn More

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.