프로젝트 생성

$ django-admin startproject mypjt

 

app 생성

$ cd mypjt

$ python manage.py startapp movies

 

프로젝트 생성

$ django-admin startproject mypjt

 

app 생성

$ cd mypjt

$ python manage.py startapp movies

 

 

가상환경 설정

$ python -m venv venv
$ source venv/Scripts/activate
$ pip install -r requirements.txt

 

 

 

settings.py

INSTALLED_APPS = [
    'rest_framework',
    'movies',

LANGUAGE_CODE = 'ko-kr'
TIME_ZONE = 'Asia/Seoul'

 

 

 

 

movies- models.py

from django.db import models

class Actor(models.Model):
    name = models.CharField(max_length=100)

class Movie(models.Model):
    title = models.CharField(max_length=100)
    overview = models.TextField()
    release_date = models.DateTimeField()
    poster_path = models.TextField()
    actors = models.ManyToManyField(Actor)

class Review(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
  1. Actor

id, name 필드로 하기 위해 name 가지는 모델 생성

 

  1. Movie

actors 가지고 있다.

movie - actors M:N 관계로 ManyToManyField이다.

 

  1. Review

movie 참조하고 있다. movie review 1:N 관계로 FK 사용한다. on_delete 요소도 추가했다.

참조 필드는 참조 모델의 id 값을 가져오게 된다.

movie Movie모델을 참조하면서, 테이블에 movie_id필드를 가져오게 된다.

모델 필드 만들떄 movie_id 해버리면 movie_id_id 되기 때문에 주의하자.

 

 

 

movies - admin.py

from django.contrib import admin
from .models import Movie, Review, Actor
admin.site.register(Actor)
admin.site.register(Movie)
admin.site.register(Review)

 

 

 

 

load data

fixtures 파일 위치 : mypjt - movies - fixtures - movies - 파일(movies.json / reviews.json / actors.json )

 

$ python manage.py makemigrations

$ python manage.py migrate

$ python manage.py loaddata movies/actors.json movies/movies.json movies/reviews.json

 

 

 

 

 

mypjt - urls.py

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include('movies.urls'))
]

 

 

actor_list

movies - urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('actors/',views.actor_list),

actor의 리스트를 조회하는 url을 만들었다.

 

 

 

movies - serializers.py

from rest_framework import serializers
from .models import Actor, Movie, Review

class ActorSerializer(serializers.ModelSerializer):

    class Meta:
        model = Actor
        fields='__all__'

.models 아니고,  mypjt.movies.models import 하면 오류 생긴다. ..

actor 조회를 위한 serializer 만들었다. model = Actor로 하고 모든 필드를 가져왔다.

 

 

 

movies- models.py

from rest_framework.response import Response
from rest_framework.decorators import api_view
from .models import Actor
from .serializers import MovieSerializer, ReviewSerializer, ActorSerializer
from django.shortcuts import get_list_or_404, get_object_or_404

@api_view(['GET'])
def actor_list(request):
    actors = get_list_or_404(Actor)
    serializer = ActorSerializer(actors, many = True)
    return Response(serializer.data)

 

 

 

actors = Actor.objects.all()

actors를 가져올 때 위처럼 objects로 가져 올 있지만, 요소가 없을 에러가 발생한다.

get_list_or_404 가져오면, 요소가 없을 에러 대신에 404 보여준다.

 

 

 

전체 actor목록 조회 !

 

 

 

actor_detail

actor 정보 디테일

 

movies-urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('actors/',views.actor_list),
    path('actors/<int:actor_id>', views.actor_detail),

url 추가했다.

 

 

serializers.py

class MovieTitleSerializer(serializers.ModelSerializer):

    class Meta:
        model = Movie
        fields=('title',)

actor 정보에 movie title 나와야한다.

먼저 Movie title 나오는 serializer 만들었다.

 

 

class ActorDetailSerializer(serializers.ModelSerializer):
    movie_set = MovieTitleSerializer(many=True)
    class Meta:
        model = Actor
        fields='__all__'

위에서 만든 MovieTitleSerializer 이용하는 ActorDetailSerializer 만들었다.

역참조 해야 하기 때문에 movie_set 오버 라이딩 한다.

actor 기준에서 여러 movie가 나올 수 있기 때문에 (M:N) many = True를 지정한다.

 

 

 

 

movies - views.py

@api_view(['GET'])
def actor_detail(request, actor_id):
    actor = get_object_or_404(Actor, pk=actor_id)
    serializer = ActorDetailSerializer(actor)
    return Response(serializer.data)

 

 

 

movie_list

movie 전체 조회

 

movies- serializers.py

class MovieSerializer(serializers.ModelSerializer):

    class Meta:
        model = Movie
        fields=('title','overview',)

 

 

 

movies-urls.py

    path('movies/<int:movie_id>/', views.movie_detail),

 

 

 

movies - views.py

 

@api_view(['GET'])
def movie_detail(request, movie_id):
    movie = get_object_or_404(Movie, pk=movie_id)
    serializer = MovieSerializer(movie)
    return Response(serializer.data)

 

 

 

 

 

 

movie_detail

serializers.py

class ActorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Actor
        fields='__all__'

class ReviewSerializer(serializers.ModelSerializer):
    class Meta:
        model = Review
        fields=('title','content')

class MovieDetailSerializer(serializers.ModelSerializer):
    actors = ActorSerializer(many=True)
    review_set = ReviewSerializer(many=True)
    class Meta:
        model = Movie
        fields='__all__'

movie - review 에서도 review가 movie를 참조하기 때문에 역참조 매니저 review_set을 오버라이딩 했다.

 

 

 

 

views.py

@api_view(['GET'])
def movie_detail(request, movie_id):
    movie = get_object_or_404(Movie, pk=movie_id)
    serializer = MovieDetailSerializer(movie)
    return Response(serializer.data)

 

 

 

review_list

 

class ReviewSerializer(serializers.ModelSerializer):

    class Meta:
        model = Review
        fields=('title','content')

 

@api_view(['GET'])
def review_list(request):
    rivews = get_list_or_404(Review)
    serializer = ReviewSerializer(rivews, many = True)
    return Response(serializer.data)

리뷰 목록 조회

review 여러개를 가져오는 것이기 때문에 get_list_or_404를 이용했고, many=True로 ReviewSerializer에 넣어준다.

 

 

 

 

review_detail

class MovieTitleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Movie
        fields=('title',)


class ReviewDetailSerializer(serializers.ModelSerializer):
    movie = MovieTitleSerializer()
    class Meta:
        model = Review
        fields='__all__'

Review에는 movie 요소가 있고, 이것을 오버라이딩한다.

영화, 리뷰는 1:N으로 리뷰에는 영화가 하나로 정해져있기 때문에 movie에 many=True를 넣으면 안된다. (기본값 False)

이 serializer로 리뷰 생성도 할 것이기 때문에 read_only를 넣어주었다.

read_only는 movie가 읽기전용으로, 입력을 할 수 없게 하는 것이다. 리뷰를 작성할때 영화는 정해져있기때문이다.

 

 

@api_view(['GET'])
def review_detail(request, review_id):
    review = get_object_or_404(Review, pk=review_id)
    serializer = ReviewDetailSerializer(review)
    return Response(serializer.data)

리뷰 디테일 조회

 

 

 

 

 

review_detail 조회, 수정, 삭제

from rest_framework import status

@api_view(['GET','PUT','DELETE'])
def review_detail(request, review_id):
    review = get_object_or_404(Review, pk=review_id)
    
    if request.method =="GET":
        serializer = ReviewDetailSerializer(review)
        return Response(serializer.data)
        
    if request.method=='DELETE':
        review.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
        
    elif request.method == 'PUT':
        serializer = ReviewDetailSerializer(instance = review, data = request.data)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(serializer.data)

method GET, PUT, DELETE 나누어 조회, 수정, 삭제를 한번에 관리한다.

review_id 가지고 가져온 인스턴스 review 동일하게 사용하도록 위에 작성한다.

 

1. 조회

위에서 작성한 코드를 그대로 if request.method=="GET": 넣어준다.

 

2. 삭제

삭제한 뒤에 204 no content 상태를 리턴해준다.

 

3. 수정

인스턴스와 입력된 값을 serializer 넣어주어야 한다.

modelform 다르게 인스턴스, 데이터 순으로 매개변수를 작성한다.

is_valid() 해준 뒤에 save()해주어야 한다. (아니면 오류!)

is_valid 해줄때 raise_exception=True해주면, valid하지 않을때의 상태도 자동적으로 처리한다.

 

 

POSTMAN에서 확인가능하다.

 

 

create_review

urls.py

path('movies/<int:movie_id>/reviews/',views.create_review)

댓글 생성 url 추가

 

 

 

serializers.py

 

class MovieTitleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Movie
        fields=('title',)


class ReviewDetailSerializer(serializers.ModelSerializer):
    movie = MovieTitleSerializer(read_only=True)
    class Meta:
        model = Review
        fields='__all__'
        # read_only_fields = ('movie',)

review를 작성할 때 movie read_only 상태여야 한다read_only 해야 리뷰를 create   요소(movie)는 작성해주지 않는 것이기 때문이다.

read_only_fields = ('movies',) 혹은 read_only=True 지정한다.

 

 

@api_view(['POST'])
def create_review(request,movie_id):
    movie = get_object_or_404(Movie,pk=movie_id)
    serializer = ReviewDetailSerializer(data = request.data)
    if serializer.is_valid(raise_exception=True):
        serializer.save(movie=movie)
        return Response(serializer.data, status =status.HTTP_200_OK)

create로 POST method이다. movie_id로 Movie요소를 가지고 온다.

request.data data serializer 만든다.

data = 넣어주지 않으면, () 가장 파라미터는 인스턴스로 인식하기때문에 오류가 생긴다.

인스턴스가 아니고 data라는 것을 명시해주어야 한다.

저장하기 전에 is_valid(raise_exception=True)해준다.

 

postman으로 확인 가능하다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

'Back-end > Django' 카테고리의 다른 글

REST API (N:M)  (0) 2022.11.15
REST API (1:N)  (0) 2022.11.15
Fixtures - dumpdata, loaddata  (0) 2022.10.12
Django M:N 관계 - User끼리의 follow 구현하기  (0) 2022.10.12
Django M:N 관계 - 좋아요 버튼 / 프로필 페이지  (0) 2022.10.12