728x90
rest
모델 - 시리얼라이져 만듬
장고 기본모델 - 템플러? 만듬?
모델과 시리얼라이저, 그리고 뷰와 템플릿을 어떻게 연결하는지 설명해 드리겠습니다.
1. 모델 생성
먼저, Django의 기본 모델을 상속받아 새로운 모델을 생성합니다.
from django.db import models class Article(models.Model): title = models.CharField(max_length=100) content = models.TextField() author = models.ForeignKey('auth.User', related_name='articles', on_delete=models.CASCADE) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return self.title |
2. 시리얼라이저 생성
이제 위에서 만든 Article 모델을 위한 시리얼라이저를 만듭니다.
from rest_framework import serializers from .models import Article class ArticleSerializer(serializers.ModelSerializer): class Meta: model = Article fields = '__all__' |
3. 뷰 생성
REST API로 모델을 다룰 수 있는 뷰를 생성합니다.
from rest_framework import generics from .models import Article from .serializers import ArticleSerializer from .permissions import CustomReadOnly # 이전에 만든 CustomReadOnly 사용 class ArticleListCreateView(generics.ListCreateAPIView): queryset = Article.objects.all() serializer_class = ArticleSerializer permission_classes = [CustomReadOnly] class ArticleDetailView(generics.RetrieveUpdateDestroyAPIView): queryset = Article.objects.all() serializer_class = ArticleSerializer permission_classes = [CustomReadOnly] |
4. URL 라우팅
생성한 뷰를 URL에 연결합니다.
from django.urls import path from .views import ArticleListCreateView, ArticleDetailView urlpatterns = [ path('articles/', ArticleListCreateView.as_view(), name='article-list'), path('articles/<int:pk>/', ArticleDetailView.as_view(), name='article-detail'), ] |
5. 템플릿 생성
장고 템플릿을 사용해 데이터를 렌더링할 수 있습니다. 예를 들어, articles.html이라는 템플릿을 만들어서 모든 기사를 리스트로 보여줄 수 있습니다.
<!-- templates/articles.html --> <!DOCTYPE html> <html> <head> <title>Articles</title> </head> <body> <h1>Articles</h1> <ul> {% for article in articles %} <li>{{ article.title }} by {{ article.author }}</li> {% endfor %} </ul> </body> </html> |
6. 뷰와 템플릿 연결
템플릿을 렌더링하기 위한 Django 뷰를 작성합니다.
from django.shortcuts import render from .models import Article def article_list(request): articles = Article.objects.all() return render(request, 'articles.html', {'articles': articles}) |
7. URL에 템플릿 뷰 연결
from django.urls import path from .views import article_list urlpatterns = [ path('articles/', article_list, name='article-list-html'), ] |
정리
이제 Article 모델을 생성하고, 시리얼라이저를 통해 API로 접근할 수 있으며, Django 템플릿을 통해 HTML로 데이터를 렌더링할 수 있습니다. API와 템플릿을 적절히 활용해 프로젝트의 요구사항에 맞는 웹 애플리케이션을 구축할 수 있습니다.
저번시간 이어서 작성
4. 필터링 기능
- 필터링 기능: 게시글 전체를 가져올 때 조건을 걸어 가져오도록 하는 기능
- Django에서 이미 지원하는 기능임
- View 등의 코드에서 따로 호출하지 않아도 프로젝트 전역에 적용됨
pip install django-filter
4.1 settings.py 설정
# board/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework.authtoken',
'users',
'corsheaders',
'posts',
'django_filters',
]
...
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
],
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
],
}
4.2 Views (뷰는 시리얼라이저하고 템플릿을 연결해주는 역할을함, 기존 시리얼라이저들을 참고로 쓰게됨)
# posts/views.py
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import viewsets
from users.models import Profile
from .models import Post
from .permissions import CustomReadOnly
from .serializers import PostSerializer, PostCreateSerializer
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
permission_classes = [CustomReadOnly]
filter_backends = [DjangoFilterBackend]
filterset_fields = ['author', 'likes']
def get_serializer_class(self):
if self.action == 'list' or 'retrieve':
return PostSerializer
return PostCreateSerializer
def perform_create(self, serializer):
profile = Profile.objects.get(user=self.request.user)
serializer.save(author=self.request.user, profile=profile)
5. 페이징 기능
5.1 Pagination
- 게시글 전체 조회 페이지를 여러 페이지로 나누는 기능
- 한 번에 모든 글을 가져오기 부담스러울 경우 한 번의 API 요청으로 가져울 수 있는 데이터의 수를 제한하는 기능
- 별다른 작업은 필요없음 → settings.py의 REST_FRAMEWORK에 관련 기능을 추가하기만 하면 됨
- 단, 결과 데이터는 results에 들어가서 프론트엔드에 전달되므로 프론트엔드에서는 데이터를 꺼내가는 과정이 추가로 요구됨
# board/settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
],
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
],
'DEFAULT_PAGINATION_CLASS':
'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE':
3,
}
6. 좋아요 기능
6.1 Views
- 좋아요 기능은 오직 likes 필드에만 영향을 주므로 간단한 GET 요청 하나로 처리 가능
- 요구되는 설정
- 데코레이터로 GET 요청을 받는 함수형 뷰라는 설정
- 권한이 필요하다는 설정
- 좋아요를 누르는 권한은 회원가입을 한 유저라면 모두 가능하므로 IsAuthenticated로 설정
- 처리 내용
- post.likes.all() 내에 request.user가 있으면 request.user 삭제
- post.likes.all() 내에 request.user가 없으면 request.user 추가
# posts/views.py
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import viewsets
from rest_framework.decorators import api_view, permission_classes
from rest_framework.generics import get_object_or_404
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from users.models import Profile
from .models import Post
from .permissions import CustomReadOnly
from .serializers import PostSerializer, PostCreateSerializer
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
permission_classes = [CustomReadOnly]
filter_backends = [DjangoFilterBackend]
filterset_fields = ['author', 'likes']
def get_serializer_class(self):
if self.action == 'list' or 'retrieve':
return PostSerializer
return PostCreateSerializer
def perform_create(self, serializer):
profile = Profile.objects.get(user=self.request.user)
serializer.save(author=self.request.user, profile=profile)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def like_post(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.user in post.likes.all():
post.likes.remove(request.user)
else:
post.likes.add(request.user)
return Response({'status': 'ok'})
6.2 URL
# posts/urls.py
from django.urls import path
from rest_framework import routers
from .views import PostViewSet, like_post
router = routers.SimpleRouter()
router.register('posts', PostViewSet)
urlpatterns = router.urls + [
path('like/<int:pk>/', like_post, name='like_post')
]
7. 댓글 기능
7.1 댓글 기능 정리
- 댓글 생성
- 댓글 1개 가져오기
- 댓글 목록 가져오기
- 댓글 수정하기
- 댓글 삭제하기
- 게시글을 가져올 때 댓글도 가져오게 만들기
7.2 댓글 모델 & 마이그레이션
- 댓글 모델에 필요한 필드들
- 작성자, 작성자 프로필, 게시글, 내용
- 댓글의 경우 게시글과 밀접한 연관이 있음 → 따로 모델을 만들 필요는 없음
- Foreign Key로 유저, 프로필, 포스트와 연결됨 + 댓글 내용 텍스트만 추가
# posts/models.py
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
from users.models import Profile
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='author')
profile = models.ForeignKey(Profile, on_delete=models.CASCADE, blank=True)
title = models.CharField(max_length=128)
category = models.CharField(max_length=128)
body = models.TextField()
image = models.ImageField(upload_to='post/', default='default.png')
likes = models.ManyToManyField(User, related_name='like_posts', blank=True)
published_date = models.DateTimeField(default=timezone.now)
class Comment(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
profile = models.ForeignKey(Profile, on_delete=models.CASCADE)
post = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE)
text = models.TextField()
- 마이그레이션
# Migration
python manage.py makemigrations
python manage.py migrate
7.3 Serializers
- 댓글을 작성할 때, 가져올 때 각각 다른 시리얼라이저가 필요함 → 게시글 시리얼라이저와 비슷
- 게시글에서도 댓글을 불러올 수 있어야 함 → Nested Serializer 개념 활용(작성해 놓은 댓글 시리얼라이저를 게시글 시리얼라이저에 넣어주기)
- 게시글 시리얼라이저에 댓글 시리얼라이저가 포함됨 → 댓글 시리얼라이저가 더 위에 선언되어야 함
from rest_framework import serializers
from users.serializers import ProfileSerializer
from .models import Post, Comment
class CommentSerializer(serializers.ModelSerializer):
profile = ProfileSerializer(read_only=True)
class Meta:
model = Comment
fields = ("pk", "profile", "post", "text")
class CommentCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = ("post", "text")
class PostSerializer(serializers.ModelSerializer):
profile = ProfileSerializer(read_only=True)
comments = CommentSerializer(many=True, read_only=True)
class Meta:
model = Post
fields = ("pk", "profile", "title", "body", "image", "published_date", "likes", "comments")
class PostCreateSerializer(serializers.ModelSerializer):
image = serializers.ImageField(use_url=True, required=False)
class Meta:
model = Post
fields = ("title", "category", "body", "image")
7.4 Views
- ViewSet 사용
- 댓글에 필요한 권한은 게시글과 동일
- 댓글 보기: 모두
- 댓글 작성: 유저만
- 댓글 수정/삭제: 해당 댓글 작성자만 → CustomReadOnly 활용
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import viewsets
from rest_framework.decorators import api_view, permission_classes
from rest_framework.generics import get_object_or_404
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import generics, status
from users.models import Profile
from .models import Post, Comment
from .permissions import CustomReadOnly
from .serializers import PostSerializer, PostCreateSerializer, CommentSerializer, CommentCreateSerializer
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
permission_classes = [CustomReadOnly]
filter_backends = [DjangoFilterBackend]
filterset_fields = ['author', 'likes']
def get_serializer_class(self):
if self.action == 'list' or 'retrieve':
return PostSerializer
return PostCreateSerializer
def perform_create(self, serializer):
profile = Profile.objects.get(user=self.request.user)
serializer.save(author=self.request.user, profile=profile)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def like_post(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.user in post.likes.all():
post.likes.remove(request.user)
else:
post.likes.add(request.user)
return Response({'status': 'ok'})
class CommentViewSet(viewsets.ModelViewSet):
queryset = Comment.objects.all()
permission_classes = [CustomReadOnly]
def get_serializer_class(self):
if self.action == 'list' or 'retrieve':
return CommentSerializer
return CommentCreateSerializer
def perform_create(self, serializer):
profile = Profile.objects.get(user=self.request.user)
serializer.save(author=self.request.user, profile=profile)
7.5 URL
from django.urls import path
from rest_framework import routers
from .views import PostViewSet, like_post, CommentViewSet
router = routers.SimpleRouter()
router.register('posts', PostViewSet)
router.register('comments', CommentViewSet)
urlpatterns = router.urls + [
path('like/<int:pk>/', like_post, name='like_post')
]
- 실행
python manage.py runserver
728x90
'PYTHON-BACK' 카테고리의 다른 글
#파이썬 32일차_이커머스 클론코딩2 (0) | 2024.08.19 |
---|---|
#파이썬 31일차_이커머스 클론코딩1 (0) | 2024.08.16 |
#파이썬 30일차_게시판 만들기2 (0) | 2024.08.14 |
#파이썬 29일차_게시판 만들기1 (0) | 2024.08.13 |
#파이썬 28일차_MYSQL5 (0) | 2024.08.12 |