Notice
Recent Posts
Recent Comments
Link
오늘도 개발
Django Rest Framework 튜토리얼 따라하기 4. Hyperlink API 본문
여러 테이블 간 관계를 표현하기 위해 DRF에선 다음과 같은 방법을 제공한다.
1. primary key 사용
2. 엔티티를 hyperlink로 연결
3. 연관된 엔티티에 고유한 slug field 사용
4. 연관된 엔티티에 디폴트 string representation 사용
5. 연관된 엔티티를 부모 representation에 네스팅
등등..
여기선 hyperlink를 사용한 방법을 알아보자.
<urls.py>
각 path에 name 지정해주기
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
urlpatterns = format_suffix_patterns([
path('', views.api_root),
path('snippets/', views.SnippetList.as_view(), name='snippet-list'),
path('snippets/<int:pk>/', views.SnippetDetail.as_view(), name='snippet-detail'),
path('snippets/<int:pk>/highlight/', views.SnippetHighlight.as_view(), name='snippet-highlight'),
path('users/', views.UserList.as_view(), name='user-list'),
path('users/<int:pk>/', views.UserDetail.as_view(), name='user-detail')
])
<models.py>
from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles
from pygments.lexers import get_lexer_by_name
from pygments.formatters.html import HtmlFormatter
from pygments import highlight
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):
owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
highlighted = models.TextField()
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)
class Meta:
ordering = ['created']
def save(self, *args, **kwargs):
# django의 save 메서드를 override
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, lineos=linenos, full=True, **options)
self.highlighted = highlight(self.code, lexer, formatter)
# django의 기존 save 메서드 실행
super().save(*args, **kwargs)
<serializers.py>
from rest_framework import serializers
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES
from django.contrib.auth.models import User
class SnippetSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
# hyperlink로 연결
highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')
class Meta:
model = Snippet
fields = ['id', 'highlight', 'owner', 'title', 'code', 'linenos', 'language', 'style']
class UserSerializer(serializers.ModelSerializer):
# hyperlink로 연결
snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True)
# primary key로 연결한 버전
# snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())
class Meta:
model = User
fields = ['id', 'username', 'snippets']
<views.py>
from rest_framework import mixins
from rest_framework import generics
from rest_framework import permissions
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse
from rest_framework import renderers
from snippets.models import Snippet
from django.contrib.auth.models import User
from snippets.serializers import SnippetSerializer, UserSerializer
from snippets.permissions import IsOwnerOrReadOnly
class SnippetHighlight(generics.GenericAPIView):
queryset = Snippet.objects.all()
# 디폴트로 사용하는 JSONrenderer 말고 다른 renderer 사용하로 싶을 때 정의
renderer_class = [renderers.StaticHTMLRenderer]
def get(self, request, *args, **kwargs):
snippet = self.get_object()
return Response(snippet.highlighted)
@api_view(['GET'])
def api_root(request, format=None):
return Response({
'users' : reverse('user-list', request=request, format=format),
'snippets' : reverse('snippet-list', request=request, format=format)
})
class UserList(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class SnippetList(mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class SnippetDetail(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
generics.GenericAPIView):
permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
<settings.py>
페이지네이션 추가하고 싶은 경우
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10
}
'웹 프로그래밍 > Django' 카테고리의 다른 글
| refresh_from_db() (0) | 2023.02.18 |
|---|---|
| django에 데이터베이스 여러 개 연결하기 (0) | 2023.02.18 |
| Django Rest Framework 튜토리얼 따라하기 3. authentications and permissions (0) | 2023.01.08 |
| Django Rest Framework 튜토리얼 따라하기 2. view 쉽게 작성하기 (0) | 2023.01.08 |
| Django Rest Framework 튜토리얼 따라하기 1. Serialization (6) | 2023.01.07 |