오늘의 과제
1. Django 프로젝트를 생성하고, user 라는 앱을 만들어서 settings.py 에 등록해보세요.
2. user/models.py에 `Custom user model`을 생성한 후 django에서 user table을 생성 한 모델로 사용할 수 있도록 설정해주세요.
3. user/models.py에 사용자의 상세 정보를 저장할 수 있는 `UserProfile` 이라는 모델을 생성해주세요.
4. blog라는 앱을 만든 후 settings.py에 등록해주세요.
5. blog/models.py에 <카테고리 이름, 설명>이 들어갈 수 있는 `Category`라는 모델을 만들어보세요.
6. blog/models.py에 <글 작성자, 글 제목, 카테고리, 글 내용>이 들어갈 수 있는 `Article` 이라는 모델을 만들어보세요.(카테고리는 2개 이상 선택할 수 있어야 해요)
7. Article 모델에서 외래 키를 활용해서 작성자와 카테고리의 관계를 맺어주세요.
8. admin.py에 만들었던 모델들을 추가해 사용자와 게시글을 자유롭게 생성, 수정 할 수 있도록 설정해주세요.
9. CBV 기반으로 로그인 / 로구아웃 기능을 구현해주세요,
10. CBV 기반으로 로그인 한 사용자의 게시글의 제목을 리턴해주는 기능을 구현해주세요.
1. Django 프로젝트 및 user 앱 생성 후 settings.py에 등록하기
django-admin startproject DRF .
위의 명령어를 통해 DRF 라는 이름의 Django 프로젝트를 생성한다.
django-admin startapp user
위의 명령어를 통해 user 라는 이름의 앱을 생성한다.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'user',
]
DRF 폴더의 settings.py 내의 INSTALLED_APPS 리스트에 user 앱을 추가해준다.
2. user/models.py에 Custom user model을 생성하고, Django에서 user table을 생성한 모델로 사용할 수 있도록 설정하기
Django에서 커스텀 유저 모델을 생성하기 위해서는 두 개의 클래스 (BaseUserManager, AbstractBaseUser)를 구현해야한다. BaseUserManager 클래스는 유저를 생성할 때 사용하는 헬퍼(Helper) 클래스이며, 실제 모델(Model) 은 AbstractBaseUser을 상속받아 생성하는 클래스이다.
우선, 헬퍼 클래스인 BaseUserManager를 상속받는 UserManager 클래스를 만들어보자.
class UserManager(BaseUserManager):
def create_user(self, username, password=None):
if not username:
raise ValueError('Users must have an username')
user = self.model(
username=username,
)
user.set_password(password)
user.save(using=self._db)
return user
# python manage.py createsuperuser 사용 시 해당 함수가 사용됨
def create_superuser(self, username, password=None):
user = self.create_user(
username=username,
password=password
)
user.is_admin = True
user.save(using=self._db)
return user
위와 같이 UserManager 클래스를 작성해준다. create_user 함수는 말 그대로 user를 생성해주는 함수이고, create_superuser 함수는 superuser를 생성해주는 함수이다.
python manage.py createsuperuser
위와 같은 명령어가 입력될 시, create_superuser 함수가 호출된다.
이번에는 실제 모델인 AbstractBaseUser을 상속받는 User 클래스를 만들어보자.
class User(AbstractBaseUser):
username = models.CharField("사용자 계정", max_length=20, unique=True)
email = models.EmailField("이메일 주소", max_length=100)
password = models.CharField("비밀번호", max_length=128)
fullname = models.CharField("이름", max_length=20)
join_date = models.DateField("가입일", auto_now_add=True)
# is_active가 False일 경우 계정이 비활성화됨
is_active = models.BooleanField(default=True)
# is_staff에서 해당 값 사용
is_admin = models.BooleanField(default=False)
# id로 사용 할 필드 지정.
# 로그인 시 USERNAME_FIELD에 설정 된 필드와 password가 사용된다.
USERNAME_FIELD = 'username'
# user를 생성할 때 입력받은 필드 지정
REQUIRED_FIELDS = []
objects = UserManager() # custom user 생성 시 필요
def __str__(self):
return self.username
# 로그인 사용자의 특정 테이블의 crud 권한을 설정, perm table의 crud 권한이 들어간다.
# admin일 경우 항상 True, 비활성 사용자(is_active=False)의 경우 항상 False
def has_perm(self, perm, obj=None):
return True
# 로그인 사용자의 특정 app에 접근 가능 여부를 설정, app_label에는 app 이름이 들어간다.
# admin일 경우 항상 True, 비활성 사용자(is_active=False)의 경우 항상 False
def has_module_perms(self, app_label):
return True
# admin 권한 설정
@property
def is_staff(self):
return self.is_admin
위와 같이 User 클래스를 작성해준다.
이제 Django가 user table을 생성한 모델로 사용할 수 있도록 해보자. settings.py를 수정해주면 된다.
AUTH_USER_MODEL = 'user.User'
위의 코드를 settings.py에 추가해준다.
3. user/models.py에 사용자의 상세 정보를 등록할 수 있는 UserProfile 모델 생성하기
사용자의 상세 정보들을 하나의 column으로 지정해준다. 나의 경우, username, description, nickname, age, hobby를 column으로 할 수 있도록 지정해주었다. 또, hobby의 경우 클래스를 하나 더 생성하여 Many-to-Many 관계를 가질 수 있도록 설정하였다.
class UserProfile(models.Model):
user = models.OneToOneField(User, verbose_name="유저", on_delete=models.CASCADE)
description = models.TextField("한 줄 소개", max_length=256)
nickname = models.TextField("별명", max_length=50)
age = models.IntegerField("나이")
hobby = models.ManyToManyField(Hobby, verbose_name="취미")
def __str__(self):
return f"{self.user.username} 님의 프로필"
위와 같이 UserProfile을 작성하였다.
class Hobby(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
Hobby 클래스는 위와 같이 작성하였다.
4. blog 앱 생성 후, settings.py에 등록하기
django-admin startapp blog
위의 명령어를 통해 blog 라는 이름의 앱을 추가해준다.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'user',
'blog',
]
DRF 폴더의 settings.py 내의 INSTALLED_APPS 리스트에 blog 앱을 추가해준다.
5. blog/models.py에 <카테고리 이름, 설명>이 들어갈 수 있는 'Category' 모델 생성하기
class Category(models.Model):
name = models.CharField(max_length=50)
description = models.TextField(max_length=100)
def __str__(self):
return self.name
위와 같이 models.py에 Category 클래스를 생성해주었다.
6. blog/models.py에 <글 작성자, 글 제목, 카테고리, 글 내용>이 들어갈 수 있는 'Article' 이라는 모델 생성하기 (카테고리는 2개 이상 선택 가능하도록)
class Article(models.Model):
username = models.ForeignKey(UserModel, on_delete=models.CASCADE)
title = models.TextField(max_length=100)
category = models.ManyToManyField(Category, related_name="articles")
contents = models.TextField(max_length=256)
def __str__(self):
return f"{self.user.username} 님의 게시글"
위와 같이 username은 UserModel로부터 사용자의 이름을 foreign key로 가져올 수 있도록 하였다. 왜냐하면 게시글 하나 당 작성자는 한 명일 수 밖에 없기 때문이다. 그러나 한 명의 사용자는 여러 게시글을 작성할 수 있으므로 One-to-Many 관계를 가지는 것을 알 수 있다. 반면, category는 하나의 category에 여러 게시글이 있을 수 있고, 하나의 게시글도 여러 개의 category를 가질 수 있으므로 Many-to-Many 관계를 가질 수 있도록 설정해주었다.
7. Article 모델에서 외래 키를 활용해서 작성자와 카테고리의 관계를 맺어주세요.
위와 동일합니다.
8. admin.py에 만들었던 모델들을 추가해 사용자와 게시글을 자유롭게 생성, 수정할 수 있도록 설정하기
admin.site.register(User)
admin.site.register(UserProfile)
admin.site.register(Hobby)
user/admin.py에 다음과 같이 작성해준다.
admin.site.register(Category)
admin.site.register(Article)
blog/admin.py에 다음과 같이 작성해준다.
9. CBV 기반으로 로그인 / 로그아웃 기능 구현하기
class UserApiView(APIView):
def post(self, request):
username = request.data.get('username', '')
password = request.data.get('password', '')
user = authenticate(request, username=username, password=password)
if not user:
return Response({"error": "존재하지 않는 계정이거나 패스워드가 일치하지 않습니다."})
login(request, user)
return Response({"message": "로그인 성공!!"})
def delete(self, request):
logout(request)
return Response({"message": "로그아웃 성공!!"})
다음과 같이 UserApiView 클래스를 작성해준다. POST 메소드가 들어왔을 경우에는 로그인을 시도하고, DELETE 메소드가 들어왔을 경우에는 로그아웃을 하도록 작성해주었다.
10. CBV 기반으로 로그인 한 사용자의 게시글의 제목을 리턴해주는 기능을 구현하기
class UserArticleView(APIView):
permission_classes = [permissions.AllowAny]
def get(self, request):
user = request.user
articles = Article.objects.filter(user_id=user.id).values()
titles=[]
for article in articles:
titles.append(article['title'])
title_list_str=", ".join(titles)
return Response({"title": title_list_str})
위와 같이 articles를 가져와서 title들을 titles라는 리스트에 추가한 후, 이를 쉼표로 이어붙인 문자열형으로 바꿔 리턴해준다.