Django 개념
장고 rest api 게시판 게시글, 댓글 만들기 (DRF, json)
MC류짱
2022. 10. 17. 18:01
최종 코드를 보시려면 맨 아래에 있습니다.
세팅
- DRF 설치
- https://www.django-rest-framework.org/#installation
- pip install djangorestframework
- settings.py > INSTALLED_APPS 에 'rest_framework', 추가
- 더미데이터를 넣어줄 것 이라면 django seed 설치
- https://github.com/Brobin/django-seed
- pip install django-seed
- settings.py > INSTALLED_APP 에 'django_seed' 추가
- python manage.py seed 앱이름 --number=갯수
models.py
from django.db import models
# Create your models here.
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Comment(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
- models.py는 기존 템플릿으로 만들던 방식과 동일함
- python manage.py makemigrations
- python manage.py migrate
- 기존 articles앱 내의 fixtures폴더 안의 articles.json, comments.json DB에 넣기
- python manage.py loaddata articles.json comments.json
전체 게시글 조회
serializers.py 만들기
from rest_framework import serializers
from .models import Article, Comment
class ArticleListSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ('id', 'title', 'content')
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('articles/', views.article_list),
]
views.py
from django.urls import is_valid_path
from articles.serializers import ArticleListSerializer, ArticleSerializer, CommentSerializer
from .models import Article, Comment
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status
from django.shortcuts import get_object_or_404, get_list_or_404
@api_view(['GET'])
def article_list(request):
if request.method == 'GET':
# articles = Article.objects.all()
articles = get_list_or_404(Article)
serializer = ArticleListSerializer(articles, many=True)
return Response(serializer.data)
- 일단 나중의 전체 과정을 위해 편의상 필요한 모듈, 함수 import 해왔음
- serializer의 매개변수는 articles와 many=True 설정
- GET요청만 받도록 데코레이터 지정
포스트맨 확인
게시글 생성하기
serializers.py
from rest_framework import serializers
from .models import Article, Comment
class ArticleListSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ('id', 'title', 'content')
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = '__all__'
- 새로운 ArticleSerializer생성, 필드는 '__all__'
views.py
from django.urls import is_valid_path
from articles.serializers import ArticleListSerializer, ArticleSerializer, CommentSerializer
from .models import Article, Comment
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status
from django.shortcuts import get_object_or_404, get_list_or_404
@api_view(['GET', 'POST'])
def article_list(request):
if request.method == 'GET':
# articles = Article.objects.all()
articles = get_list_or_404(Article)
serializer = ArticleListSerializer(articles, many=True)
return Response(serializer.data)
# 이 부분 추가!!!!
elif request.method == 'POST':
serializer = ArticleSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
# return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
- 생성은 method가 POST
- 유효성 검사하는 함수에 raise_exception=True로 지정해주면 맨 밑에 에러와 400상태를 리턴하는 것 빼줘도 됨
- 유효성 검사를 통과했다면 201상태를 보여줌
포스트맨 확인
특정 게시글 조회
serializers.py
from rest_framework import serializers
from .models import Article, Comment
class ArticleListSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ('id', 'title', 'content')
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = '__all__'
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('articles/', views.article_list),
path('articles/<int:article_pk>/', views.article_detail),
]
views.py
from django.urls import is_valid_path
from articles.serializers import ArticleListSerializer, ArticleSerializer, CommentSerializer
from .models import Article, Comment
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status
from django.shortcuts import get_object_or_404, get_list_or_404
@api_view(['GET'])
def article_list(request):
if request.method == 'GET':
# articles = Article.objects.all()
articles = get_list_or_404(Article)
serializer = ArticleListSerializer(articles, many=True)
return Response(serializer.data)
@api_view(['GET'])
def article_detail(request, article_pk):
# article = Article.objects.get(pk=article_pk)
article = get_object_or_404(Article, pk=article_pk)
if request.method == 'GET':
serializer = ArticleSerializer(article)
return Response(serializer.data)
- article_detail 함수 만들어 주기
- article은 article_pk를 받아 쿼리셋을 찾아낸다.
- 이 함수에서 수정과 삭제 기능을 넣어줄 것.
포스트맨 확인
데이터 삭제, 수정하기
views.py
from django.urls import is_valid_path
from articles.serializers import ArticleListSerializer, ArticleSerializer, CommentSerializer
from .models import Article, Comment
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status
from django.shortcuts import get_object_or_404, get_list_or_404
@api_view(['GET', 'POST'])
def article_list(request):
if request.method == 'GET':
# articles = Article.objects.all()
articles = get_list_or_404(Article)
serializer = ArticleListSerializer(articles, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = ArticleSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
# return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET', 'DELETE', 'PUT'])
def article_detail(request, article_pk):
# article = Article.objects.get(pk=article_pk)
article = get_object_or_404(Article, pk=article_pk)
if request.method == 'GET':
serializer = ArticleSerializer(article)
return Response(serializer.data)
elif request.method == 'DELETE':
article.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
elif request.method == 'PUT':
serializer = ArticleSerializer(article, data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data)
- 기존 있던 article_detail함수에 메서드 추가, 동작 추가
포스트맨 확인
전체 댓글 조회하기
serializers.py
from rest_framework import serializers
from .models import Article, Comment
class ArticleListSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ('id', 'title', 'content')
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = '__all__'
# 이 부분 만들어주기!!
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = '__all__'
read_only_fields = ('article',)
- serializers.py에 CommentSerializer클래스 추가
- Meta의 read_only_fields에 article을 넣어준 것은 후에 유효성검사할때 article은 확인 하지 않도록 하기 위함이다.
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('articles/', views.article_list),
path('articles/<int:article_pk>/', views.article_detail),
path('comments/', views.comment_list),
]
views.py
from django.urls import is_valid_path
from articles.serializers import ArticleListSerializer, ArticleSerializer, CommentSerializer
from .models import Article, Comment
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status
from django.shortcuts import get_object_or_404, get_list_or_404
@api_view(['GET', 'POST'])
def article_list(request):
if request.method == 'GET':
# articles = Article.objects.all()
articles = get_list_or_404(Article)
serializer = ArticleListSerializer(articles, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = ArticleSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
# return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET', 'DELETE', 'PUT'])
def article_detail(request, article_pk):
# article = Article.objects.get(pk=article_pk)
article = get_object_or_404(Article, pk=article_pk)
if request.method == 'GET':
serializer = ArticleSerializer(article)
return Response(serializer.data)
elif request.method == 'DELETE':
article.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
elif request.method == 'PUT':
serializer = ArticleSerializer(article, data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data)
@api_view(['GET'])
def comment_list(request):
if request.method == 'GET':
# comments = Comment.objects.all()
comments = get_list_or_404(Comment)
serializer = CommentSerializer(comments, many=True)
return Response(serializer.data)
- commnet_list 함수 추가
- 기존 모든 게시글을 조회하는 article_list와 비슷함
포스트맨 확인
특정 댓글 조회, 수정, 삭제
serializers.py
from rest_framework import serializers
from .models import Article, Comment
class ArticleListSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ('id', 'title', 'content')
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = '__all__'
read_only_fields = ('article',)
class ArticleSerializer(serializers.ModelSerializer):
# comment_set = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
comment_set = CommentSerializer(many=True, read_only=True)
comment_count = serializers.IntegerField(source='comment_set.count', read_only=True)
class Meta:
model = Article
fields = '__all__'
- CommentSerializers를 ArticleSerializers위로 올려주고,
- ArticleSerializers 에 필드 오버라이드
- comment_set에 CommentSerializer를 참조하고, many=True, read_only=True로 매개변수를 넣어줌
- 댓글의 수를 알고 싶다면 필드 추가
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('articles/', views.article_list),
path('articles/<int:article_pk>/', views.article_detail),
path('comments/', views.comment_list),
path('comments/<int:comment_pk>/', views.comment_detail),
]
views.py
from django.urls import is_valid_path
from articles.serializers import ArticleListSerializer, ArticleSerializer, CommentSerializer
from .models import Article, Comment
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status
from django.shortcuts import get_object_or_404, get_list_or_404
@api_view(['GET', 'POST'])
def article_list(request):
if request.method == 'GET':
# articles = Article.objects.all()
articles = get_list_or_404(Article)
serializer = ArticleListSerializer(articles, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = ArticleSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
# return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET', 'DELETE', 'PUT'])
def article_detail(request, article_pk):
# article = Article.objects.get(pk=article_pk)
article = get_object_or_404(Article, pk=article_pk)
if request.method == 'GET':
serializer = ArticleSerializer(article)
return Response(serializer.data)
elif request.method == 'DELETE':
article.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
elif request.method == 'PUT':
serializer = ArticleSerializer(article, data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data)
@api_view(['GET'])
def comment_list(request):
if request.method == 'GET':
# comments = Comment.objects.all()
comments = get_list_or_404(Comment)
serializer = CommentSerializer(comments, many=True)
return Response(serializer.data)
@api_view(['GET', 'DELETE', 'PUT'])
def comment_detail(request, comment_pk):
# comment = Comment.objects.get(pk=comment_pk)
comment = get_object_or_404(Comment, pk=comment_pk)
if request.method == 'GET':
serializer = CommentSerializer(comment)
return Response(serializer.data)
elif request.method == 'DELETE':
comment.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
elif request.method == 'PUT':
serializer = CommentSerializer(comment, data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data)
- comment_detail함수 추가
- GET은 조회, DELETE는 삭제, PUT은 수정
댓글 생성하기
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('articles/', views.article_list),
path('articles/<int:article_pk>/', views.article_detail),
path('comments/', views.comment_list),
path('comments/<int:comment_pk>/', views.comment_detail),
path('articles/<int:article_pk>/comments/', views.comment_create),
]
views.py
from django.urls import is_valid_path
from articles.serializers import ArticleListSerializer, ArticleSerializer, CommentSerializer
from .models import Article, Comment
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status
from django.shortcuts import get_object_or_404, get_list_or_404
@api_view(['GET', 'POST'])
def article_list(request):
if request.method == 'GET':
# articles = Article.objects.all()
articles = get_list_or_404(Article)
serializer = ArticleListSerializer(articles, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = ArticleSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
# return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET', 'DELETE', 'PUT'])
def article_detail(request, article_pk):
# article = Article.objects.get(pk=article_pk)
article = get_object_or_404(Article, pk=article_pk)
if request.method == 'GET':
serializer = ArticleSerializer(article)
return Response(serializer.data)
elif request.method == 'DELETE':
article.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
elif request.method == 'PUT':
serializer = ArticleSerializer(article, data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data)
@api_view(['GET'])
def comment_list(request):
if request.method == 'GET':
# comments = Comment.objects.all()
comments = get_list_or_404(Comment)
serializer = CommentSerializer(comments, many=True)
return Response(serializer.data)
@api_view(['GET', 'DELETE', 'PUT'])
def comment_detail(request, comment_pk):
# comment = Comment.objects.get(pk=comment_pk)
comment = get_object_or_404(Comment, pk=comment_pk)
if request.method == 'GET':
serializer = CommentSerializer(comment)
return Response(serializer.data)
elif request.method == 'DELETE':
comment.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
elif request.method == 'PUT':
serializer = CommentSerializer(comment, data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data)
@api_view(['POST'])
def comment_create(request, article_pk):
# article = Article.objects.get(pk=article_pk)
article = get_object_or_404(Article, pk=article_pk)
serializer = CommentSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save(article=article)
return Response(serializer.data, status=status.HTTP_201_CREATED)
- comment_create함수 추가
- 기존 article생성 하는 것과 비슷하다.
- 이 때의 과정이 유효성 검사를 한 다음에 article을 추가해주는데, 이 부분에서 에러가 난다.
- 그래서 위의 serializers.py에서 read_only_fields에 article을 추가 해준 것이다.
포스트맨 확인
최종 코드
serializers.py
from rest_framework import serializers
from .models import Article, Comment
class ArticleListSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ('id', 'title', 'content')
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = '__all__'
read_only_fields = ('article',)
class ArticleSerializer(serializers.ModelSerializer):
# comment_set = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
comment_set = CommentSerializer(many=True, read_only=True)
comment_count = serializers.IntegerField(source='comment_set.count', read_only=True)
class Meta:
model = Article
fields = '__all__'
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('articles/', views.article_list),
path('articles/<int:article_pk>/', views.article_detail),
path('comments/', views.comment_list),
path('comments/<int:comment_pk>/', views.comment_detail),
path('articles/<int:article_pk>/comments/', views.comment_create),
]
views.py
from django.urls import is_valid_path
from articles.serializers import ArticleListSerializer, ArticleSerializer, CommentSerializer
from .models import Article, Comment
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status
from django.shortcuts import get_object_or_404, get_list_or_404
@api_view(['GET', 'POST'])
def article_list(request):
if request.method == 'GET':
# articles = Article.objects.all()
articles = get_list_or_404(Article)
serializer = ArticleListSerializer(articles, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = ArticleSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
# return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET', 'DELETE', 'PUT'])
def article_detail(request, article_pk):
# article = Article.objects.get(pk=article_pk)
article = get_object_or_404(Article, pk=article_pk)
if request.method == 'GET':
serializer = ArticleSerializer(article)
return Response(serializer.data)
elif request.method == 'DELETE':
article.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
elif request.method == 'PUT':
serializer = ArticleSerializer(article, data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data)
@api_view(['GET'])
def comment_list(request):
if request.method == 'GET':
# comments = Comment.objects.all()
comments = get_list_or_404(Comment)
serializer = CommentSerializer(comments, many=True)
return Response(serializer.data)
@api_view(['GET', 'DELETE', 'PUT'])
def comment_detail(request, comment_pk):
# comment = Comment.objects.get(pk=comment_pk)
comment = get_object_or_404(Comment, pk=comment_pk)
if request.method == 'GET':
serializer = CommentSerializer(comment)
return Response(serializer.data)
elif request.method == 'DELETE':
comment.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
elif request.method == 'PUT':
serializer = CommentSerializer(comment, data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data)
@api_view(['POST'])
def comment_create(request, article_pk):
# article = Article.objects.get(pk=article_pk)
article = get_object_or_404(Article, pk=article_pk)
serializer = CommentSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save(article=article)
return Response(serializer.data, status=status.HTTP_201_CREATED)