본문 바로가기
Coding/Python

Django Model 정리

by Hide­ 2018. 4. 19.
반응형

1.

Django에서 모델을 정의하다보면 같은 내용을 반복해서 작성해야하는 경우가 있다.

이럴때는 class를 하나 만들고 해당 클래스를 타 클래스들에서 상속받아서 사용하는게 편하다.

하지만 그냥 생성만 하면 안되고 장고에게 이건 Abstract Class라는것을 알려줘야 한다.

아래의 방법으로 알려주면 된다.


from django.db import models

class TimeStampedModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

class Meta:
abstract = True

이런식으로 class Meta를 만들고 abstract = True를 주면 알아서 Abstract Class라고 생각한다.

(Abstract Class이기 때문에 데이터베이스와 연결되지 않는다)

이후 타 클래스에서 class Test(TimeStampedModel) 형식으로 상속받은 후 사용하면 됨.


2.

models.ImageField()를 사용하려고 하면 아래와 같은 에러가 발생할때가 있다.


Cannot use ImageField because Pillow is not installed.

HINT: Get Pillow at https://pypi.python.org/pypi/Pillow or run command "pip install Pillow".


이럴 경우 다음의 명령어로 Pillow를 설치해주면 해결된다.


pip install Pillow


3.

모델을 구성하다보면 1:N, M:N관계가 필요할 경우가 종종 생긴다.

먼저 1:N부터 생각해보자면, 하나의 사진이 여러개의 좋아요를 받을 때가 적절한 예이다.

Image와 Like두개의 모델이 존재한다고 가정한다.

그렇다면 Like모델에 다음의 필드를 추가해준다.


image = ForeignKey(Image, null=True)


첫번째 인자는 참조할 모델명이고 두번째부터는 옵션이다.

예를 들어 좋아요를 누른 이미지가 없을 경우 값이 공백이어야 하기 때문에 null=True옵션을 줬다.

(Foreign Key는 공백이 허용되지 않기 때문에 null=True로 강제로 허용해줌)


first_image = Image.objects.create(name='test')

golike = Like.objects.get(pk=1)

golike.image = first_image

golike.save()


위와 같이 명령어를 준다면 Like 필드에 있는 id=1값의 image필드에

name이 test인 Image의 PK가 담긴다.

예를 들어 Image모델에 subtitle이라는 컬럼이 있다고 가정해보자.

지금 Like모델의 image필드가 Image모델을 참조하고 있으므로

golike.image.subtitle을 출력해보면 Image모델의 값도 출력해줄 수 있다.

쉽게 말해서 Foreign Key가 참조하고 있는 모델의 값도 가져올 수 있다고 생각하면 된다.

또한 이런식으로 FK를 지정하면 자동으로 _set이라는 필드가 생성된다. (참조하는모델명_set형태)

위 예제는 Like모델의 image필드가 Image모델을 참조하고 있으므로

like_set이라는 필드가 Image모델에 생성된다.

(알아둬야할 점은 _set은 실제로 데이터베이스의 컬럼 형태로 생성되진 않는다)

그렇기 때문에 다음과 같이 _set을 통해 연결된 모든 Like를 불러올 수 있다.


first_image = Image.objects.get(pk=2)

first_image_likes = first_image.like_set.all()


위처럼 set을 이용하여 모든 오브젝트를 가져올 수 있다.

다시 한번 말하지만 Image모델에 like_set이 생성된 이유는 Like모델의 특정 필드가 Image모델을 Foreign Key로 지정했기 때문이다.


다음으로 M:N은 많은 유저가 또다른 많은 유저들을 팔로우하는 경우를 생각하면 된다.

예를 들어 다음의 User모델이 있다고 가정한다.


class User(models.Model):
name = models.CharField(max_length=100)
followers = models.ManyToManyField("self")
following = models.ManyToManyField("self")

여기서 self를 주는 이유는 한명의 유저가 똑같지만 다른 유저를 팔로잉할 수 있기 때문이다.

쉽게 말해서 본인을 향하고 있기 때문이다.

위에서 _set은 실제 DB컬럼형태로 생성되진 않는다고 했지만 ManyToManyField는 다르다.

실제 DB의 컬럼으로 생성이 된다. (또한 ManyToManyField는 공백이 허용된다)


hide = User.objects.get(pk=1)

test = User.objects.get(pk=2)

node = User.objects.get(pk=3)


위처럼 차례대로 유저를 불러와서 변수에 담았다고 가정한다.

여기서 hide의 팔로워에 test와 node를 추가해주고 싶다면 다음과 같이 작성한다.


hide.followers.add(test, node)


위 명령어를 내리고 나면 hide의 followers필드에 test와 node의 PK값인 2, 3이 저장된다.


4.

장고 2.0버전부터 모델에서 Foreign Key를 사용할때 on_delete옵션을 주지 않으면 에러가 발생한다.

대부분의 경우 참조하는 값이 사라지면 삭제시키는 경우가 많으므로 다음과 같이 CASCADE옵션을 주면 된다.


ForeignKey(User, on_delete=models.CASCADE)


한가지 더, 아마 여러가지 앱을 만들고 타 앱에 존재하는 모델을 import 시키는 경우가 있을텐데

그럴 경우 상단에 import 해줘야 한다. 예를 들어 users앱에 있는 User모델을 import 시키는경우


from users import models as user_models


형태로 작성해준다. as로 별명을 준건 기본 models와 이름이 duplicate되기 때문.