F1 레이스에서 이런 상황을 상상해보자. 엔지니어가 랩마다 엔진 온도를 측정해 기록 시스템에 입력한다. 1랩에 36.5도, 2랩에 37.1도, 3랩에 36.8도 — 입력할 때마다 데이터가 하나씩 쌓이고, 레이스가 끝난 뒤 팀은 전체 기록을 꺼내 분석한다. 이 흐름을 웹 앱으로 구현할 때 Django ORM이 핵심 역할을 한다.
ORM 이란 무엇인지, 데이터가 입력될 때마다 DB에 어떻게 누적되는지, 그리고 ORM 없이 직접 SQL을 쓰면 무엇이 달라지는지를 이 온도 데이터 예시로 풀어낸다.
ORM 이란 무엇인가 — Python과 DB를 연결하는 번역 계층
ORM은 Object Relational Mapping의 약자다. Python 객체와 관계형 DB 테이블을 연결해주는 번역 계층이다. 개발자가 Python으로 명령을 내리면 Django ORM이 이를 SQL로 변환해 DB에 전달하고, 결과를 다시 Python 객체로 돌려준다.
ORM 이란 개념을 이해하는 가장 빠른 방법은 세 가지 개념을 구분하는 것이다.
| 개념 | DB에서의 의미 | 온도 예시 |
|---|---|---|
| 클래스 | 테이블 설계도 | “value와 recorded_at 컬럼을 가진 테이블” |
| 클래스 속성(필드) | 컬럼 | value, recorded_at |
| 클래스 인스턴스 | 저장된 행(row) 하나 | “36.5도, 2026-03-31 09:00” |
클래스는 설계도일 뿐, 데이터를 직접 담지 않는다. 데이터가 10개면 인스턴스가 10개 DB에 쌓이는 것이지, models.py에 10줄이 추가되는 게 아니다. 이 구분이 ORM 이란 개념의 출발점이다.
SQL 없이 DB를 다루는 법 — Django ORM이 하는 일
Django ORM의 DB 조작은 모두 클래스명.objects.명령어() 형태다. objects가 Python과 DB 사이의 중간 관리자 역할을 한다.
| 작업 | SQL | Django ORM |
|---|---|---|
| 저장 | INSERT INTO ... | objects.create() |
| 전체 조회 | SELECT * FROM ... | objects.all() |
| 조건 검색 | WHERE value = 36.5 | objects.filter(value=36.5) |
| 삭제 | DELETE FROM ... | objects.delete() |
중요한 점은 DB 종류와 무관하게 이 코드가 그대로 동작한다는 것이다. SQLite를 쓰든 PostgreSQL을 쓰든 objects.create() 한 줄이면 저장된다. ORM 이란 결국 각 DB에 맞는 SQL로 내부에서 번역해주는 통역사다.
데이터 입력부터 저장까지 — 파일별 역할 정리
Django에서 사용자가 온도를 입력하고 DB에 저장되는 흐름은 4개 파일이 담당한다.
브라우저 입력 → urls.py → views.py → models.py → DB
models.py — 설계도 DB 테이블 구조를 Python 클래스로 정의한다. 최초 1회 작성 후 makemigrations → migrate 명령으로 실제 DB에 반영한다. 이후 데이터가 아무리 쌓여도 이 파일은 바뀌지 않는다.
urls.py — 교통 정리 어떤 URL 요청을 어떤 views.py 함수로 보낼지 연결한다. 이 파일이 없으면 요청이 어디로 가야 할지 Django가 판단할 수 없다.
views.py — 두뇌 요청 종류에 따라 다르게 동작한다. POST 요청(폼 제출)이면 입력값을 꺼내 ORM으로 DB에 저장한다. GET 요청(페이지 열기)이면 DB에서 데이터를 조회해 템플릿에 넘긴다.
template — 화면 사용자에게 입력 폼을 보여주고, views.py가 넘겨준 데이터를 화면에 출력한다.
| 파일 | 역할 | 저장 기능에서의 위치 |
|---|---|---|
| models.py | 테이블 구조 정의 | 최초 1회 설계 |
| urls.py | 요청 경로 연결 | 요청을 views.py로 전달 |
| views.py | 저장 명령 실행 | ORM 호출의 주체 |
| template | 입력 창구 | 사용자 데이터 수집 |
데이터가 누적되는 메커니즘
여기서 중요한 점이 있다. models.py는 최초 1회 설계로 끝나지만, views.py는 입력이 들어올 때마다 매번 실행된다. F1 엔지니어가 랩마다 온도를 입력하는 상황을 그대로 대입하면 아래와 같다.
models.py → "value와 recorded_at 컬럼을 가진 테이블을 만들어" (최초 1회)
↓
1랩: 36.5 입력 → views.py → DB 1번 행 저장
2랩: 37.1 입력 → views.py → DB 2번 행 저장
3랩: 36.8 입력 → views.py → DB 3번 행 저장
...
10랩: 36.2 입력 → views.py → DB 10번 행 저장
F1 레이싱 Engineering 사례는 설명을 위해 구성한 가상의 시나리오다.
실제 특정 팀이나 드라이버의 데이터를 기반으로 한 것이 아님을 밝혀 둔다.
입력이 10번 발생하면 DB에 10개의 행이 쌓인다. models.py는 단 한 줄도 바뀌지 않는다. 설계도는 그대로이고, 데이터만 DB에 누적되는 구조다. 레이스가 끝난 뒤 objects.all()을 호출하면 10개의 행 전체가 한 번에 조회된다.
ORM 이란 이 구조를 가능하게 하는 핵심이다. 구조(models.py)와 데이터(DB)를 분리해서 관리하기 때문에, 데이터가 아무리 많아져도 코드는 변하지 않는다.
ORM 없이 직접 SQL을 쓰면 어떻게 달라지는가
Django ORM 없이 DB에 데이터를 저장하려면 views.py 안에 아래 단계를 모두 직접 작성해야 한다.
1. DB 연결 (connect)
2. 커서 생성
3. SQL 문자열 직접 작성
4. 실행
5. 변경 저장 (commit)
6. 연결 종료 (close)
코드가 길어지는 것뿐 아니라 하나라도 빠뜨리면 버그가 생긴다. commit을 빠뜨리면 저장이 안 되고, close를 빠뜨리면 연결이 누적된다.
| 비교 항목 | Django ORM | 직접 SQL |
|---|---|---|
| 저장 코드 | 1줄 | 6단계 직접 작성 |
| 오타 감지 | IDE가 Python 오류로 잡아줌 | 실행 전까지 모름 |
| DB 교체 시 | 설정 파일 한 줄 변경 | 전체 SQL 코드 수정 |
| 가독성 | 코드만 봐도 동작 파악 | SQL 문자열 안에 로직이 묻힘 |
특히 DB 교체 문제는 실무에서 자주 발생한다. 개발 단계에서 SQLite를 쓰다가 운영 환경에서 PostgreSQL로 바꾸는 경우가 대표적이다. 직접 SQL을 썼다면 문법 차이 때문에 코드 전체를 다시 검토해야 한다. ORM 이란 이 전환 비용을 거의 제로로 만드는 구조적 선택이다.
핵심 요약
- ORM 이란 Python 코드를 SQL로 자동 번역해 DB와 연결하는 통역 계층이다
- models.py에 클래스로 테이블 구조를 선언하면, 이후 저장과 조회는
objects.create(),objects.all()한 줄로 처리된다 - 구조(models.py)와 데이터(DB)가 분리되어 있어 데이터가 아무리 쌓여도 코드는 변하지 않는다
- ORM 없이 직접 SQL을 쓰면 저장 하나에 6단계가 필요하고, DB 교체 시 전체 코드 수정이 불가피하다
- Django ORM을 쓰는 이유는 편해서가 아니라 유지보수 비용을 구조적으로 낮추기 때문이다
[링크 제안]
Django ORM으로 데이터를 저장하는 구조를 이해했다면, 그 데이터를 분석 가능한 형태로 바꾸는 방법도 함께 챙겨두자.
코딩 입문 자체가 막막하다면 이 글이 출발점이 될 수 있다.
0.001초의 데이터 — F1이 보여주는 엔지니어링의 극한







