🧩

006 accounts 앱 모델 생성

 

1. 패키지 설치

이미지 처리를 위한 패키지부터 설치하고 시작하겠습니다. 저번에 설치한 것과 겹칠 수도 있습니다.
root@goorm:/workspace/instaclone/instaclone# pip install pillow
 
notion imagenotion image
 
root@goorm:/workspace/instaclone/instaclone# pip install pilkit
 
notion imagenotion image
 
root@goorm:/workspace/instaclone/instaclone# pip install psycopg2-binary
 
notion imagenotion image
 
root@goorm:/workspace/instaclone/instaclone# pip install django-imagekit
 
notion imagenotion image
 
💡
다음과 같이 패키지 이름들을 나열하여 한번에 설치할 수도 있습니다. pip install pillow pilkit psycopg2-binary django-imagekit
 

2. 모델 작성

1. models.py

이제 accounts 폴더 안에 models.py 를 작성하도록 하겠습니다. models.py 에서 모델을 정하게 되면 Django의 데이터베이스에 적용되게 됩니다.
notion imagenotion image
 
models.py 구조를 살펴보겠습니다. models.py 위쪽 상단에서는 이와 같이 import를 통해 4가지 기능을 가져옵니다. import 아래 부분에서 실제 함수와 클래스를 생성하면서 기능을 사용하게 됩니다.
 
파일명 : accounts/models.py
from django.db import models from django.conf import settings # django.conf에서 settings를 import from imagekit.models import ProcessedImageField # imagekit에서 이미지를 처리하는 필드를 import from imagekit.processors import ResizeToFill # imagekit에서 이미지 사이즈를 재조정하는 기능을 import
 

2. Profile 모델 작성

사용자 정보를 의미하는 Profile 클래스를 만들겠습니다. models.Model를 상속받아서 만듭니다. 이 부분이 DB의 테이블이 됩니다.
 
파일명 : accounts/models.py
... class Profile(models.Model):
 

3. user 필드

user 항목을 만듭니다. 1대1 관계의 필드로 지정하고 settings.AUTH_USER MODEL을 활용합니다.
settings.AUTH_USER_MODEL에는 현재 인증으로 사용하고 있는 유저 모델이 설정되어 있습니다. 기본값으로 Django에서는 내장된 auth 앱의 User 모델을 사용합니다.
유저 정보는 삭제 시 관련 정보들도 같이 삭제되게 하기 위해서 on_delete 값을 models.CASCADE로 설정합니다.
 
파일명 : accounts/models.py
... class Profile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
 

4. nickname 필드

nickname은 별명에 해당하는 부분입니다. 최대 길이 20글자로 설정하고, 각자 고유한 별명을 가질 수 있도록 unique 속성을 True로 정하겠습니다.
 
파일명 : accounts/models.py
... class Profile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) nickname = models.CharField('별명', max_length=20, unique=True)
 
그리고 Profile 객체들을 표현할 때 nickname을 사용하도록 설정합니다.
 
파일명 : accounts/models.py
... class Profile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) nickname = models.CharField('별명', max_length=20, unique=True) def __str__(self): return self.nickname
 

5. about 필드

about은 자기 소개 부분입니다. 최대 길이를 300정도 설정하고, 없을 수도 있기 때문에 blank 속성을 True로 설정합니다.
 
파일명 : accounts/models.py
... class Profile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) nickname = models.CharField('별명', max_length=20, unique=True) about = models.CharField(max_length=300, blank=True) def __str__(self): return self.nickname
 

6. gender 필드

GENDER_C는 성별을 고르는 Select Box를 위해 작성합니다.
 
파일명 : accounts/models.py
... class Profile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) nickname = models.CharField('별명', max_length=20, unique=True) about = models.CharField(max_length=300, blank=True) GENDER_C = ( ('선택안함', '선택안함'), ('여성', '여성'), ('남성', '남성'), ) def __str__(self): return self.nickname
(A, B)일 때, 왼쪽 값 A는 DB에 저장되는 값, 오른쪽 값 B는 유저에게 보이는 값입니다.
 
gender 필드를 만들고, GENDER_Cchoices 항목의 값으로 넣어줍니다. max_lengthchoices는 미리 정해진 이름이어서 틀리시면 오류가 납니다. GENDER_C는 이름이 바뀌어도 되는 변수입니다.
 
파일명 : accounts/models.py
... class Profile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) nickname = models.CharField('별명', max_length=20, unique=True) about = models.CharField(max_length=300, blank=True) GENDER_C = ( ('선택안함', '선택안함'), ('여성', '여성'), ('남성', '남성'), ) gender = models.CharField('성별(선택사항)', max_length=10, choices=GENDER_C, default='N') def __str__(self): return self.nickname
 

7. picture 필드

사진 처리 부분을 추가하겠습니다. import한 ProcessedImageField를 사용합니다.
upload_to라는 항목은 저장 위치 처리 부분입니다. 포스트, 글 작성을 구현할 때도 똑같이 쓰이기 때문에, 잘 활용할 수 있을 겁니다.
 
파일명 : accounts/models.py
... class Profile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) nickname = models.CharField('별명', max_length=20, unique=True) about = models.CharField(max_length=300, blank=True) GENDER_C = ( ('선택안함', '선택안함'), ('여성', '여성'), ('남성', '남성'), ) gender = models.CharField('성별(선택사항)', max_length=10, choices=GENDER_C, default='N') picture = ProcessedImageField(upload_to=user_path, processors=[ResizeToFill(150, 150)], format='JPEG', options={'quality': 90}, blank=True) def __str__(self): return self.nickname
 
user_path 함수를 작성하겠습니다. 사용자가 업로드한 이미지 파일의 경로를 생성하여 반환해주는 함수입니다.
 
파일명 : accounts/models.py
... def user_path(instance, filename): class Profile(models.Model): ... ...
 
instancePhoto의 모델이고 filename은 사용자의 파일명입니다. random 선택을 하는 choice 기능과 string 기능도 가져옵니다.
 
파일명 : accounts/models.py
... def user_path(instance, filename): from random import choice import string ...
 
대소문자 관계없이 8번 반복하여 문자를 불러옵니다.
 
파일명 : accounts/models.py
... def user_path(instance, filename): from random import choice import string arr = [choice(string.ascii_letters) for _ in range(8)] ...
 
불러온 문자들을 이어 붙입니다.
 
파일명 : accounts/models.py
... def user_path(instance, filename): from random import choice import string arr = [choice(string.ascii_letters) for _ in range(8)] pid = ''.join(arr) ...
 
파일 확장자명을 분리해서 저장합니다.
 
파일명 : accounts/models.py
... def user_path(instance, filename): from random import choice import string arr = [choice(string.ascii_letters) for _ in range(8)] pid = ''.join(arr) extension = filename.split('.')[-1] ...
 
결과적으로 accounts/username/random.확장자명 과 같은 파일 경로 문자열을 반환하게 됩니다.
 
파일명 : accounts/models.py
... def user_path(instance, filename): from random import choice import string arr = [choice(string.ascii_letters) for _ in range(8)] pid = ''.join(arr) extension = filename.split('.')[-1] return 'accounts/{}/{}.{}'.format(instance.user.username, pid, extension) ...
 
완성된 코드는 아래와 같습니다.
 
파일명 : accounts/models.py
from django.db import models from django.conf import settings from imagekit.models import ProcessedImageField from imagekit.processors import ResizeToFill def user_path(instance, filename): from random import choice import string arr = [choice(string.ascii_letters) for _ in range(8)] pid = ''.join(arr) extension = filename.split('.')[-1] return 'accounts/{}/{}.{}'.format(instance.user.username, pid, extension) class Profile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) nickname = models.CharField('별명', max_length=20, unique=True) about = models.CharField(max_length=300, blank=True) GENDER_C = ( ('선택안함', '선택안함'), ('여성', '여성'), ('남성', '남성'), ) gender = models.CharField('성별(선택사항)', max_length=10, choices=GENDER_C, default='N') picture = ProcessedImageField(upload_to=user_path, processors=[ResizeToFill(150, 150)], format='JPEG', options={'quality': 90}, blank=True) def __str__(self): return self.nickname
 

3. 마이그레이트

  1. 먄약에 PostgreSQL을 설치하셨다면 서버를 켜주시길 바랍니다. (만약 SQLite를 사용하신다면 건너 뛰시고 2번부터 수행해줍니다.)
    1. root@goorm:/workspace/instaclone/instaclone# service postgresql start
       
      notion imagenotion image
       
  1. accounts 폴더를 makemigration 하겠습니다.
    1. root@goorm:/workspace/instaclone/instaclone# python manage.py makemigrations accounts
       
      notion imagenotion image
       
  1. 그러고 나서 전체 변경 사항들을 migrate을 하겠습니다.
    1. root@goorm:/workspace/instaclone/instaclone# python manage.py migrate
       
      notion imagenotion image
      성공적으로 migrate하면 이와 같이 나옵니다. 이렇게 쿼리문 작성 없이 모델을 규정했을 뿐인데 테이블이 생성된 것입니다.
       
  1. PostgreSQL에서 테이블을 직접 확인 해보겠습니다. (postgresql 사용하시는 분만 하시면 됩니다.)
    1. root@goorm:/workspace/instaclone/instaclone# su - postgres
       
      notion imagenotion image
       
      psql 입력해서 데이터베이스로 접속합니다.
      postgres@goorm:~$ psql
       
      notion imagenotion image
       
      데이터베이스 리스트를 확인합니다.
      postgres=# \l
       
      notion imagenotion image
       
      instaclone 데이터베이스에 접속합니다.
      postgres=# \c instaclone
       
      notion imagenotion image
       
      테이블 리스트를 출력하겠습니다.
      instaclone=# \d
       
      notion imagenotion image
       
      맨 위에 accoutns_profile이 있습니다. accounts 앱의 models.pyProfile 클래스를 만들었던 것이 테이블로 만들어진 것입니다. 여기까지 되셨으면 모델을 잘 생성한 것입니다.