현재의 API에는 스니펫을 편집하거나 삭제할 수 있는 사용자에 대한 제한이 없다. 이를 확실히 하기 위해 몇 가지 고급 동작을 추가하자.
- 스니펫은 항상 작성자와 연결됨
- 인증된 사용자만 스니펫을 만들 수 있음
- 스니펫 작성자만 스니펫을 업데이트하거나 삭제할 수 있음
- 인증되지 않은 요청은 전체 읽기 전용 액세스 권한을 가짐
모델에 정보 추가하기
스니펫 모델 클래스를 몇 가지 변경하자. 먼저 몇 개의 필드를 추가한다. 그 중 하나는스니펫을 만든 사용자를 나타내는 데 사용된다. 다른 필드는 코드의 강조 표시된 HTML 표현을 저장하는 데 사용된다.
models.py의 스니펫 모델에 다음 두 필드를 추가
# snippets/models.py
owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
highlighted = models.TextField()
# related_name: reverse accessors(역접근자)의 이름을 커스텀 하는 방법. 모델 A가 모델 B에 foreign key(외래 키)를 가지고 있을 때 자동적으로 모델 B는 '모델 A_set'을 받게 된다. 여기서 related_name을 A로 설정하면 B는 A_set 대신 A를 사용할 수 있게 된다.
# reverse accessors(역접근자): 예를 들어 user와 room이 있고 room이 user에 대한 foreign key를 가지고 있을 때 user의 입장에서 user를 가리키고 있는 room은 어떤 게 있는지 알고 싶을 때 역접근자를 사용한다. 역방향으로 가리키는 건 _set으로 구현된다. room_set은 user를 가리키는 모든 rooms의 리스트라고 할 수 있다. 장고가 모델의 이름을 가져가서 그걸 소문자로 만들고, '_set'을 추가하는데 이 작업은 자동으로 발생한다. 그런데 room_set이라는 단어를 커스텀 하고 싶다면 바로 여기서 related_name을 사용하면 된다. 즉 related_name은 foreign key와 사용하는 것인데 타켓 모델이 foreign key를 만드는 모델에 어떻게 접근할 수 있는지 명시하게 한다.
모델을 저장할 때 pygments 코드 강조 표시 라이브러리를 사용하여 강조 표시된 필드를 채우는지 확인해야 한다. 이를 위해 몇 가지를 추가적으로 import 해준다.
# snippets/models.py
from pygments.lexers import get_lexer_by_name
from pygments.formatters.html import HtmlFormatter
from pygments import highlight
이제 모델 클래스에 .save() 메서드를 추가할 수 있다.
def save(self, *args, **kwargs):
"""
Use the `pygments` library to create a highlighted HTML
representation of the code snippet.
"""
lexer = get_lexer_by_name(self.language)
linenos = 'table' if self.linenos else False
options = {'title': self.title} if self.title else {}
formatter = HtmlFormatter(style=self.style, linenos=linenos,
full=True, **options)
self.highlighted = highlight(self.code, lexer, formatter)
super().save(*args, **kwargs)
모든 작업이 완료되면 데이터베이스 테이블을 업데이트해야 한다. 일반적으로는 데이터베이스 마이그레이션을 생성하여 이를 수행하지만, 이 튜토리얼에서는 데이터베이스를 삭제하고 다시 시작한다.
rm -f db.sqlite3
rm -r snippets/migrations
python manage.py makemigrations snippets
python manage.py migrate
API를 테스트하는 데 사용할 몇 가지 다른 사용자를 만들 수 있다. 가장 빠른 방법은 createsuperuser 명령을 사용하는 것이다.
python manage.py createsuperuser
사용자 모델에 엔드포인트 추가하기
이제 작업할 사용자가 생겼으니 해당 사용자의 값을 API에 추가하자. serializers.py에 새 serializer를 만든다.
# snippets/serializer.py
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())
class Meta:
model = User
fields = ['id', 'username', 'snippets']
'스니펫'은 사용자 모델에서 역관계(reverse relationship)이기 때문에 ModelSerializer 클래스를 사용할 때 기본적으로 포함되지 않으므로 이를 위한 명시적 필드를 추가해야 했다.
다음으로 views.py에 몇 가지 view를 추가하자. 사용자 값을 읽기 전용으로 할 것이기 때문에 ListAPIView 및 RetrieveAPIView generic class-based views를 사용한다.
# snippets/views.py
from django.contrib.auth.models import User
from snippets.serializers import UserSerializer
class UserList(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
마지막으로 URL conf에서 views를 참조하여 API에 추가해야 한다. snippets/urls.py에 다음을 추가하자.
path('users/', views.UserList.as_view()),
path('users/<int:pk>/', views.UserDetail.as_view()),
'DRF Tutorial' 카테고리의 다른 글
DRF Tutorial 4: Authentication & Permissions 3 (0) | 2023.02.15 |
---|---|
DRF Tutorial 4: Authentication & Permissions 2 (0) | 2023.02.15 |
DRF Tutorial 3: Class-based Views (0) | 2023.02.14 |
DRF Tutorial 2: Requests and Responses 2 (0) | 2023.02.14 |
DRF Tutorial 2: Requests and Responses 1 (0) | 2023.02.14 |