Django, Vue, GraphQL을 이용한 블로그 프로젝트 3

cathy·2024년 5월 22일

Projects

목록 보기
5/10
post-thumbnail

이제 GraphQL 과 GraphiQL을 위한 URL 패턴을 추가하기

장고가 GraphQL 엔트포인트와 GraphiQL 인터페이스를 제공하도록하기위해 새로운 URL 패턴을 'backend/urls.py'에 추가한다. 이 URL 패턴은 Graphene-Django의 'GraphQLView'를 가리킨다.

# backend/urls.py
from django.contrib import admin
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from graphene_django.views import GraphQLView

urlpatterns = [
    path("admin/", admin.site.urls),
    path("graphql/", csrf_exempt(GraphQLView.as_view(graphiql=True))),
]

GraphQL 스키마 생성하기

스키마는 각 Django 모델과 관련된 여러 클래스와 프론트엔드에서 필요한 몇 가지 중요한 쿼리 유형을 해결하는 방법을 지정하는 클래스로 구성된다.

  • 'blog/' 디렉토리에 'schema.py' 모듈을 새로 만든다.
  • 'DjangoObjectType', 블로그 모델, 장고 사용자 모델에 접근 할 수 있는 'get_user_model()'을 가져온다.
# back_end/blog/schema.py
from django.contrib.auth import get_user_model
from graphene_django import DjangoObjectType
from blog import models

이제 각 모델과 사용자 모델에 해당하는 클래스를 만든다. 각 클래스는 GraphQL 타입을 나타내므로 이름끝에 'Type'을 붙인다.

# back_end/blog/schema.py
class UserType(DjangoObjectType):
    class Meta:
        model = get_user_model()

class AuthorType(DjangoObjectType):
    class Meta:
        model = models.Profile

class PostType(DjangoObjectType):
    class Meta:
        model = models.Post

class TagType(DjangoObjectType):
    class Meta:
        model = models.Tag

추가적으로 'graphene.ObjectType'을 상속하는 'Query' 클래스를 만들어야한다. 이 클래스는 생성한 모든 타입 클래스를 하나로 모아준다. 'graphene'을 가져와서 쿼리할 모델을 지정하는 메소드를 추가한다.

# back_end/blog/schema.py
import graphene
from django.contrib.auth import get_user_model
from graphene_django import DjangoObjectType
from blog import models

class Query(graphene.ObjectType):
    all_posts = graphene.List(PostType)
    author_by_username = graphene.Field(AuthorType, username=graphene.String())
    post_by_slug = graphene.Field(PostType, slug=graphene.String())
    posts_by_author = graphene.List(PostType, username=graphene.String())
    posts_by_tag = graphene.List(PostType, tag=graphene.String())

    def resolve_all_posts(root, info):
        return models.Post.objects.prefetch_related("tags").select_related("author").all()

    def resolve_author_by_username(root, info, username):
        return models.Profile.objects.select_related("user").get(user__username=username)

    def resolve_post_by_slug(root, info, slug):
        return models.Post.objects.prefetch_related("tags").select_related("author").get(slug=slug)

    def resolve_posts_by_author(root, info, username):
        return models.Post.objects.prefetch_related("tags").select_related("author").filter(author__user__username=username)

    def resolve_posts_by_tag(root, info, tag):
        return models.Post.objects.prefetch_related("tags").select_related("author").filter(tags__name__iexact=tag)

'Query'클래스는 'graphene.List' 또는 'graphene.Field' 유형의 여러 속성으로 구성된다. 단일 항목을 반환하는 쿼리에는 'graphene.Field'를 사용하고, 여러 항목을 반환하는 쿼리에는 'graphene.List'를 사용한다.

이제 모든 타입과 resolver를 가진 스키마가 완성되었다.

# back_end/blog/schema.py
schema = graphene.Schema(query=Query)

이제 서버를 실행하여 GraphQL 인터페이스에 접속하자.

python manage.py runserver

브라우저를 열고 localhost:8000/graphql 주소로 이동하면 다음과 같은 화면이 뜬다.

여기에서 GraphiQL 인터페이스를 사용하여 GraphQL 쿼리를 실행 할 수 있다. 또한 저장된 데이터에 접근하고 다양한 쿼리를 테스트 할 수 있다.

GraphiQL 활성화 확인

이제 화면 좌측 상단의 Docs 섹션을 확장하고 'query:Query'를 클릭한다. 이제 다음 쿼리를 입력해보자! 다음 쿼리는 생성한 모든 게시물의 리스트를 반환한다.

{
  allPosts {
    title
    author {
      user {
        username
      }
    }
    tags {
      name
    }
  }
}

위의 쿼리를 입력 후 play 버튼을 누르면 게시물 목록을 반환받는다.

django-cors-headers 설정

백엔드와 프론트엔드가 로컬에서 다른 포트에서 실행이 되기때문에, 프로덕션 환경에서 완전히 별개의 도메인에서 실행 될 수 있기 때문에 교차 출처 리소스 공유(Cross-origin resource sharing, CORS)를 처리해야한다. 이를 처리하지 않으면 프론트엔드에서 백엔드로의 요청이 브라우저에 의해 차단된다. django-cors-headers 프로젝트를 사용하면 CORS를 쉽게 처리 할 수 있다. 이 프로젝트를 사용하여 Django가 다른 출처에서 오는 요청에도 응답하도록 설정하면 프론트엔드가 GraphQL API와 원활하게 통신 할 수 있다.

교차 출처 리소스 공유(CORS)란?
추가 HTTP 헤더를 사용하여 한 출처에서 실행중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근 할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다. 웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행한다.

django-cors-headers 설치

'django-cors-headers'를 requirements 파일에 추가한다.

이제 업데이트된 requirements 파일을 사용하여 패키지를 설치한다.

yeryeongseo@seoyelyeong-ui-MacBookPro backend % python3 -m pip install -r requirements.txt 

이제 프로젝트의 'settings.py' 모듈에서 'INSTALLED_APPS' 리스트에 'corsheaders'를 추가한다.

저장하기전에 'MIDDLEWARE'리스트의 맨 앞에 "corsheaders.middleware.CorsMiddleware" 을 추가한다. django-cors-headers 문서에서는 미들웨어 리스트의 가능한 앞 쪽에 이 미들웨어를 두는것을 권장한다고한다. 최소한 Django의 'CommonMiddleware'보다 앞에 두어야한다.

이제 django-cors-headers 를 설치해보자

yeryeongseo@seoyelyeong-ui-MacBookPro back_end % pip3 install django-cors-headers

특정 도메인에서만 요청을 허용하려면 settings.py 에 다음을 추가해준다.

CORS_ALLOWED_ORIGINS = [
    "http://localhost:5173",
]

이제 Django 백엔드가 CORS 설정을 통해 프론트엔드에서의 요청을 허용 할 수 있다.

Vue.js 설정

Node.js 설치

공식홈페이지에서 다운받아준다.

설치 확인

설치가 확인되었다면 Vue 프로젝트를 생성할 디렉토리 'dvg'로 이동해 생성한다.

Project name(프로젝트 이름): front_end
Add TypeScript?(TypeScript를 추가하시겠습니까?): No
Add JSX Support?(JSX 지원을 추가하시겠습니까?): No
Add Vue Router for Single Page Application development?(단일 페이지 애플리케이션 개발을 위해 Vue Router를 추가하시겠습니까?): Yes
Add Pinia for state management?(상태 관리를 위해 Pinia를 추가하시겠습니까?): No
Add Vitest for Unit Testing?(단위 테스트를 위해 Vitest를 추가하시겠습니까?): No
Add an End-to-End Testing Solution?(종단 간 테스트 솔루션을 추가하시겠습니까?): No
Add ESLint for code quality?(코드 품질을 위해 ESLint를 추가하시겠습니까?): No
Add Vue DevTools 7 extension for debugging?(디버깅을 위해 Vue DevTools 7 확장을 추가하시겠습니까?): Yes(그냥 Yes해봄)

이제 백엔드 폴더, 프론트엔드 폴더가 만들어진걸 확인 할 수 있다.

front_end/ 폴더로 이동하여 프로젝트의 모든 종속 항목을 설치한다.

프로젝트 구조가 마련되고 모든 종속 항목이 설치되었으므로 Vite 개발 서버를 실행 할 수 있다.

Vite란..

$ npm run dev

기본적으로 Vite 서버는 5173 포트에서 실행된다. 이제 Django 애플리케이션은 http://localhost:8000 에서 실행되고 Vue 애플리케이션은 http://localhost:5173 에서 실행된다. http://localhost:5173를 방문해보자.

야호

0개의 댓글