
- User 추가
- User 관리
- Form을 사용하여 User 생성
- Serializer를 사용하여 User 생성
- User 권한 관리
- POSTMAN
오늘은 앞서 작성한 Question에 작성자를 만들고 작성자만 Question을 수정, 삭제할 수 있도록 만들어보자.
Question 모델의 필드에 owner 변수를 추가한다# polls.models.py
class Question(models.Model):
question_text = models.CharField(max_length=200, verbose_name='질문')
pub_date = models.DateTimeField(auto_now_add=True, verbose_name='생성일')
# related_name을 지정하면 User에서 questions라는 이름으로 Question들을 가져올 수 있다.
# related_name을 지정하지 않으면 Django에서 자동적으로 '모델명_set'을 구현해주기 때문에 그 이름으로 사용할 수 있다.
owner = models.ForeignKey('auth.User', related_name='questions', on_delete=models.CASCADE, null=True)
# ...
polls_api/serializers.py 파일에 UserSerializer 작성 class UserSerializer(serializers.ModelSerializer):
# question들을 가져오는 필드의 정보는 User 테이블에 있는게 아니기 때문에 따로 불러오는 처리가 필요
questions = serializers.PrimaryKeyRelatedField(many=True, queryset=Question.objects.all())
class Meta:
model = User
fields = ('id', 'username', 'questions')
polls_api/views.py : User에 대한 View 작성 class UserList(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
urlpatterns = [
#...
path('users/', UserList.as_view()),
path('users/<int:pk>/', UserDetail.as_view()),
]

polls/views.py 파일에 SignupView 클래스 추가from django.views import generic
from django.urls import reverse_lazy
from django.contrib.auth.forms import UserCreationForm
# ...
class SignupView(generic.CreateView):
form_class = UserCreationForm
# reverse_lazy는 url에서 정의한 name을 기반으로 url을 가져오는 함수
success_url = reverse_lazy('user-list')
template_name = 'registration/signup.html'
signup.html 템플릿 작성<h2>회원가입</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">가입하기</button>
</form>
polls/urls.py 에서 URL 연결 app_name = 'polls'
urlpatterns = [
# ...
path('signup/', SignupView.as_view(), name='signup'),
]

polls_api/serializers.py 에 RegisterSerializer 클래스 작성class RegisterSerializer(serializers.ModelSerializer):
# 패스워드에 대한 설정 (validate_password를 이용하여 password의 유효성을 검사)
password = serializers.CharField(write_only=True, required=True, validators=[validate_password])
password2 = serializers.CharField(write_only=True, required=True)
# 자체 유효성 검사를 위한 validate 메서드 구현
def validate(self, attrs):
if attrs['password']!= attrs['password2']:
raise serializers.ValidationError({'password': '비밀번호가 일치하지 않습니다.'})
return attrs
# User 객체에는 password2 가 없기 때문에 따로 create 메서드 구현
def create(self, validated_data):
user = User.objects.create_user(username=validated_data['username'])
user.set_password(validated_data['password'])
user.save()
return user
class Meta:
model = User
fields = ('username', 'password', 'password2')
polls_api/views.py에 RegisterUser 뷰 작성# ...
class RegisterUser(generics.CreateAPIView):
serializer_class = RegisterSerializer
polls_api/urls.py URL 설정urlpatterns = [
# ...
path('register/', RegisterUser.as_view(), name='register'),
]

polls_api/urls.py에 로그인 처리를 할 url 설정urlpatterns = [
# ...
path('api-auth/', include('rest_framework.urls')),
]
mysite.settings.py 에서 로그인 성공시 리다이렉트 되는 url을 설정.# ...
from django.urls import reverse_lazy
LOGIN_REDIRECT_URL = reverse_lazy('question-list')
LOGOUT_REDIRECT_URL = reverse_lazy('question-list')
# ...

owner가 되도록 설정# polls_api/serializers.py
class QuestionSerializer(serializers.ModelSerializer):
# 작성자를 나타낼 owner 변수 추가
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = Question
fields = ('id', 'question_text', 'pub_date', 'owner')
polls_api/view.py)class QuestionList(generics.ListCreateAPIView):
queryset = Question.objects.all()
serializer_class = QuestionSerializer
# 로그인이 된 상태에서만 question 생성 가능
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
# create할 때 owner필드를 현재 접속한 유저로 설정
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
class QuestionDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Question.objects.all()
serializer_class = QuestionSerializer
# 로그인한 사용자가 작성한 질문이 아니면 수정이 불가능하게 권한 설정
permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]
polls_api/permissions.py)from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
# 조회 등의 조작이 일어나지 않는 http 메서드는 그냥 통과
if request.method in permissions.SAFE_METHODS:
return True
# 그 외의 메서드는 request를 보낸 유저와 대상의 owner로 설정된 유저가 같은지 유효성 검사
return obj.owner == request.user
- API의 작동 과정을 확인할 수 있는 프로그램으로 URL과 Body를 설정해서 API의 응답을 확인해 볼 수있다.
여러 라이브러리를 사용해서 클래스가 많아지고 클래스 간의 관계가 복잡해져서 알아보고 이해하는 것이 가장 어려웠던 것 같다. 자동적으로 메서드를 생성하거나 데이터를 연결해주는 기능들은 편하긴 하지만 충분한 이해가 선행되어야 할 것 같다는 생각이 들었다.