Django와 ORM

이동건·2021년 4월 6일
0

Django

목록 보기
3/4

Model

모델은 테이블을 정의하는 장고의 클래스를 말한다. 그리고 그 모델은 models.py에 정의된다.
models.py에는 테이블을 기본으로 정의하지만, 그 외에도 관련 속성이나 메소드를 정의할 수도 있다.
이렇게 클래스의 특징인 속성과 메소드를 가질 수 있는 건 ORM 방식에 기반해 테이블을 클래스로 정의하고 있기 때문에 가능한 일이다.

테이블을 클래스로 처리하는 ORM의 특징 때문에 테이블을 정의하는 모델 클래스는 속성과 메소드를 갖는다. 테이블 컬럼은 모델 클래스에서 속성으로 정의된다. 테이블에 관련된 메소드들이 모델 클래스에 정의된다.

모델 클래스에서 하나의 속성은 명시적으로 지정하지 않으면 디폴트 속성으로 들어가는 것이 있는데, objects이다.
objects는 따로 지정하지 않을경우 objects = models.Manager()가 들어가게 된다.

모델 클래스에서는 필드를 정의하기 위해 항상 필드명, 필드 타입과 필드 옵션을 지정해야 한다.

description <-필드명 = models.CharField <- 필드타입 ('One line Descrition', max_length=100, blank=True) <- 필드옵션

모델 클래스에는 메소드를 정의할 수 있는데, 클래스 메소드는 테이블 레벨에서 동작하는 메소드이고, 객체 메소드는 레코드 레벨에서 동작하는 메소드가 된다.
장고에서 클래스 메소드는 사용하지 않고 객체 메소드만 사용하기 때문에 모델 클래스에서 정의하는 모델 메소드는 모두 객체 메소드이고, 호출하면 레코드 단위에서만 영향을 미치게 된다.

그럼 테이블 레벨의 동작은 어떡해야 할까?
장고는 Manager 클래스를 정의하고 Manager 클래스의 메소드를 통해 테이블에 대한 CRUD 동작을 수행한다.
모든 모델은 Manager 속성을 가져야만 하며, Manager 속성은 모델 클래스를 통해서만 액세스 할 수 있고 모델 객체를 통해서는 액세스 할 수 없다.
Manager 속성은 models.Manager 타입으로 정의되고, 장고의 Manager 클래스를 통해 데이터베이스 쿼리가 이루어진다. 즉, 테이블 레벨의 동작은 Manager 클래스의 메소드를 통해 이루어지는 것이다.
예를 들면 Album.objects.all()을 통해 테이블 레벨의 Read 동작이 가능한 것이다.

Album은 모델 객체가 아닌 모델 클래스, object는 Manager 속성명, all은 Manager 클래스의 메소드가 된다.
Album.objects.all()는 QuerySet 객체를 반환한다. QuerySet 클래스 메소드와 Manager 클래스 메소드는 거의 동일하다. 그래서 QuerySet 메소드는 모두 Manager 메소드로 사용이 가능하다.
all(), filter(), exclude(), get(), count() 등이 가능한 것이다.
2개의 Manager 속성을 정의할 수도 있는데, 그 경우 첫 번째로 정의된 Manager가 디폴트 Manager가 된다. 추가 매니저는 따로 class를 작성하여 만들어 준다. 그럼 추가 매니저를 이용한 Manager 메소드를 사용할 때 특정 값이 필터링 된 레코드만 받을 수 있는 것이다.

Meta 내부 클래스를 정의해 모델에 대한 메타데이터를 정의할 수 있다.
모델 클래스의 필드는 아니지만 모델 클래스에 필요한 항목을 Meta 내부 클래스에 정의한다. 모델 클래스 속성인 필드 이외는 전부 Meta 내부 클래스의 속성으로 정의하는 것이다.
db_table = 'test_db'
verbose_name = "my test"
와 같은 것들이 Meta 내부 클래스에 들어가게 된다.

모델 간 관계

테이블 간에는 관계를 맺을 수 있고, 장고는 테이블 간의 관계를 3가지로 분류해 제공하고 있다. 1:N(one-to-many), N:N(many-to-many), 1:1(one-to-one) 관계이다.

이 부분을 공부하기 전에 알아야 할 개념이 두 가지 있다.

첫 번째로 관계는 양방향 개념으로, 양쪽 모델에서 정의가 필요한 게 원칙이다. 하지만 장고에서는 한쪽 클래스에서만 관계를 정의하면 이를 바탕으로 상대편 정의는 자동으로 정의해 준다.
따라서 개발자는 한쪽 클래스에서 관계가 정의했다면 반대 방향의 정의는 명시적으로 보이지 않아도 이해할 수 있어야 한다.

두 번째로 한쪽 방향으로 관계를 생성하거나 변경하면, 반대 방향으로의 관계도 그에 따라 변한다는 것이다. 장고에서는 이것 역시 알아서 처리해 주므로 개발자는 이 동작을 이해하고 있어야 한다.

1:N(one-to-many) 관계

테이블 간에 1:N 관계를 맺기 위해서는 모델의 필드를 정의할 때 ForeignKey 필드 타입을 사용하면 된다. ForeignKey 필드 타입은 필수 인자로 관계를 맺고자 하는 모델 클래스를 지정해야 한다.
즉, N 모델에서 FK 필드를 정의하면서 FK 필드의 필수 인자로 1 모델을 지정하는 방식이다.
1:N 관계에서 1쪽의 객체를 지우면 CASCADE로 동작해 N 쪽의 객체도 사라지게 된다.

N:N(many-to-many) 관계

테이블 간에 N:N 관계를 맺기 위해서는 모델의 필드를 정의할 때 ManyToManyField 필드 타입을 사용하면 된다.
관계를 맺고자 하는 모델 클래스를 필수 인자로 지정한다. 한쪽에만 지정해야 하고, 양쪽에 지정하면 안 된다.

1:1(one-to-one) 관계

테이블 간에 1:1 관계를 맺기 위해서는 모델의 필드를 정의할 때 OneToOneField 타입을 사용한다. FK와 마찬가지로 관계를 맺고자 하는 모델 클래스를 필수 인자로 지정한다.
OneToOneField 필드타입은 서로 하나의 객체만을 반환한다.

관계 매니저

Manager 클래슨느 데이터베이스에 대한 처리, 즉 데이터베이스에 쿼리를 보내고 응답을 받는 역할을 한다. 매니저 중에서 모델 간 관계에 대한 기능 및 데이터베이스 쿼리를 담당하는 클래스를 관계 매니저라고 한다.

1:N, N:N의 경우가 관계 매니저 클래스를 사용하는 경우이다.
1:1의 경우에는 상대 객체가 하나이기 때문에 관계 매니저를 사용할 필요가 없다.

1:N의 경우, 1에서 N방향으로 액세스 할 때 관계 매니저가 필요하다. 모두 불러와야 하기 때문이다.
N에서 1방향으로 액세스 하는 경우는 FK로 정의한 필드명을 사용해 액세스하면 되므로 관계 매니저는 불필요하다.

N:N의 경우는 양쪽 방향 모두 관계 매니저 클래스가 필요하다. 양쪽 모두 객체가 복수이므로 관계 매니저를 사용하는 것이다.

관계 매니저 클래스에서 제공하는 매소드 들은 다음과 같다.
add - 인자로 주어진 모델 객체들을 객체의 집합에 추가한다. 두 모델 객체간의 관계를 맺어주는 역할.

create - 새로운 객체를 생성해서 데이터베이스에 저장하고 관계 객체 집합에 넣는다. 그리고 새로 생성된 객체를 반환한다. 다시말해 상대방 모델 객체를 만들고, 두 객체 간 관계를 만들어 준다.

remove - 인자로 지정된 모델 객체들을 관계 객체 집합에서 삭제한다. 두 모델 객체 간 관계를 해제한다.

clear - 관계 객체 집합에 있는 모든 객체를 삭제한다. 관계를 맺고 있는 다른 객체들과의 관계도 모두 제거한다.

profile
코드를 통한 세계의 창조

0개의 댓글