Search
🏬

Django Migration & ORM

Django는 Model을 사용하여 데이터를 생성하고 관리한다.
이와 관련된 추가적인 개념 중 대표적인게 ORMMigration이며, 이에 관한 내용을 정리한 페이지이다.
Django를 이용하며 서버를 구축할 때 굉장히 많이 사용되며, 많은 종류의 명령어와 옵션이 있기에 정리를 잘 해두면 좋다.
목차

 Model

Model 이란?

우선 ORM과 Migration에 대해 알아보기 위해 Model을 먼저 알아보자.
간단히 말하면 저장되는 데이터의 구조를 정의한 것이다. 하나의 모델하나의 테이블에 매핑된다.
예시
from django.db import models class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30)
Python
복사
예시 모델의 SQL
기본적으로 DJango에서는 PRIMARY KEY로 명시된 필드가 존재하지 않을 경우 id 필드를 자동으로 추가해준다.
CREATE TABLE myapp_person ( "id" serial NOT NULL PRIMARY KEY, "first_name" varchar(30) NOT NULL, "last_name" varchar(30) NOT NULL );
SQL
복사

Field란?

Model을 작성할 때 필드 목록을 정의해야 합니다. 이 필드들은 각 테이블의 컬럼을 정한다.
예시로 CharFieldTextField 를 사용하면 문자형 필드를 생성하게 된다.
from django.db import models class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30)
Python
복사

 Migration

Migration 이란?

모델의 변경 사항(필드 추가, 모델 삭제 등) DB에 적용하기 위한 방법이다.
관련된 명령어는 아래 4가지다.
makemigration : 모델의 변경사항을 확인하여 새로운 마이그레이션을 생성하는 명령어
migrate : Migration의 적용과 취소를 진행하는 명령어
sqlmigrate : 특정 마이그레이션의 sql 구문을 확인하는 명령어
showmigrations : 적용된 마이그레이션과 상태를 확인하는 명령어
적용 시 : [x]
미 적용 시 : [ ]
Django에서 Migration을 사용하여 DB에 적용하는 순서는 아래와 같다.
1.
makemigration 명령어를 사용하여 새로운 마이그레이션 생성 [ 식당 주문서 작성 ]
2.
1번 과정을 이용하여 생성된 마이그레이션을 migrate 명령어로 적용 [ 고객 주문 전달 ]

Migration 예시

우선 특정 앱에서 아래와 같은 Model을 생성했다고 가정하자.
from django.db import models class HelloWorld(models.Model): title = models.CharField(max_length=255, null=False) class Meta: db_table = 'helloworld'
Python
복사

1. 새로운 마이그레이션을 생성

아래 명령어로 새로운 마이그레이션을 생성한다.
앱 생성 후, 가장 처음 마이그레이션 생성은 특정 앱 이름을 지정하면 안된다. Django에서 기본적으로 생성하는 마이그레이션이 존재하기 때문이다.
# 프로젝트의 모든 앱의 마이그레이션 생성 python manage.py makemigrations # 특정 앱만 마이그레이션 생성 (처음 제외 / 가급적 앱 지정 추천) python manage.py makemigrations [app_name]
Bash
복사
/app_name/migrations 경로 아래에 xxxx_xxx.py 형태로 마이그레이션 파일이 생성된다.
파일을 확인하면 name, fields, options 등을 확인할 수 있다.
매번 마이그레이션을 생성할 때 마다 0001, 0002 ... 접두사가 붙는다.
# /app_name/migrations/0001_initial.py from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='HelloWorld', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('title', models.CharField(max_length=255)), ], options={ 'db_table': 'helloworld', }, ), ]
Python
복사

2. 생성한 마이그레이션을 적용

이제 migrate 명령어를 사용하여 생성한 마이그레이션을 적용할 수 있다.
# 프로젝트의 모든 앱의 마이그레이션 적용 python manage.py migrate # 특정 앱만 마이그레이션 생성 (처음 제외 / 가급적 앱 지정 추천) python manage.py migrate [app_name] # 특정 앱의 특정 마이그레이션 적용 (이전 버전 복원 등, 특정 마이그레이션 사용 시) python manage.py migrate [app_name] [migrationname]
Bash
복사
연결된 DB를 확인하면 생성한 모델을 이용한 마이그레이션이 잘 적용된 것을 확인할 수 있다.

만약 Migration을 잘못했다면?

이런일이 없으면 좋겠지만, 가끔 실수로 잘못 적용하거나 모델의 수정이 이루어진 경우가 존재한다.
크게 DB를 초기화해도 되는 경우와 그러면 안되는 경우가 있다.

1. DB를 다 날려도 되는 경우

보통 초반에 Migration에 미숙하거나 실수로 잘못 적용하였을 때 해당된다.
아직 실질적인 개발이 진행되지 않았을 때만 사용하는 것을 권장한다.
1.
makemigration 으로 적용되지 않은 마이그레이션을 적용시킨다.
2.
showmigrations 로 삭제를 원하는 앱의 마이그레이션 적용을 확인한다.
3.
migrate —fake [app_name] zero 명령어로 해당 앱의 마이그레이션 적용을 모두 초기화 시킨다.
4.
해당 모델로 생성한 테이블을 직접 삭제한다.

2. DB를 다 날리면 안되는 경우

협업하며 만드는 프로젝트에서 DB를 전부 날리면 큰일나기 때문에, 이전에 생성한 특정 마이그레이션으로 돌아가면 된다.
즉, 이전에 생성한 마이그레이션 파일이 존재하지 않는다면 불가능하기 때문에 주기적으로 마이그레이션 파일을 백업하는 것도 중요하다.
새롭게 생성된 마이그레이션 파일은 이전의 마이그레이션 파일의 영향을 받기 때문이다.
1.
migration [app_name] [migrationname] 명령어를 사용하여 원하는 지점의 마이그레이션으로 이동한다.
2.
잘못 생성한 마이그레이션 파일을 삭제한다.
3.
makemigration 명령어로 수정한 마이그레이션을 생성한다.

 ORM

ORM 이란?

객체(Object)와 DB의 데이터를 매핑해주는 도구이다. 즉 객체 간의 관계를 사용하여 SQL구문을 자동으로 생성하며, 직접 SQL 쿼리문을 작성할 필요 없이 데이터를 다룰 수 있는 방법이다.

ORM 예시

예시 모델
class HelloWorld(models.Model): title = models.CharField(max_length=255, null=False) content = models.CharField(max_length=255, default="테스트 값")
Python
복사
sqlmigrate 를 사용하면 위 모델을 이용한 테이블 생성 정보 쿼리를 ORM을 사용하여 만들어준다.
# sqlmigrate 결과 BEGIN; -- -- Create model HelloWorld -- CREATE TABLE "helloworld" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(255) NOT NULL, "content" varchar(255) NULL); COMMIT;
Plain Text
복사
모델을 파이썬 코드에서 가져온 후, ORM을 사용하여 다양한 명령(조회, 데이터 관리 등)을 사용할 수 있다.
예시) HelloWorld 모델을 가져와 데이터를 추가 (Django Shell 사용)
# HelloWorld 모델 가져오기 >>> from users.models import HelloWorld # title, content 값 설정 후 객체 생성 >>> HelloWorld.objects.create(title="test_title", content="test_content") <HelloWorld: HelloWorld object (1)>
Bash
복사
예시2) HelloWorld 모델을 가져와 데이터 조회 (Django Shell 사용)
# HelloWorld 모델 가져오기 >>> from users.models import HelloWorld # 테이블의 모든 데이터 중 가장 첫번째 데이터 가져오기 >>> obj = HelloWorld.objects.all().first() # 조회 >>> obj.title 'test_title' >>> obj.content 'test_content'
Bash
복사

ORM을 사용한 관리

 객체 추가

아래와 같이 모델의 인수를 사용하여 인스턴스화 후, save() 메서드를 사용하여 DB에 적용합니다.
이 구문은 SQL의 INSERT 구문을 실행합니다.
from blog.models import Blog b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.') b.save()
Python
복사

 객체 편집

아래와 같이 얻어온 객체를 사용하여 값을 변경 후, save() 메서드를 사용하여 저장합니다.
이 구문은 SQL의 UPDATE 구문을 실행합니다.
from blog.models import Blog b = Blog.objects.get(name='Beatles Blog') b.name = 'New name' b.save()
Python
복사

 객체 삭제

아래와 같이 얻어온 객체를 사용하여 delete() 메서드를 사용하여 해당 객체(레코드)를 삭제합니다.
QuerySet을 이용한 여러 개체 삭제도 가능하며, 삭제 시 지워진 오브젝트에 대한 정보가 작성된 값을 반환합니다.
from blog.models import Blog b = Blog.objects.get(name='Beatles Blog') b.delete() # 아래 값 반환 (지워진 Objects 갯수, {"지워진 object의 타입": 지워진 딕셔너리 갯수})
Python
복사
또한 실수로 모든 레코드를 삭제하는 것을 방지하기 위해, 모든 레코드 삭제 시 반드시 all()을 작성한 명령어로만 가능하다.
Entry.objects.all().delete()
Python
복사

관계를 사용하는 조회

필드에는 일대다, 다대다 관계등 연결을 위해 ForeignKey 필드 등을 사용하여 관계를 만든다.
이 연결된 관계를 이용하여 객체를 필터링 할 수 있다.
ForeignKey를 이용한 참조 종류는 아래와 같다.
정참조 : 자신이 참조하는 table을 접근하는 것. 역참조 : 자신을 참조하는 table을 접근하는 것.
Blog 테이블 예시
id
name
1
TEST Blog
2
NEW Blog
Entry 테이블 예시
Entry에서 아래와 같이 blog 필드를 정의하였고, 해당 테이블로 생성되었다.
기본적으로 관계 필드 생성 시 related_name을 설정하지 않으면 필드명_id 형태로 컬럼명이 설정되기 때문에, blog_id 로 컬럼 이름을 가정하였다.
class Entry(models.Model): headline = models.CharField(max_length=255) body_text = models.TextField() blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
Python
복사
id
headline
body_text
blog_id
1
TEST headline
TEST bodytext
1
2
NEW headline
NEW bodytext
2
모델의 소문자를 이용하여 두 모델간 사이의 Join을 위해 사용할 수 있다.
예시로 Blog 모델을 소문자로 사용하여 Entry 모델과 JOIN을 시도한 예시이다.
Shell
# name값이 'TEST Blog'인 Blog 객체와 관계가 연결된 Entry 객체 필터링 Entry.objects.filter(blog__name='TEST Blog')
Python
복사
SQL
SELECT e.* FROM entry AS e JOIN blog AS b ON e.blog_id = b.id WHERE b.name = 'TEST Blog'
SQL
복사
이는 역방향으로도 JOIN이 가능하다.
예시로 Entry 모델을 소문자로 사용하여 Blog 모델과 JOIN을 시도한 예시이다.
Shell
# headline값에 'TEST' 문자가 포함된 Entry 객체와 관계가 연결된 Blog 객체 필터링 Blog.objects.filter(entry__headline__contains='TEST')
Python
복사
SQL
SELECT b.* FROM blog AS b JOIN entry AS e ON b.id = e.blog_id WHERE e.headline LIKE '%TEST%'
SQL
복사
이런 방법으로 관계를 이용하여 조회할때는 아래와 같이 , 로 구분하거나, filter() 메서드를 중첩하여 사용 가능하다.
예시 1
Blog.objects.filter(entry__headline__contains='Lennon', entry__pub_date__year=2008)
Python
복사
예시 2
Blog.objects.filter(entry__headline__contains='Lennon').filter(entry__pub_date__year=2008)
Python
복사

참고

이름
태그
URL
COUNT14