목차
학습 내용
Django - User
- USer 생성 : Form 사용 / Serializer 사용
- User 권한 관리
- 상속 메소드 오버라이딩
- Postman을 사용해 로그인한 상태로 요청 보내기
새로 알게 된 것
ForeignKey의 related_name 속성
역방향으로 연결된 객체에서 해당 객체에 접근할 때 사용하는 이름을 지정할 수 있는 속성이다.
class Question(models.Model):
# ...
owner = models.ForeignKey('auth.User', related_name='questions', on_delete=models.CASCADE, null=True)
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
사용자 측에서 Question에 접근할 때 user.questions.all() 형태로 접근할 수 있다.
related_name을 지정하지 않으면 question.choice_set.all() 형태로 접근해야 한다.
Serializer에서 외래키 표현 : PrimaryKeyRelatedField
class UserSerializer(serializers.ModelSerializer):
questions = serializers.PrimaryKeyRelatedField(many=True, queryset=Question.objects.all())
여기서 many=True를 꼭 설정해야 한다. User는 여러 개의 Question을 가질 수 있는 일대다 관계이기 때문에 이를 명시해야 한다.
그리고 questions를 정의하는 이유는 User 테이블에는 Question 정보가 없기 때문이다.
https://www.django-rest-framework.org/api-guide/relations/#primarykeyrelatedfield
User 생성
1. Form 사용
- 장고에서 제공하는 UserCreationForm을 사용해 구현한다.
2. Serializer 사용
Serializer를 사용해 구현하는 이유 : API 서버를 구현하기 위해서
[ 구현과정 ]
- RegisterSerializer 생성
- Password 유효성 검사를 위해 유효성 검사 함수 정의
- Password의 일치 여부를 위해 추가적으로 password2 변수 생성
- 기존 User 모델에는 password2 변수가 없기 때문에 새로 create 함수 정의
User 권한 관리
Django REST framework에서 접근 권한을 관리할 수 있는 permissions를 제공한다.
실습에서는 읽는 것은 누구나 가능하지만, 수정 요청을 할 때는 owner와 로그인 user가 일치하는지 확인하는 과정이 필요했다. 그래서 따로 permissions를 정의해주었다.
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.owner == request.user
- SAFE_METHODS : GET, HEAD, OPTIONS -> 읽는 것은 허용한다는 뜻
perform_create 함수에 대해서
class QuestionList(generics.ListCreateAPIView):
queryset = Question.objects.all()
serializer_class = QuestionSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
perform_create에서 serializer.save를 할 때 owner를 사용하는데, QuestionSerializer에서 owner는 readonly 필드다.
이게 사용가능한 이유는 save를 할 때는 read_only 여부와 상관없이 주어진 필드를 그냥 사용하기 때문이다.
궁금한 점
Question 모델에서 외래키를 정의할 때는 클래스 명을 문자열로 작성했는데, 이전에 정의한 Choice에서는 외래키를 정의할 때 객체를 사용했다. 둘 다 사용이 가능한건가 궁금해서 찾아봤다.
class Question(models.Model):
# ...
owner = models.ForeignKey('auth.User', related_name='questions', on_delete=models.CASCADE, null=True)
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
우선 장고 공식 문서에서는 다음과 같이 ForeignKey 필드에 대해서 설명하고 있다.
"Many-to-One 관계. 두 개의 위치 인수가 필요합니다: 모델이 관련된 클래스와 on_delete 옵션입니다. 재귀적 관계를 만들려면 – 자신과 다대일 관계를 갖는 객체 – models.ForeignKey('self', on_delete=models.CASCADE)를 사용하세요. 아직 정의되지 않은 모델에서 관계를 만들어야 하는 경우 모델 객체 대신 모델의 이름을 사용할 수 있습니다."
여기서 아직 정의되지 않은 모델에서 관계를 만들어야 하는 경우 모델 객체 대신 모델의 이름을 사용할 수 있다고 말하고 있다.
그렇다면 우리는 이미 장고에서 제공하고 있는 User 모델을 사용하는 것이니까 모델 객체를 사용해도 된다.
from django.contrib.auth.models import User
class Question(models.Model):
# ...
owner = models.ForeignKey(User, related_name='questions', on_delete=models.CASCADE, null=True)
다음과 같이 변경해서 잘 동작하는지 확인해본 결과, 잘 동작한다.
model 파일을 변경했으니 혹시 몰라 마이그레이션도 해봤는데, No changes detected라고 떴다.
https://docs.djangoproject.com/en/3.2/ref/models/fields/#foreignkey
느낀 점
permission을 따로 만들어서 원하는 권한으로 만드는 실습을 하면서 무엇이든 직접 만들어서 사용할 수 있다는 것을 느낄 수 있었다.
'기록 > TIL' 카테고리의 다른 글
[TIL] 231108 - 데브코스 24일차 (0) | 2023.11.08 |
---|---|
[TIL] 231107 - 데브코스 23일차 (5) | 2023.11.07 |
[TIL] 231101 - 데브코스 17일차 (1) | 2023.11.01 |
[TIL] 231031 - 데브코스 16일차 (0) | 2023.10.31 |
[TIL] 231030 - 데브코스 15일차 (0) | 2023.10.30 |