티스토리 뷰
Adding information to our model
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 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)
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)
highlighted = models.TextField()
class Meta:
ordering = ['created']
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(Snippet, self).save(*args, **kwargs)
Adding endpoints for our User models
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']
snippets 필드는 reverse relationship이기 때문에, ModelSerializer를 사용할 때 기본적으로 포함되지 않으므로, 명시적으로 정의.
# views.py
class UserList(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
# urls.py
from django.urls import path
from snippets import views
urlpatterns = [
path('users/', views.UserList.as_view()),
path('users/<int:pk>/', views.UserDetail.as_view()),
]
Associating Snippets with Users
새로운 Snippet을 생성할 때 생성한 user를 같이 저장.
.perform_create() 메서드를 사용.
class SnippetList(generics.ListCreateAPIView):
"""
List all code snippets, or create a new snippet
"""
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
create() 메서드가 owner 필드를 request 데이터에 추가하여 전송.
위의 내용을 반영하기 위해 SnippetSerializer 수정.
class SnippetSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = Snippet
fields = ['id', 'owner', 'title', 'code', 'linenos', 'language', 'style']
source argument는 Django의 template language가 사용되어지는 것과 비슷한 방식으로 사용되어짐.
ReadOnlyField는 deserialized 될 때 모델 인스턴스를 업데이트하기 위해 사용되지 않음. CharField(read_only=True)로도 표현 가능.
Adding required permissions to views
class SnippetList(generics.ListCreateAPIView):
"""
List all code snippets, or create a new snippet
"""
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
"""
Retrieve, update or delete a code snippet.
"""
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
Adding login to the Browsable API
# root urls.py
urlpatterns += [
path('api-auth/', include('rest_framework.urls')),
]
'api-auth' 주소는 원하는 주소로 수정 가능
Object level permissions
# permissions.py
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow owners of an object to edit it.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
# Write permissions are only allowed to the owner of the snippet.
return obj.owner == request.user
class SnippetList(generics.ListCreateAPIView):
"""
List all code snippets, or create a new snippet
"""
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOny]
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
"""
Retrieve, update or delete a code snippet.
"""
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOny]
Authenticating with the API
기본적으로 SessionAuthentication과 BasicAuthentication이 적용됨
아래와 같이 settings.py에 명시적으로 설정도 가능
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
}
https://www.django-rest-framework.org/tutorial/4-authentication-and-permissions/
https://www.django-rest-framework.org/api-guide/authentication/
'Django' 카테고리의 다른 글
ViewSets & Routers (0) | 2019.08.29 |
---|---|
Relationships & Hyperlinked APIs (0) | 2019.08.29 |
Rest Framework Views (0) | 2019.08.29 |
Serializer (0) | 2019.08.29 |
클래스 필터링, 검색, 정렬의 이해 (0) | 2019.08.28 |