그 동안 작성해왔던 API는 누가 어떤 액션을 취하는지에 대한 제약사항이 따로 없었다. 아래와 같이 인증, 허가와 관련된 몇 가지 조건들이 포함된 기능들을 추가해보자.
처음에 작성했던 Snippet
모델 클래스에 필드 몇 개를 추가하여 약간 변화시켜줄 것이다.
하나는 누가 스니펫을 작성했는지를 나타내는 owner
, 다른 하나는 하이라이트 처리된 HTML 코드를 저장할 hightlighted
필드이다.
owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
hightlighted = models.TextField()
또 모델이 저장될 때, pygments
라는 코드 하이라이팅 라이브러를 사용하여 hightlighted
필드를 채울 수 있는지 확인해야 한다.
pygments
라이브러리의 모듈들을 import 해주고, save
메소드를 정의한다.
# models.py
from django.db import models
from pygments.lexers import get_all_lexers, get_lexer_by_name
from pygments.styles import get_all_styles
from pygments.formatters.html import HtmlFormatter
from pygments import hightlight
LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()])
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)
owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
hightlighted = models.TextField()
class Meta:
ordering = ['created']
def save(self, *args, **kwargs):
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.hightlighted = hightlight(self.code, lexer, formatter)
super(Snippet, self).save(*args, **kwargs)
2개 필드를 추가하여 모델이 변경되었으므로 makemigrations
커맨드를 통해 갱신시키자.
$ ./manage.py makemigrations
$ ./manage.py migrate
Admin 계정도 만들어주자.
$ ./manage.py createsuperuser
API response 데이터의 각 스니펫에 사용자도 추가하기 위해 새로운 시리얼라이저를 추가할 것이다.
# models.py
from rest_framework import serializers
from django.contrib.auth.models import User
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES
class SnippetSerializer(serializers.ModelSerializer):
class Meta:
model = Snippet
fields = ['id', 'title', 'code', 'linenos', 'language', 'style']
class UserSerializer(serializers.ModelSerializer):
snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())
class Meta:
model = User
fields = ['id', 'username', 'snippets']
UserSerializer
에서의 snippets
는 User
로부터의 Reverse relationship이므로 ModelSerializer
를 사용할 때 자동으로 만들어지지 않는다. 필드를 명시적으로 추가해줘야 한다.
API에서 사용자 정보를 확인할 수 있도록 하기 위해 2개의 view를 추가하자. ListAPIView
와 RetrieveAPIView
Generic CBV를 사용한다.
아, UserSerializer
도!
# views.py
...
from django.contrib.auth.models import User
from snippets.serializers import SnippetSerializer, UserSerializer
...
class UserList(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
views도 다 추가했고 남은 건 URL conf이다. urls.py
모듈도 만져주자.
# urls.py
...
urlpatterns = [
...
path('users/', views.UserList.as_view()),
path('users/<int:pk>/', views.UserDetail.as_view()),
]
다음 포스트에서는 스니펫과 사용자를 연결하는 작업을 하려 한다.
빠잇.