├── .gitignore ├── README.md ├── REST Framework Tutorial.md ├── doc ├── Django REST Framework - 01. Requests.md ├── Django REST Framework - 02. Responses.md ├── Django REST Framework - 03. Views.md ├── Django REST Framework - 04. Generic views.md ├── Django REST Framework - 05. ViewSets.md ├── Django REST Framework - 06. Routers.md ├── Django REST Framework - 07. Parsers.md ├── Django REST Framework - 08. Renderers.md ├── Django REST Framework - 09. Serializers.md ├── Django REST Framework - 10. Serializer fields.md ├── Django REST Framework - 11. Serializer relations.md ├── Django REST Framework - 12. Validators.md ├── Django REST Framework - 13. Authentication.md ├── Django REST Framework - 14. Permissions.md ├── Django REST Framework - 15. Throttling.md ├── Django REST Framework - 16. Filtering.md ├── Django REST Framework - 17. Pagination.md ├── Django REST Framework - 18. Versioning.md ├── Django REST Framework - 19. Content negotiation.md ├── Django REST Framework - 20. Metadata.md ├── Django REST Framework - 21. Schemas.md ├── Django REST Framework - 22. Format suffixes.md ├── Django REST Framework - 23. Returning URLs.md ├── Django REST Framework - 24. Exceptions.md ├── Django REST Framework - 25. Status Codes.md ├── Django REST Framework - 26. Testing.md ├── Django REST Framework - 27. Settings.md └── images │ ├── AdminRenderer.png │ ├── BrowsableAPIRenderer.png │ ├── DefaultRouter.png │ ├── SimpleRouter.png │ ├── fieldfilter.png │ ├── genericfiltering.png │ ├── linkheader.png │ ├── orderingfilter.png │ ├── searchfilter.png │ ├── serializer.jpeg │ ├── token1.png │ ├── token2.png │ ├── token3.png │ └── token_delete.png ├── requirements.txt └── tutorial ├── db.sqlite3 ├── manage.py ├── snippets ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── permissions.py ├── serializers.py ├── tests.py ├── urls.py └── views.py └── tutorial ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.db 2 | *.pyc 3 | *~ 4 | .* 5 | env 6 | .idea/ 7 | .conf/ 8 | # Accept these files in the repository 9 | !.gitignore 10 | !.travis.yml 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Django REST Framework Tutorial 2 | 3 | [Django REST framework tutorial](http://www.django-rest-framework.org/tutorial/1-serialization/) 4 | 5 | --- 6 | 7 | - Tutorial 8 | 9 | --- 10 | 11 | - doc 12 | > - testing 13 | > - Serializers 14 | > - Serializer fields 15 | > - Serializer relations 16 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 01. Requests.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Requests 2 | 3 | --- 4 | _"If you're doing REST-based web service stuff ... you should ignore request.POST." 5 | "REST 기반 웹 서비스 작업을 하고있다면 ... POST 요청을 무시해야한다." 6 | — Malcom Tredinnick_ 7 | 8 | 9 | ## Requests 10 | 11 | REST 프레임워크의 `Request` 클래스는 표준 `HttpRequest`를 확장하여 REST 프레임워크의 유연한 request 구문 분석 및 요청 인증을 지원합니다. 12 | 13 | ## Request parsing 14 | REST 프레임워크의 Request 객체는 유연한 request 구문 분석 기능을 제공하므로 사용자가 일반적으로 form 데이터를 처리하는 것과 같은 방식으로 JSON 데이터 또는 다른 미디어 유형으로 요청을 처리 할 수 ​​있습니다. 15 | 16 | ### .data 17 | `request.data`는 요청 본문의 구문 분석 된 내용을 반환합니다. 이는 다음을 제외하고 표준 `request.POST` 및 `request.FILES` 속성과 유사합니다. 18 | 19 | - 여기에는 파일과 파일이 아닌 입력을 포함하여 파싱 된 모든 내용이 포함됩니다. 20 | - `POST`가 아닌 `HTTP`메소드의 컨텐츠 분석을 지원합니다. 즉, `PUT`과 `PATCH` 요청의 컨텐츠에 액서스 할 수 있습니다. 21 | - 이는 form 테이터를 지원하는 것보다 REST 프레임워크의 유연한 request 구문 분석을 지원합니다. 예를 들어, 들어오는 form 데이터를 처리하는 것과 같은 방식으로 들어오는 JSON 데이터를 처리 할 수 있습니다. 22 | 더 자세한 내용은 [parsers documentation](http://www.django-rest-framework.org/api-guide/parsers/)을 참조하세요. 23 | 24 | ### .query_params 25 | `request.query_params`는 `request.GET`에 대해 보다 정확하게 명명 된 동의어입니다. 26 | 코드 내에서 명확성을 위해 Django의 표준 `request.GET` 대신 `request.query_params`를 사용하는 것이 좋습니다. 이렇게 하면 코드베이스를 보다 정확하고 명확하게 유지할 수 있습니다. 모든 HTTP 메소드 유형에는 `GET`request 뿐만 아니라 쿼리 parameter가 포함될 수 있습니다. 27 | 28 | ### .parsers 29 | `APIView` 클래스나 `@api_view` 데코레이터는 뷰에 설정 된 `parser_classes`나 `DEFAULT_PARSER_CLASSES`설정에 따라 속성이 자동으로 `Parser` 인스턴스 목록으로 설정되도록 합니다. 30 | 일반적으로 이 속성에 액서스 할 필요는 없습니다. 31 | 32 | --- 33 | **NOTE**: 클라이언트가 조작 된 콘텐츠를 보낸 경우 `request.data`에 액서스하면 `ParserError`가 발생할 수 있습니다. 기본적으로 REST 프레임워크의 `APIView` 클래스나 `@api_view`데코레이터는 오류를 포착하고, `400 Bad Request` 응답을 반환합니다. 34 | 클라이언트가 파싱 할 수 없는 content-type을 가진 request를 보내면 `UnsuppoertedMediaType`예외가 발생합니다. 이 예외는 기본적으로 포착되어 지원되지 않는 미디어 유형 응답을 반환합니다. 35 | 36 | --- 37 | 38 | ## Content negotiation 39 | request는 콘텐츠 협상 단계의 결과를 결정할 수 있는 몇가지 속성을 제공합니다. 이를 통해 다양한 미디어 유형에 대해 다른 serializer 스키마를 선택하는 것과 같은 동작을 구현할 수 있습니다. 40 | 41 | ### .accepted_renderer 42 | renderer 인스턴스는 컨텐츠 협상 단계에서 선택 된 인스턴스입니다. 43 | 44 | ### .accepted_media_type 45 | 내용 협상 단계에서 수락 한 미디어 유형을 나타내는 문자열입니다. 46 | 47 | --- 48 | 49 | ## Authentication (입증) 50 | REST 프레임워크는 다음과 같은 기능을 제공하는 유연한 request 별 인증을 제공합니다. 51 | 52 | - API의 다른 부분에 대해 서로 다른 인증 정책을 사용합니다. 53 | - 다중 인증 정책의 사용을 지원합니다. 54 | - 들어오는 request와 관련된 사용자와 토큰 정보를 제공합니다. 55 | 56 | ### .user 57 | `request.user`는 일반적으로 `django.contrib.auth.models.User`의 인스턴스를 반환하지만 동작은 사용되는 인증 정책에 따라 다릅니다. 58 | request이 인증되지 않은 경우 request.user의 기본값은 `django.contrib.auth.models.AnonymousUser`의 인스턴스입니다. 59 | 자세한 내용은 [authentication documentation](http://www.django-rest-framework.org/api-guide/authentication/)을 참조하세요. 60 | 61 | ### .auth 62 | `request.auth`는 추가 인증 컨텍스트를 리턴합니다. `request.auth`의 정확한 작동은 사용되는 인증 정책에 따라 다르지만 대개 request가 인증 된 토큰의 인스턴스 일 수 있습니다. 63 | request가 인증되지 않았거나 추가 컨텍스트가 없는 경우, `request.auth`의 기본값은 없습니다. 64 | 자세한 내용은 [authentication documentation](http://www.django-rest-framework.org/api-guide/authentication/)을 참조하세요. 65 | 66 | ### .authenticators 67 | `APIView` 클래스나 `@api_view`데코레이터는 뷰에 설정된 `authentication_classes`나 `DEFAULT_AUTHENTICATORS` 설정에 따라 속성이 자동으로 `Authentication`인스턴스 목록으로 설정되도록 합니다. 68 | 일반적으로 이 속성에 액서스 할 필요는 없습니다. 69 | 70 | --- 71 | 72 | ## Browser enhancements 73 | REST 프레임워크는 브라우저 기반의 `PUT`, `PATCH`, `DELETE` form과 같은 몇 가지 브라우저 개선 사항을 지원합니다. 74 | 75 | ### .method 76 | `request.method`는 request의 HTTP 메소드의 **uppercased**(대문자)로 된 문자열 표현을 리턴합니다. 77 | 브라우저 기반의 `PUT`, `PATCH` 및 `DELETE` form이 투명하게 지원됩니다. 78 | 자세한 내용은 [browser enhancements documentation](http://www.django-rest-framework.org/topics/browser-enhancements/)을 참조하세요. 79 | 80 | ### .content_type 81 | `request.content_type`은 HTTP request 본문의 미디어 유형을 나타내는 문자열 객체를 반환하거나 미디어 유형이 제공되지 않은 경우 빈 문자열을 반환합니다. 82 | 일반적으로 REST 프레임워크의 기본 request 구문 분석 동작에 의존하므로 일반적으로 request의 콘텐츠 형식에 직접 액서스 할 필요가 없습니다. 83 | request의 콘텐츠 형식에 액서스해야하는 경우 브라우저 기반 non-form 콘텐츠에 대한 투명한 지원을 제공하므로 `request.META.get('HTTP_CONTENT_TYPE')`을 사용하는 것보다 `.content_type`속성을 사용해야 합니다. 84 | 자세한 내용은 [browser enhancements documentation](http://www.django-rest-framework.org/topics/browser-enhancements/)을 참조하세요. 85 | 86 | ### .stream 87 | `request.stream`은 request 본문의 내용을 나타내는 스트림을 반환합니다. 88 | 일반적으로 REST 프레임워크의 기본 request 구문 분석 동작에 의존하므로 대개 request의 콘텐츠에 직접 액세스 할 필요가 없습니다. 89 | 90 | --- 91 | 92 | ## Standard HttpRequest attributes 93 | REST 프레임워크의 `request`는 Django의 `HttpRequest`를 확장하므로 다른 모든 표준 속성과 메소드도 사용할 수 있습니다. 예를 들어, `request.META`와 `request.session` dict는 정상적으로 사용 가능합니다. 94 | 구현 이유로 인해 `Request`클래스는 `HttpRequest`클래스에 상속하지 않고 대신 `composition`을 사용하여 클래스를 확장합니다. 95 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 02. Responses.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Responses 2 | 3 | --- 4 | 5 | _"Unlike basic HttpResponse objects, TemplateResponse objects retain the details of the context that was provided by the view to compute the response. The final output of the response is not computed until it is needed, later in the response process."_ 6 | 7 | _"기본 HttpResponse 객체와 달리 TemplateResponse 객체는 응답을 계산하기 위해 뷰에서 제공한 컨텍스트의 세부 정보를 유지합니다. response의 최종 출력은 나중에 응답 프로세스에서 필요할 때까지 계산되지 않습니다."_ 8 | 9 | _— Django documentation_ 10 | 11 | ## Responses 12 | REST 프레임워크는 클라이언트 요청에 따라 여러 콘텐츠 형식으로 렌더링 할 수 있는 콘텐츠를 반환할 수 있는 `Response` 클래스를 제공하여 HTTP 콘텐츠 협상을 지원합니다. 13 | `response` 클래스는 Django의 `SimpleTemplateResponse`하위 클래스입니다. `response`객체는 Python 기본 요소로 구성되어야 하는 데이터로 초기화됩니다. 그런 다음 REST 프레임워크는 표준 HTTP 내용 협상을 사용하여 최종 응답 내용을 렌더링하는 방법을 결정합니다. 14 | `Response` 클래스를 사용할 필요는 없으며, 필요한 경우 일반 `HttpResponse`나 `StreamingHttpResponse` 객체를 뷰에서 반환 할 수도 있습니다. `Response`클래스를 사용하면 여러가지 형식으로 렌더링 할 수 있는 컨텐츠 협상 웹 API 응답을 반환하기에 더 좋은 인터페이스만 제공됩니다. 15 | 어떤 이유로든 REST 프레임워크를 많이 사용자 정의하지 않으려면 `Response`객체를 반환하는 뷰에 항상 `APIView`클래스나 `@api_view`함수를 사용해야 합니다. 이렇게하면 뷰에서 내용협상을 수행하고 응답에 적합한 렌더러를 선택하여 뷰에 반환 할 수 있습니다. 16 | 17 | --- 18 | 19 | ## Creating responses 20 | 21 | ### Response() 22 | **Signature** : `Response(data, status=None, template_name=None, headers=None, content_type=None)` 23 | 일반 `HttpResponse`개체와 달리 렌더링 된 콘텐츠로 `Response` 개체를 인스턴스화하지 않습니다. 대신 기존의 파이썬으로 구성된 렌더링되지 않은 데이터를 전달합니다. 24 | `Response`클래스에서 사용하는 렌더러는 Django모델 인스턴스와 같은 복잡한 데이터 유형을 기본적으로 처리 할 수 없으므로 `Response`객체를 만들기 전에 데이터를 기본 데이터 유형으로 serializer해야 합니다. 25 | REST 프레임워크의 `Serializer`클래스를 사용하여 데이터를 serializer를 수행하거나 custom serializer를 사용할 수 있습니다. 26 | 27 | Arguments: 28 | 29 | - `data`: response의 serializer 된 데이터입니다. 30 | - `status`: response의 상태 코드입니다. 기본값은 200입니다. [status codes](http://www.django-rest-framework.org/api-guide/status-codes/) 참조 31 | - `template_name`: `HTMLRenderer`가 선택된 경우 사용할 템플릿 이름입니다. 32 | - `headers`: 응답에 사용할 HTTP 헤더 dict입니다. 33 | - `content_type`: 응답의 내용 유형입니다. 일반적으로 콘텐츠 협상에 따라 렌더러에서 자동으로 설정되지만 콘텐츠 유형을 명시적으로 지정해야하는 경우가 있습니다. 34 | 35 | --- 36 | 37 | ## Attributes 38 | 39 | ### .data 40 | `Request` 객체의 렌더링되지 않은 내용입니다. 41 | 42 | ### .status_code 43 | HTTP 응답의 숫자 상태 코드입니다. 44 | 45 | ### .content 46 | `response`의 렌더링 된 내용입니다. `.content`에 액서스하려면 먼저 `.render()`메서드를 호출해야 합니다. 47 | 48 | ### .template_name 49 | `template_name`이 제공된 경우. `HTTPRenderer`나 다른 custom 템플릿 렌더러가 응답에 대해 허용된 렌더러인 경우에만 필요합니다. 50 | 51 | ### .accepted_renderer 52 | 응답을 렌더링하는데 사용되는 렌더러 인스턴스입니다. 53 | 뷰에서 응답이 반환되기 직전에 `APIView`나 `@api_view`에 의해 자동으로 설정됩니다. 54 | 55 | ### .accepted_media_type 56 | 콘텐츠 협상 단계에서 선택한 미디어 유형입니다. 57 | 뷰에서 응답이 반환되기 직전에 `APIView`나 `@api_view`에 의해 자동으로 설정됩니다. 58 | 59 | ### .renderer_context 60 | 렌더러의 `.render()`메소드에 전달 될 추가 컨텍스트 정보의 dict입니다. 61 | 뷰에서 응답이 반환되기 직전에 `APIView`나 `@api_view`에 의해 자동으로 설정됩니다. 62 | 63 | ## Standard HttpResponse attributes 64 | `Response`클래스는 `SimpleTemplateResponse`를 확장하고 모든 일반적이니 특성과 메서드를 response에서도 사용할 수 있습니다. 예를 들어 표준방식으로 response에 헤더를 설정 할 수 있습니다. 65 | 66 | ```python 67 | response = Response() 68 | response['Cache-Control'] = 'no-cache' 69 | ``` 70 | 71 | ### .render() 72 | **Signature**: `.render()` 73 | 다른 `TemplateResponse`와 마찬가지로 이 메소드는 응답의 serializer 된 데이터를 최종 response 컨텐츠로 렌더링하기 위해 호출됩니다. `.render()`가 호출되면 `accept_renderer`인스턴스에서 `.render (data, accepted_media_type, renderer_context)` 메서드를 호출 한 결과로 response 내용이 설정됩니다. 74 | 일반적으로 Django의 표준 응답주기에 의해 처리되므로 `.render()`를 직접 호출 할 필요가 없습니다. 75 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 03. Views.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Views 2 | 3 | --- 4 | 5 | _"Django's class-based views are a welcome departure from the old-style views."_ 6 | 7 | _"Django의 CBV는 구식 뷰에서 출발하는 것을 환영합니다."_ 8 | 9 | _— Reinout van Rees_ 10 | 11 | --- 12 | 13 | ## Class-based Views 14 | REST 프레임워크는 Django의 `View` 클래스를 하위 클래스로 하는 `APIView`클래스를 제공합니다. 15 | `APIView`클래스는 다음과 같은 방식으로 일반 `View`클래스와 다릅니다. 16 | 17 | - 핸들러 메서드에 전달 된 `Request`는 Django의 `HttpRequest` 인스턴스가 아닌 REST 프레임워크의 `request`인스턴스가 됩니다. 18 | - 핸들러 메서드는 Django의 `HttpResponse` 대신 REST 프레임워크의 `Response`를 반환 할 수 있습니다. 뷰는 콘텐츠 협상을 관리하고 `response`에서 올바른 렌더러를 설정합니다. 19 | - 모든 `APIException` 예외가 발견되면 적절한 `response`으로 조정됩니다. 20 | - 들어오는 request가 인증이 된 request를 핸들러 메서드에 보내기 전에 적절한 권한과 `/` 또는 `throttle(제한)` 체크를 실행합니다. 21 | 22 | `APIView` 클래스를 사용하는 것은 일반 `View`클래스를 사용하는 것과 거의 같습니다. 들어오는 request은 `.get()`이나 `.post()`와 같은 적절한 핸들러 메서드로 전달됩니다. 또한 API 정책의 다양한 측면을 제어하는 여러 속성을 클래스에 설정 할 수 있습니다. 23 | 24 | 예를 들어: 25 | 26 | ```python 27 | from rest_framework.views import APIView 28 | from rest_framework.response import Response 29 | from rest_framework import authentication, permissions 30 | 31 | class ListUsers(APIView): 32 | """ 33 | View to list all users in the system. 34 | 35 | * 토큰 인증이 필요합니다. 36 | * 관리자만 view에 액서스 할 수 있습니다. 37 | """ 38 | authentication_classes = (authentication.TokenAuthentication,) 39 | permission_classes = (permissions.IsAdminUser,) 40 | 41 | def get(self, request, format=None): 42 | """ 43 | 모든 사용자 리스트를 반환합니다. 44 | """ 45 | usernames = [user.username for user in User.objects.all()] 46 | return Response(usernames) 47 | ``` 48 | 49 | ### API policy attributes(API 정책 속성) 50 | 다음 속성들은 API view의 플러그 가능한 부분을 제어합니다. 51 | `.renderer_classes` 52 | `.parser_classes` 53 | `.authentication_classes` 54 | `.throttle_classes` 55 | `.permission_classes` 56 | `.content_negotiation_class` 57 | 58 | ### API policy instantiation methods(API 정책 인스턴스화 메서드) 59 | 다음 메서드들은 REST 프레임워크에서 다양한 플러그가 가능한 API 정책을 인스턴스화하는데 사용됩니다. 일반적으로 이러한 메서드를 재정의 할 필요는 없습니다. 60 | `.get_renderers(self)` 61 | `.get_parsers(self)` 62 | `.get_authenticators(self)` 63 | `.get_throttles(self)` 64 | `.get_permissions(self)` 65 | `.get_content_negotiator(self)` 66 | `.get_exception_handler(self)` 67 | 68 | ### API policy implementation methods(API 정책 구현 방법) 69 | 다음 메서드는 핸들러 메서드에 전달하기 전에 호출됩니다. 70 | `.check_permissions(self, request)` 71 | `.check_throttles(self, request)` 72 | `.perform_content_negotiation(self, request, force=False)` 73 | 74 | ### Dispatch methods (파견 메서드) 75 | 다음 메서드는 뷰의 `.dispatch()`메서드에 의해 직접 호출됩니다. 이 메서드들은 `.get()`, `.post()`, `put()`, `patch()` 및 `.delete()`와 같은 핸들러 메서드들을 호출하기 전후에 수행되어야하는 모든 조치들을 수행합니다. 76 | 77 | #### `.initial(self, request, *args, **kwargs)` 78 | 핸들러 메서드가 호출되기 전에 발생해야하는 모든 작업을 수행합니다. 이 메서드는 사용 권한 및 제한을 적용하고 콘텐츠 협상을 수행하는데 사용됩니다. 79 | 일반적으로 이 메서드를 재정의 할 필요는 없습니다. 80 | 81 | #### `.handle_exception(self, exc)` 82 | 핸들러 메서드에 의해 버려진 예외는 `Resopnse`인스턴스를 반환하거나 예외를 다시 발생시키는 이 메서드로 전달됩니다. 83 | 기본 구현에서는 Django의 `Http404`와 `PermissionDenied`예외 뿐만 아니라 `rest_framework.exceptions.APIXeception`의 하위 클래스를 처리하고 적절한 오류 response를 반환합니다. 84 | API에서 반환하는 오류 response를 사용자 정의해야하는 경우 이 메소드를 서브 클래스화해야 합니다. 85 | 86 | #### `.initialize_request(self, request, *args, **kwargs)` 87 | 핸들러 메소드에 전달 된 request 객체가 일반적인 Django `HttpRequest`가 아닌 `Request`의 인스턴스인지 확인합니다. 88 | 일반적으로 이 메서드를 재정의 할 필요는 없습니다. 89 | 90 | #### `.finalize_response(self, request, response, *args, **kwargs)` 91 | 핸들러 메서드에서 반환 된 모든 `Response`객체가 내용 협상에 의해 결정된 대로 올바른 내용 유형으로 렌더링되도록 합니다. 92 | 일반적으로 이 메서드는 재정의 할 필요는 없습니다. 93 | 94 | --- 95 | 96 | ### Function Based Views 97 | _"Saying [that class-based views] is always the superior solution is a mistake."_ 98 | _"[그 클래스 기반의 견해]가 항상 우월한 해결책은 실수라고 말하는 것입니다."_ 99 | 100 | _— Nick Coghlan_ 101 | 102 | REST 프레임워크를 사용하면 일반 FBV로 작업 할 수 있습니다. 그것은 간단한 Django `HttpRequest`가 아닌 `Request`의 인스턴스를 수신하고 Django `HttpResponse` 대신 `response`을 리턴 할 수 있도록 FBV를 래핑하는 간단한 데코레이터 세트를 제공하며, request가 처리됩니다. 103 | 104 | ### @api_view() 105 | **Signature**: `@api_view(http_method_names=['GET'], exclude_from_schema=False)` 106 | 이 기능의 핵심은 `api_view`데코레이터(뷰가 응답해야하는 HTTP 메서드 리스트를 사용함)입니다. 예를 들어, 다음은 몇 가지 데이터를 수동으로 반환하는 아주 간단한 view를 작성하는 방법입니다. 107 | 108 | ```python 109 | from rest_framework.decorators import api_view 110 | 111 | @api_view() 112 | def hello_world(request): 113 | return Response({"message": "Hello, world!"}) 114 | ``` 115 | 이 뷰는 [설정](http://www.django-rest-framework.org/api-guide/settings/)에 지정된 기본 렌더러, 파서, 인증 클래스 등을 사용합니다. 116 | 기본적으로 `GET`메서드만 허용됩니다. 다른 메서드들은 "405 Method Not Allowed"로 응답합니다. 이 동작을 변경하려면 view에서 허용하는 방법을 지정하세요. 117 | 118 | ```python 119 | @api_view(['GET', 'POST']) 120 | def hello_world(request): 121 | if request.method == 'POST': 122 | return Response({"message": "Got some data!", "data": request.data}) 123 | return Response({"message": "Hello, world!"}) 124 | ``` 125 | `exclude_from_schema`인수를 사용하여 API 뷰를 [자동 생성 스키마(auto-generated schema)](http://www.django-rest-framework.org/api-guide/schemas/)에서 생략된 것으로 표시 할 수도 있습니다. 126 | 127 | ```python 128 | @api_view(['GET'], exclude_from_schema=True) 129 | def api_docs(request): 130 | ... 131 | ``` 132 | 133 | ### API policy decorators 134 | 기본 설정을 재정의하기 위해 REST 프레임워크는 뷰에 추가 할 수 있는 일련의 추가 데코레이터를 제공합니다. 이들은 `@api_view`데코레이터 다음에 와야합니다. 예를 들어, [`throttle`](http://www.django-rest-framework.org/api-guide/throttling/)을 사용하여 특정 사용자가 하루에 한번만 호출 할 수 있도록 뷰를 만들려면 `@thottle_classes`데코레이터를 사용하여 `throttle` 클래스 목록을 전달하세요. 135 | 136 | ```python 137 | from rest_framework.decorators import api_view, throttle_classes 138 | from rest_framework.throttling import UserRateThrottle 139 | 140 | class OncePerDayUserThrottle(UserRateThrottle): 141 | rate = '1/day' 142 | 143 | @api_view(['GET']) 144 | @throttle_classes([OncePerDayUserThrottle]) 145 | def view(request): 146 | return Response({"message": "Hello for today! See you tomorrow!"}) 147 | ``` 148 | 이러한 데코레이터는 위에서 설명한 `APIView`하위 클래스에 설정된 특성에 해당합니다. 사용 가능한 데코레이터는 다음과 같습니다. 149 | 150 | - `@renderer_classes(...)` 151 | - `@parser_classes(...)` 152 | - `@authentication_classes(...)` 153 | - `@throttle_classes(...)` 154 | - `@permission_classes(...)` 155 | 156 | 이러한 데코레이터 각각은 클래스의 `list`나 `tuple`인 단일 인수를 취합니다. 157 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 04. Generic views.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Generic views 2 | 3 | --- 4 | 5 | _"Django’s generic views... were developed as a shortcut for common usage patterns... They take certain common idioms and patterns found in view development and abstract them so that you can quickly write common views of data without having to repeat yourself."_ 6 | _"Django의 generic views... 일반적인 사용 패턴을 위한 지름길로 개발되었습니다... 그들은 view 개발에서 발견되는 특정 공통 관용구와 패턴을 취해서 반복함으로써 반복하지 않고도 공통된 데이터 view를 빠르게 작성할 수 있습니다."_ 7 | _— Django Documentation_ 8 | 9 | --- 10 | 11 | ## Generic views 12 | CBV의 주요 이점 중 하나는 재사용이 가능한 동작을 구성하는 것입니다. REST 프레임워크는 일반적으로 사용되는 패턴을 제공하는 다수의 dict에 빌드 된 view를 제공함으로써 이를 활용합니다. 13 | REST 프레임워크에서 제공하는 generic view를 사용하면 데이터베이스 모델과 밀접하게 매핑되는 API 뷰를 빠르게 빌드 할 수 있습니다. 14 | `generic views` 가 API의 요구 사항에 맞지 않으면 정규 `APIView`클래스를 사용하여 drop down 하거나 `generic views`에서 사용하는 `mixin`과 기본 클래스를 재사용하여, 자신만 재사용이 가능한 `generic views` set를 작성할 수 있습니다. 15 | 16 | ### Examples 17 | 일반적으로 `generic views`를 사용하는 경우 view를 무시하고 여러 클래스 속성을 설정합니다. 18 | 19 | ```python 20 | from django.contrib.auth.models import User 21 | from myapp.serializers import UserSerializer 22 | from rest_framework import generics 23 | from rest_framework.permissions import IsAdminUser 24 | 25 | class UserList(generics.ListCreateAPIView): 26 | queryset = User.objects.all() 27 | serializer_class = UserSerializer 28 | permission_classes = (IsAdminUser,) 29 | ``` 30 | 보다 복잡한 경우에는 view 클래스의 다양한 메서드를 재정의 할 수도 있습니다. 예를 들면: 31 | 32 | ```python 33 | class UserList(generics.ListCreateAPIView): 34 | queryset = User.objects.all() 35 | serializer_class = UserSerializer 36 | permission_classes = (IsAdminUser,) 37 | 38 | def list(self, request): 39 | # Note the use of `get_queryset()` instead of `self.queryset` 40 | queryset = self.get_queryset() 41 | serializer = UserSerializer(queryset, many=True) 42 | return Response(serializer.data) 43 | ``` 44 | 매우 간단한 경우에는 `.as_view()`메서드를 사용하여 클래스 속성을 전달할 수 있습니다. 예를 들어, `URLconf`에 다음 항목이 포함 될 수 있습니다. 45 | 46 | ```python 47 | url(r'^/users/', ListCreateAPIView.as_view(queryset=User.objects.all(), serializer_class=UserSerializer), name='user-list') 48 | ``` 49 | 50 | --- 51 | 52 | ## API Reference 53 | 54 | ### GenericAPIView 55 | 이 클래스는 REST 프레임워크의 `APIView` 클래스를 확장하여 기존 list view와 detail views에 일반적으로 필요한 동작을 추가합니다. 56 | 제공된 각각의 `generic views`는 `GenericAPIView`를 하나 이상의 `minxin`클래스와 결합하여 빌드됩니다. 57 | 58 | #### Attributes 59 | ##### Basic settings: 60 | 다음 속성은 기본 뷰 동작을 제어합니다. 61 | 62 | - `queryset` : 이 뷰에서 객체를 반환하는 데 사용해야 하는 쿼리셋입니다. 일반적으로 이 속성을 설정하거나 `get_queryset()`메서드를 대체해야합니다. 뷰 메서드를 오버라이드하는 경우, 이 속성에 직접 액서스하는 대신 `get_queryset()`을 호출하는 것이 중요합니다. 쿼리셋은 한번 평가되고 그 결과는 모든 후속 request에 대해 캐시됩니다. 63 | - `serializer_class` : 입력의 검증과 serializer 복원 및 출력 serializer에 사용하는 `serializer` 클래스입니다. 일반적으로 이 속성을 설정하거나 `get_serializer_class()`메소드를 대체해야 합니다. 64 | - `lookup_field` : 개별 모델 인스턴스의 object 조회를 수행 할 때 사용해야하는 모델 필드입니다. 기본값은 `'pk'`입니다. 하이퍼링크 된 API에 custom 값을 사용해야 하는 경우 API views와 serializer 클래스가 `lookup`필드를 설정해야 합니다. 65 | - `lookup_url_kwarg` : 객체 검색에 사용해야하는 URL 키워드 인수입니다. `URL conf`에는 이 값에 해당하는 키워드 인수가 포함되어야 합니다. 설정을 해제하면 `lookup_field`와 동일한 값을 사용합니다. 66 | 67 | ##### Pagination: 68 | 다음 속성은 list views와 함께 사용될 때 `pagination`을 제어하는데 사용됩니다. 69 | 70 | - `pagination_class` : 결과 목록을 지정할 때 사용해야하는 `pagination`클래스입니다. 기본값은 `'rest_framework.pagination.PageNumberPagination'`인 `DEFAULT_PAGINATION_CLASS`설정과 동일한 값입니다. `pagination_class=None`으로 설정하면 이 view에서 pagination을 사용할 수 없습니다. 71 | 72 | ##### Filtering: 73 | 74 | - `filter_backends` : 쿼리셋을 필터링하는데 사용해야하는 `filter backend`클래스의 list입니다. 기본값은 `DEFAULT_FILTER_BACKENDS`설정과 동일합니다. 75 | 76 | #### Method 77 | ##### Base methods: 78 | 79 | ``` 80 | get_queryset(self) 81 | ``` 82 | **`list view`**에서 사용되는 쿼리셋을 돌려줍니다. `detail view` 안의 `lookup`의 베이스로 사용됩니다. `queryset`속성에 의해 지정된 쿼리셋을 리턴하는 것이 기본값입니다. 83 | 이 메서드는 `self.queryset`에 직접 액서스하는 대신 항상 사용되어야하며, `self.queryset`은 한번만 평가되고 그 결과는 모든 후속 요청에 캐시됩니다. 84 | request를 작성하는 사용자에게 특정되는 쿼리셋 반환과 같은 동적 동작을 제공하도록 재정의 될 수 있습니다. 85 | 86 | 예제: 87 | 88 | ```python 89 | def get_queryset(self): 90 | user = self.request.user 91 | return user.accounts.all() 92 | ``` 93 | 94 | ``` 95 | get_object(self) 96 | ``` 97 | **`detail views`**에 사용해야 하는 객체 인스턴스를 반환합니다. 기본적으로 `lookup_field` parameter를 사용하여 기본 쿼리셋을 필터링합니다. 98 | 둘 이상의 `URL kwarg`를 기반으로 하는 `object lookups`와 같이 복잡한 동작을 제공하기 위해 무시될 수 있습니다. 99 | 100 | 예를 들어: 101 | 102 | ```python 103 | def get_object(self): 104 | queryset = self.get_queryset() 105 | filter = {} 106 | for field in self.multiple_lookup_fields: 107 | filter[field] = self.kwargs[field] 108 | 109 | obj = get_object_or_404(queryset, **filter) 110 | self.check_object_permissions(self.request, obj) 111 | return obj 112 | ``` 113 | API에 객체 수준 권한이 없으면 선택적으로 `self.check_object_permissions`를 제외하고 단순히 `get_object_or_404` lookup에서 객체를 반환 할 수 있습니다. 114 | 115 | ``` 116 | filter_queryset(self, queryset) 117 | ``` 118 | **`serializer`**에 사용해야하는 클래스를 반환합니다. 기본값은 `serializer_class`속성을 반환하는 것입니다. 119 | 읽기와 쓰기 작업에 다른 serializer를 사용하거나 다른 유형의 사용자에게 다른 serializer를 제공하는 등의 동적 동작을 제공하기 위해 재정의 될 수 있습니다. 120 | 121 | 예: 122 | 123 | ```python 124 | def get_serializer_class(self): 125 | if self.request.user.is_staff: 126 | return FullAccountSerializer 127 | return BasicAccountSerializer 128 | ``` 129 | 130 | ##### Save and deletion hooks: 131 | 다음과 같은 메서드가 `mixin`클래스에서 제공되며 object 저장이나 삭제 동작을 쉽게 대체 할 수 있습니다. 132 | 133 | - `perform_create(self, serializer)` : 새 object 인스턴스를 저장할 때 `CreateModelMixin`에 의해 호출됩니다. 134 | - `perform_update(self, serializer)` : 기존 object 인스턴스를 저장할 때 `UpdateModelMixin`에 의해 호출됩니다. 135 | - `perform_destroy(self, instance)` : object 인스턴스를 삭제할 때 `DestroyModelMixin`에 의해 호출됩니다. 136 | 137 | 이러한 `hooks`는 request에 내포되어 있지만, 요청 데이터의 일부가 아닌 속성을 설정하는데 특히 유용합니다. 예를 들어, request 사용자를 기준으로 또는 URL 키워드 인수를 기반으로 object의 속성을 설정할 수 있습니다. 138 | 139 | ```python 140 | def perform_create(self, serializer): 141 | serializer.save(user=self.request.user) 142 | ``` 143 | 또한 이러한 오버라이드 포인트는 확인 이메일을 보내거나 업데이트를 로깅하는 것과 같이 object 저장 전후에 발생하는 동작을 추가 할 때 특히 유용합니다. 144 | > 로깅 : 시스템을 작동할 때 시스템의 작동 상태의 기록,보존,시스템동작 분석들을 기록하는 것 145 | 146 | ```python 147 | def perform_update(self, serializer): 148 | instance = serializer.save() 149 | send_email_confirmation(user=self.request.user, modified=instance) 150 | ``` 151 | `ValidationError()`를 발생시켜 추가 유효성 검사를 제공하기 위해 이러한 `hooks`을 사용할 수도 있습니다. 데이터베이스 저장 시점에 적용 할 유효성 검증 로직이 필요한 경우 유용 할 수 있습니다. 152 | 153 | ```python 154 | def perform_create(self, serializer): 155 | queryset = SignupRequest.objects.filter(user=self.request.user) 156 | if queryset.exists(): 157 | raise ValidationError('You have already signed up') 158 | serializer.save(user=self.request.user) 159 | ``` 160 | 161 | **Note**: 이 메서드는 이전 버전(2.x)의 `pre_save`, `post_save`, `pre_delete`와 `post_delete`메서드를 대체하며 더 이상 사용할 수 없습니다. 162 | 163 | ##### Other methods: 164 | `GenericAPIView`를 사용하여 custom views를 작성하는 경우, 호출할 수도 있지만 일반적으로 다음의 메서드를 대체하야 할 필요는 없습니다. 165 | 166 | - `get_serializer_context(self)` : serializer에 제공되어야 하는 추가 컨텐스트가 포함된 dict를 반환합니다. 기본값엔 `request`, `view`, `format` 키가 포합됩니다. 167 | - `get_serializer(self, instance=None, data=None, many=False, partial=False)` : serializer 인스턴스를 반환합니다. 168 | - `get_paginated_response(self, data)` : pagination 스타일의 response object를 반환합니다. 169 | - `paginate_queryset(self, queryset)` : 필요하면, `paginate_queryset`에 page object를 반환하거나, 이 view에 pagination이 구성되지 않은 경우 None을 반환합니다. 170 | - `filter_queryset(self, queryset)` : 주어진 쿼리셋을 사용중인 필터 백엔드를 사용하여 새로운 쿼리셋을 반환합니다. 171 | 172 | --- 173 | 174 | ## Mixins 175 | `mixin`클래스는 기본 view 동작을 제공하는데 사용되는 작업을 제공합니다. `mixin`클래스는 `.get()`와 `.post()`와 같은 핸들러 메서드를 직접 정의하는 것이 아니라 작업 메서드를 제공합니다. 이것은 보다 유연한 작동 구성을 가능하게 합니다. 176 | `mixin`클래스는 `rest_framework.mixins`에서 가져 올 수 있습니다. 177 | 178 | ### ListModelMixin 179 | 쿼리셋 list를 구현하는 `.list(request, *args, **kwargs)`메서드를 제공합니다. 180 | 쿼리셋이 채워지면 response의 본문으로 쿼리셋의 serializer 된 표현과 함께 `200 OK`응답을 반환합니다. response 데이터는 선택적으로 페이징 될 수 있습니다. 181 | 182 | ### CreateModelMixin 183 | 새 모델 인스턴스 만들기 및 저장을 구현하는 `.create(request, *args, **kwargs)`메서드를 제공합니다. 184 | 객체가 생성되면 객체의 serializer 된 표현을 response의 본문으로 사용하여 `201 Created`응답을 반환합니다. 표현에 `url`이라는 키가 포함되어 있으면 response의 `Location` 헤더가 해당 값으로 채워집니다. 185 | 객체 생성을 위해 제공된 request 데이터가 유효하지 않은 경우 `400 Bad Request`응답이 반환되며, 오류 내역은 response 본문으로 반환됩니다. 186 | 187 | ### RetrieveModelMixin 188 | response에서 기존 모델 인스턴스를 반환하도록 구현하는 `.retrieve(request, *args, **kwargs)`메서드를 반환합니다. 189 | 객체를 검색 할 수 있는 경우 `200 OK`응답을 반환하며, 객체를 response 본문으로 serializer하여 반환합니다. 190 | 191 | ### UpdateModelMixin 192 | 기존 모델 인스턴스를 업데이트하고 저장하는 `.update(request, *args, **kwargs)`메서드를 제공합니다. 193 | 또한 `update`메소드와 유사한 `.partial_update(request, *args, **kwargs)`메소드도 제공합니다. 단, 업데이트의 모든 필드는 선택사항입니다. 이렇게 하면 HTTP`PATCH`request를 지원할 수 있습니다. 194 | 객체가 업데이트되면 객체의 serializer 된 표현이 응답 본문과 함께 `200 OK`응답을 반환합니다. 195 | 객체를 업데이트하기 위해 제공된 request 데이터가 유효하지 않은 경우 `400 Bad Request`응답이 반환되고 오류 세부 정보가 response 본문으로 사용됩니다. 196 | 197 | ### DestroyModelMixin 198 | 기존 모델 인스턴스의 삭제를 구현하는 `.destroy(request, *args, **kwargs)`메서드를 제공합니다. 199 | 객체가 삭제되면 `204 No Content`응답을 반환하고, 그렇지 않으면 `404 Not Found`을 반환합니다. 200 | 201 | --- 202 | 203 | ## Concrete View Classes 204 | 다음의 클래스는 구체적인 `generic views`입니다. `generic views`를 사용하는 경우 일반적을 커스터마이징 된 동작이 필요하지 않으면 할만한 수준입니다. 205 | 뷰 클래스는 `rest_framework.generics`에서 가져올 수 있습니다. 206 | 207 | ### CreateAPIView 208 | **읽기 전용** 엔드포인트에 사용됩니다. 209 | `post` 메서드 핸들러를 제공합니다. 210 | Extends: [GenericAPIView](http://www.django-rest-framework.org/api-guide/generic-views/#genericapiview), [CreateModelMixin](http://www.django-rest-framework.org/api-guide/generic-views/#createmodelmixin) 211 | 212 | ### ListAPIView 213 | **읽기 전용** 엔드포인트가 **모델 인스턴스의 콜렉션**을 나타내는데 사용됩니다. 214 | `get` 메서드 핸들러를 제공합니다. 215 | Extends: [GenericAPIView](http://www.django-rest-framework.org/api-guide/generic-views/#genericapiview), [ListModelMixin](http://www.django-rest-framework.org/api-guide/generic-views/#listmodelmixin) 216 | 217 | ### RetrieveAPIView 218 | **읽기 전용** 엔드포인트가 **단일 모델 인스턴스**를 나타내는데 사용됩니다. 219 | `get`메서드 핸들러를 제공합니다. 220 | Extends: [GenericAPIView](http://www.django-rest-framework.org/api-guide/generic-views/#genericapiview), [RetrieveModelMixin](http://www.django-rest-framework.org/api-guide/generic-views/#retrievemodelmixin) 221 | 222 | ### DestroyAPIView 223 | **삭제 전용** 엔드포인트가 **단일 모델 인스턴스**를 나타내는데 사용됩니다. 224 | `delete`메서드 핸들러를 제공합니다. 225 | Extends: [GenericAPIView](http://www.django-rest-framework.org/api-guide/generic-views/#genericapiview), [DestroyModelMixin](http://www.django-rest-framework.org/api-guide/generic-views/#destroymodelmixin) 226 | 227 | ### UpdateAPIView 228 | **업데이트 전용** 엔드포인트가 **단일 모델 인스턴스**를 나타내는데 사용됩니다. 229 | `put`과 `patch`메서드 핸들러를 제공합니다. 230 | Extends: [GenericAPIView](http://www.django-rest-framework.org/api-guide/generic-views/#genericapiview), [UpdateModelMixin](http://www.django-rest-framework.org/api-guide/generic-views/#updatemodelmixin) 231 | 232 | ### ListCreateAPIView 233 | **읽기-쓰기** 엔드포인트가 **모델 인스턴스의 컬렉션**를 나타내는데 사용됩니다. 234 | `get`과 `post` 메서드 핸들러를 제공합니다. 235 | Extends: [GenericAPIView](http://www.django-rest-framework.org/api-guide/generic-views/#genericapiview), [ListModelMixin](http://www.django-rest-framework.org/api-guide/generic-views/#listmodelmixin), [CreateModelMixin](http://www.django-rest-framework.org/api-guide/generic-views/#createmodelmixin) 236 | 237 | ### RetrieveUpdateAPIView 238 | **읽거나 업데이트** 엔드포인트가 **단일 모델 인스턴스**를 나타내는데 사용됩니다. 239 | `get`, `put`, `patch` 메서드 핸들러를 제공합니다. 240 | Extends: [GenericAPIView](http://www.django-rest-framework.org/api-guide/generic-views/#genericapiview), [RetrieveModelMixin](http://www.django-rest-framework.org/api-guide/generic-views/#retrievemodelmixin), [UpdateModelMixin](http://www.django-rest-framework.org/api-guide/generic-views/#updatemodelmixin) 241 | 242 | ### RetrieveDestroyAPIView 243 | **읽거나 삭제** 엔드포인트가 **단일 모델 인스턴스**를 나타내는데 사용됩니다. 244 | `get`과 `delete`메서드 핸들러를 제공합니다. 245 | Extends: [GenericAPIView](http://www.django-rest-framework.org/api-guide/generic-views/#genericapiview), [RetrieveModelMixin](http://www.django-rest-framework.org/api-guide/generic-views/#retrievemodelmixin), [DestroyModelMixin](http://www.django-rest-framework.org/api-guide/generic-views/#destroymodelmixin) 246 | 247 | ### RetrieveUpdateDestroyAPIView 248 | **읽기-쓰기-삭제** 엔드포인트가 **단일 모델 인스턴스**를 나타내는데 사용됩니다. 249 | `get`, `put`, `patch`, `delete`메서드 핸들러를 제공합니다. 250 | Extends: [GenericAPIView](http://www.django-rest-framework.org/api-guide/generic-views/#genericapiview), [RetrieveModelMixin](http://www.django-rest-framework.org/api-guide/generic-views/#retrievemodelmixin), [UpdateModelMixin](http://www.django-rest-framework.org/api-guide/generic-views/#updatemodelmixin), [DestroyModelMixin](http://www.django-rest-framework.org/api-guide/generic-views/#destroymodelmixin) 251 | 252 | --- 253 | 254 | ## Customizing the generic views 255 | 종종 기본 generic views를 사용하고 약간 custom 된 동작을 사용하려고 합니다. 여러 위치에서 custom 된 동작을 재사용하는 경우, 동작을 공통 클래스로 리팩토링하여 필요할 때 모든 view나 viewset에 적용할 수 있습니다. 256 | 257 | ### Creating custom mixins 258 | 예를 들어, URL conf 내의 복수의 필드에 근거해 오브젝트를 검색 할 필요가 있는 경우, 다음과 같이 `mixin` 클래스를 작성할 수 있습니다. 259 | 260 | ```python 261 | class MultipleFieldLookupMixin(object): 262 | """ 263 | Apply this mixin to any view or viewset to get multiple field filtering 264 | based on a `lookup_fields` attribute, instead of the default single field filtering. 265 | """ 266 | def get_object(self): 267 | queryset = self.get_queryset() # 기본 쿼리셋 가져오기 268 | queryset = self.filter_queryset(queryset) # backends에서 필터 적용 269 | filter = {} 270 | for field in self.lookup_fields: 271 | if self.kwargs[field]: # 빈 필드는 무시 272 | filter[field] = self.kwargs[field] 273 | return get_object_or_404(queryset, **filter) # 객체를 찾는다 274 | ``` 275 | 그런 다음 custom 동작을 적용해야 할때 mixin을 view나 viewset에 간단하게 적용할 수 있습니다. 276 | 277 | ```python 278 | class RetrieveUserView(MultipleFieldLookupMixin, generics.RetrieveAPIView): 279 | queryset = User.objects.all() 280 | serializer_class = UserSerializer 281 | lookup_fields = ('account', 'username') 282 | ``` 283 | 사용해야 하는 custom 동작이 있는 경우, custom mixin을 사용하는 것이 좋습니다. 284 | 285 | ### Creating custom base classes 286 | 여러 views에서 mixin을 사용하는 경우, 이 단계를 더 진행하고 프로젝트 전체에서 사용할 수 있는 고유한 기본 views set을 만들 수 있습니다. 예를 들어: 287 | 288 | ```python 289 | class BaseRetrieveView(MultipleFieldLookupMixin, 290 | generics.RetrieveAPIView): 291 | pass 292 | 293 | class BaseRetrieveUpdateDestroyView(MultipleFieldLookupMixin, 294 | generics.RetrieveUpdateDestroyAPIView): 295 | pass 296 | ``` 297 | 프로젝트 전반에 걸쳐 많은 수의 views에서 일관되게 반복해야 하는 custom 동작이 있는 경우, custom 기본 클래스를 사용하는 것이 좋습니다. 298 | 299 | --- 300 | 301 | ## PUT as create 302 | 버전 3.0 이전에는 객체가 이미 존재하는지 여부에 따라 REST 프레임워크 mixins가 `PUT`을 업데이트나 작성 작업으로 처리했습니다. 303 | 생성 작업으로 `PUT`을 허용하는 것은 객체의 존재나 부재에 대한 정보를 반드시 노출시키기 때문에 문제가 됩니다. 또한 이전에 삭제 된 인스턴스를 투명하게 다시 만들수 있다는 것이 단순히 `404`응답을 반환하는 것보다 더 나은 기본 동작이라고 할 수만은 없습니다. 304 | "`PUT` as 404"와 "`PUT` as create"는 서로 다른 상황에서 유효 할 수 있지만, 버전 3.0부터는 더 간단하고 명확한 404 동작을 기본값으로 사용합니다. 305 | 일반적인 `PUT-as-create`동작이 필요한 경우 `AllowPUTAsCreateMixin`클래스를 views에 mixin으로 포함할 수 있습니다. 306 | 307 | --- 308 | 309 | ## Third party packages 310 | 다음의 타사 패키지는 추가 generic view 구현을 제공합니다. 311 | 312 | ### Django REST Framework bulk 313 | [django-rest-framework-bulk](https://github.com/miki725/django-rest-framework-bulk)패키지는 API request을 통해 대량 작업을 적용할 수 있도록 generic views mixin 뿐만 아니라 일반적인 구체적 generic views를 구현합니다. 314 | 315 | ### Django Rest Multiple Models 316 | [Django Rest Multiple Models](https://github.com/Axiologue/DjangoRestMultipleModels)은 단일 API request을 통해 여러 serializer된 모델 및 `/` 또는 쿼리셋을 전송하기 위한 generic views(and mixin)을 제공합니다. 317 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 05. ViewSets.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - ViewSets 2 | 3 | --- 4 | 5 | _"After routing has determined which controller to use for a request, your controller is responsible for making sense of the request and producing the appropriate output."_ 6 | 7 | _"라우팅에서 request에 사용할 컨트롤러를 결정한 후에 컨트롤러는 request를 이해하고 적절한 출력을 생성해야합니다."_ 8 | 9 | _— Ruby on Rails Documentation_ 10 | 11 | --- 12 | 13 | ## ViewSets 14 | Django REST 프레임워크를 사용하면 `ViewSet`이라고하는 단일 클래스에서 `ViewSet`에 대한 논리를 결합할 수 있습니다. 다른 프레임워크에서는 `Resources`나 `Controllers`와 같은 개념적으로 유사한 구현을 찾을 수도 있습니다. 15 | `ViewSet` 클래스는 단순히 `.get()`이나 `.post()`과 같은 메소드 핸들러를 제공하지 않고 CBV 유형이며, 대신 `.list()`와 `.create()`와 같은 액션을 제공합니다. 16 | `ViewSet`의 메서드 핸들러는 `.as_view()`메서드를 사용하여 뷰를 마무리하는 시점의 해당 액션에만 바인딩됩니다. 17 | >바인딩 : 각종 값들이 확정되어 더이상 변경 할 수 없는 상태가 되는것. 식별자(identifier)가 그 대상인 메모리 주소, 데이터형 또는 실제값으로 배정되는 것 18 | 19 | 일반적으로 urlconf의 viewset에 뷰를 명시적을 등록하는 대신 viewset을 `router`클래스로 등록하면 자동으로 urlconf가 결정됩니다. 20 | 21 | ### Example 22 | 시스템의 모든 사용자를 나열하거나 검색하는데 사용 할 수 있는 간단한 viewset을 정의합시다. 23 | 24 | ```python 25 | from django.contrib.auth.models import User 26 | from django.shortcuts import get_object_or_404 27 | from myapps.serializers import UserSerializer 28 | from rest_framework import viewsets 29 | from rest_framework.response import Response 30 | 31 | class UserViewSet(viewsets.ViewSet): 32 | """ 33 | A simple ViewSet for listing or retrieving users. 34 | """ 35 | def list(self, request): 36 | queryset = User.objects.all() 37 | serializer = UserSerializer(queryset, many=True) 38 | return Response(serializer.data) 39 | 40 | def retrieve(self, request, pk=None): 41 | queryset = User.objects.all() 42 | user = get_object_or_404(queryset, pk=pk) 43 | serializer = UserSerializer(user) 44 | return Response(serializer.data) 45 | ``` 46 | 필요한 경우 이 viewset을 다음과 같이 두 개의 개별 뷰 바인딩 할 수 있습니다. 47 | 48 | ```python 49 | user_list = UserViewSet.as_view({'get': 'list'}) 50 | user_detail = UserViewSet.as_view({'get': 'retrieve'}) 51 | ``` 52 | 평소엔 우리는 이것을 하지 않을 것이지만, 대신 viewset을 라우터에 등록하고 urlconf가 자동으로 생성되도록 할 것입니다. 53 | 54 | ```python 55 | from myapp.views import UserViewSet 56 | from rest_framework.routers import DefaultRouter 57 | 58 | router = DefaultRouter() 59 | router.register(r'users', UserViewSet) 60 | urlpatterns = router.urls 61 | ``` 62 | 자신만의 viewset를 작성하는 대신, 기본 동작 set을 제공하는 기존 기본 클래스를 사용하는 것이 좋습니다. 예를 들어: 63 | 64 | ```python 65 | class UserViewSet(viewsets.ModelViewSet): 66 | """ 67 | A viewset for viewing and editing user instances. 68 | """ 69 | serializer_class = UserSerializer 70 | queryset = User.objects.all() 71 | ``` 72 | `View` 클래스를 사용하는 것보다 `ViewSet`클래스를 사용하는 두 가지 주요 이점이 있습니다. 73 | 74 | - 반복 논리를 하나의 클래스로 결합 할 수 있습니다. 위의 예에서 쿼리셋은 한번만 지정하면 여러 view에서 사용됩니다. 75 | - router를 사용함으로써 우리는 더 이상 URLconf의 연결을 처리 할 필요가 없습니다. 76 | 77 | 이 두가지 모두 장단점이 있습니다. 일반 views와 URL conf를 사용하면 보다 명확하게 제어할 수 있습니다. `ViewSet`는 신속하게 시작하고 실행하려는 경우, 또는 대규모 API가 있고 전체적으로 일관된 URL conf를 적용하려는 경우 유용합니다. 78 | 79 | ### Marking extra actions for routing 80 | REST 프레임워크에 포함 된 기본 router는 아래와 같이 `creste`/`retirieve`/`update`/`destroy` 스타일 작업의 기본 set을 위한 경로를 제공합니다. 81 | 82 | ```python 83 | class UserViewSet(viewsets.ViewSet): 84 | """ 85 | Example empty viewset demonstrating the standard 86 | actions that will be handled by a router class. 87 | 88 | If you're using format suffixes, make sure to also include 89 | the `format=None` keyword argument for each action. 90 | """ 91 | 92 | def list(self, request): 93 | pass 94 | 95 | def create(self, request): 96 | pass 97 | 98 | def retrieve(self, request, pk=None): 99 | pass 100 | 101 | def update(self, request, pk=None): 102 | pass 103 | 104 | def partial_update(self, request, pk=None): 105 | pass 106 | 107 | def destroy(self, request, pk=None): 108 | pass 109 | ``` 110 | 라우팅해야 하는 임시 메소드가 있는 경우 `@detail_router`나 `@list_router`데코레이터를 사용하여 라우팅을 요구하는 것으로 표시 할 수 있습니다. 111 | `@detail_router`데코레이터는 URL 패턴에 `pk`를 포함하며 단일 인스턴스가 필요한 메소드용입니다. `@list_router`데코레이터는 객체 목록에서 작동하는 메소드를 대상으로 합니다. 112 | 113 | 예를 들어: 114 | 115 | ```python 116 | from django.contrib.auth.models import User 117 | from rest_framework import status 118 | from rest_framework import viewsets 119 | from rest_framework.decorators import detail_route, list_route 120 | from rest_framework.response import Response 121 | from myapp.serializers import UserSerializer, PasswordSerializer 122 | 123 | class UserViewSet(viewsets.ModelViewSet): 124 | """ 125 | A viewset that provides the standard actions 126 | """ 127 | queryset = User.objects.all() 128 | serializer_class = UserSerializer 129 | 130 | @detail_route(methods=['post']) 131 | def set_password(self, request, pk=None): 132 | user = self.get_object() 133 | serializer = PasswordSerializer(data=request.data) 134 | if serializer.is_valid(): 135 | user.set_password(serializer.data['password']) 136 | user.save() 137 | return Response({'status': 'password set'}) 138 | else: 139 | return Response(serializer.errors, 140 | status=status.HTTP_400_BAD_REQUEST) 141 | 142 | @list_route() 143 | def recent_users(self, request): 144 | recent_users = User.objects.all().order('-last_login') 145 | 146 | page = self.paginate_queryset(recent_users) 147 | if page is not None: 148 | serializer = self.get_serializer(page, many=True) 149 | return self.get_paginated_response(serializer.data) 150 | 151 | serializer = self.get_serializer(recent_users, many=True) 152 | return Response(serializer.data) 153 | ``` 154 | 데코레이터는 라우트 된 뷰에 대해서만 설정 할 추가 인수를 추가로 취할 수 있습니다. 예를 들어.. 155 | 156 | ```python 157 | @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf]) 158 | def set_password(self, request, pk=None): 159 | ... 160 | ``` 161 | 이러한 데코레이터는 기본적으로 `GET` request를 라우트하지만 `methods`인수를 사용하여 다른 HTTP 메소드를 채택할 수도 있습니다. 예: 162 | 163 | ```python 164 | @detail_route(methods=['post', 'delete']) 165 | def unset_password(self, request, pk=None): 166 | ... 167 | ``` 168 | 두 개의 작업은 `^users/{pk}/set_password/$` 과 `^users/{pk}/unset_password/$`에서 사용 할 수 있습니다. 169 | 170 | --- 171 | 172 | ## API Reference 173 | 174 | ### ViewSet 175 | `ViewSet`클래스는 `APIView`에서 상속받습니다. viewset에 대한 API 정책을 제어하기 위해 `permission_classes`,`authentication_classes`와 같은 표준 속성을 사용할 수 있습니다. 176 | `ViewSet` 클래스는 액션의 구현을 제공하지 않습니다. `ViewSet` 클래스를 사용하려면 클래스를 오버라이트하고 액션 구현을 명시적으로 정의해야합니다. 177 | 178 | ### GenericViewSet 179 | `GenericViewSet`클래스는 `GenericAPIView`에서 상속되며, `get_object`, `get_queryset`메소드와 그 외 `generic view`의 기본 동작의 기본 set을 제공하지만, 기본적으로 어떤 액션도 포함하지 않습니다. 180 | `GenericViewSet`클래스를 사용하려면 클래스를 재정의하고 필요한 `mixin`클래스를 혼합하거나 액션 구현을 명시적으로 정의하세요. 181 | 182 | ### ModelViewSet 183 | `ModelViewSet`클래스는 `GenericAPIView`를 상속하며, 다양한 `mixin`클래스의 동작을 혼합하여 다양한 액션에 대한 구현을 포함합니다. 184 | `ModelViewSet`클래스에서 제공하는 작업은 `.list()`, `.retrieve()`, `.create()`, `.update()`, `.partial_update()`, `.destroy()`입니다. 185 | 186 | #### Example 187 | `ModelViewSet`은 `GenericAPIView`를 확장하기 때문에 일반적으로 적어도 `queryset`과 `serializer_class` 속성을 제공해야 합니다. 예: 188 | 189 | ```python 190 | class AccountViewSet(viewsets.ModelViewSet): 191 | """ 192 | A simple ViewSet for viewing and editing accounts. 193 | """ 194 | queryset = Account.objects.all() 195 | serializer_class = AccountSerializer 196 | permission_classes = [IsAccountAdminOrReadOnly] 197 | ``` 198 | `GenericAPIView`가 제공하는 표준 속성이나 메소드 오버라이드를 사용할 수 있습니다. 예를 들어, 작동해야하는 쿼리셋을 동적으로 결정하는 viewset을 사용하려면 다음과 같이 할 수 있습니다. 199 | 200 | ```python 201 | class AccountViewSet(viewsets.ModelViewSet): 202 | """ 203 | A simple ViewSet for viewing and editing the accounts 204 | associated with the user. 205 | """ 206 | serializer_class = AccountSerializer 207 | permission_classes = [IsAccountAdminOrReadOnly] 208 | 209 | def get_queryset(self): 210 | return self.request.user.accounts.all() 211 | ``` 212 | 그러나 `ViewSet`에서 `queryset` 속성을 제거하면 연관된 [라우터](http://www.django-rest-framework.org/api-guide/routers/)가 모델의 `base_name`을 자동으로 파생시킬 수 없으므로 [라우터 등록](http://www.django-rest-framework.org/api-guide/routers/)의 일부로 `base_name kwarg`를 지정해야합니다. 213 | 또한 이 클래스는 기본적으로 `create`/`list`/`retrieve`/`update`/`destroy` 액션의 전체 set을 제공하지만 표준 권한 클래스를 사용하여 사용 가능한 작업을 제한할 수 있습니다. 214 | 215 | ### ReadOnlyModelViewSet 216 | `ReadOnlyModelViewSet`클래스 또한 `GenericAPIView`에서 상속받습니다. `ModelViewSet`과 마찬가지로 다양한 액션에 대한 구현도 포함되지만 `ModelViewSet`과 달리 **일기 전용**동작인 `.list()`, `.retrieve()`만 제공됩니다. 217 | 218 | #### Example 219 | `ModelViewSet`에서와 같이 일반적으로 적어도 `queryset`과 `serializer_class`속성을 제공해야 합니다. 예: 220 | 221 | ```python 222 | class AccountViewSet(viewsets.ReadOnlyModelViewSet): 223 | """ 224 | A simple ViewSet for viewing accounts. 225 | """ 226 | queryset = Account.objects.all() 227 | serializer_class = AccountSerializer 228 | ``` 229 | `ModelViewSet`과 마찬가지로 `GenericAPIView`에서 사용할 수 있는 표준 속성과 메소드 오버라이드를 사용할 수 있습니다. 230 | 231 | ## Custom ViewSet base classes 232 | `ModelViewSet` 액션의 전체 set이 없거나 다른 방식으로 동작을 사용자 정의하는 custom `ViewSet`클래스를 제공해야 할 수도 있습니다. 233 | 234 | ### Example 235 | `create`, `list`, `retrieve` 조작을 제공하고, `GenericViewSet`에서 상속하며, 필요한 조치를 `mixin`하는 기본 viewset를 작성하려면 다음을 작성하세요. 236 | 237 | ```python 238 | class CreateListRetrieveViewSet(mixins.CreateModelMixin, 239 | mixins.ListModelMixin, 240 | mixins.RetrieveModelMixin, 241 | viewsets.GenericViewSet): 242 | """ 243 | `retrieve`, `create`, `list` actions을 제공하는 viewset입니다. 244 | 245 | 이것들을 사용하려면 클래스와 `.queryset`과 246 | `.serializer_class`의 속성을 오버라이드하세요. 247 | """ 248 | pass 249 | ``` 250 | 고유한 기본 `ViewSet`클래스를 작성하여 API 전반에 걸쳐 여러 viewset에서 재사용 할 수 있는 공통적인 동작을 제공할 수 있습니다. 251 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 06. Routers.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Routers 2 | 3 | --- 4 | 5 | _"Resource routing allows you to quickly declare all of the common routes for a given resourceful controller. Instead of declaring separate routes for your index... a resourceful route declares them in a single line of code."_ 6 | 7 | _"리소스 라우팅을 사용하면 주어진 리소스가 많은 컨트롤러에 대한 모든 일반 경로를 빠르게 선언 할 수 있습니다. 인덱스에 대해 별도의 경로를 선언하는 대신... 유용한 루트는 코드 한 줄로 선언합니다."_ 8 | 9 | _— Ruby on Rails Documentation_ 10 | 11 | --- 12 | 13 | ## Routers 14 | `Rails`와 같은 일부 웹 프레임워크는 응용 프로그램의 URL을 들어오는 요청을 처리하는 논리에 매핑하는 방법을 자동으로 결정하는 기능을 제공합니다. 15 | REST 프레임워크는 Django에 대한 자동 URL라우팅을 지원을 추가하고 뷰 로직을 URL set에 간단하고 빠르게 연관되게 연결하는 방법을 제공합니다. 16 | 17 | ### Usage 18 | 다음은 `SimpleRouter`를 사용하는 간단한 URL 구성의 예입니다. 19 | 20 | ```python 21 | from rest_framework import routers 22 | 23 | router = routers.SimpleRouter() 24 | router.register(r'users', UserViewSet) 25 | router.register(r'accounts', AccountViewSet) 26 | urlpatterns = router.urls 27 | ``` 28 | `register()`메서드는 두 가지 필수 인수가 있습니다. 29 | 30 | - `prefix` : router의 set에 사용할 URL접두어 입니다. 31 | - `viewset` : `viewset`클래스입니다. 32 | 33 | 선택적으로 추가 인수를 지정할 수도 있습니다. 34 | 35 | - `Base_name` : 작성된 URL 이름에 사용합니다. 설정되지 않은 경우 기본이름은 viewset의 쿼리셋 속성을 기반으로 자동 생성됩니다. viewset에 쿼리셋 특성이 포함되어 있지 않으면 viewset을 등록할 때 `base_name`을 설정해야 합니다. 36 | 37 | 위의 예는 다음 URL패턴을 생성합니다. 38 | 39 | - URL pattern: `^users/$` Name: `'user-list'` 40 | - URL pattern: `^users/{pk}/$` Name: `'user-detail'` 41 | - URL pattern: `^accounts/$` Name: `'account-list'` 42 | - URL pattern: `^accounts/{pk}/$` Name: `'account-detail'` 43 | 44 | --- 45 | **Note**: `base_name`인수는 뷰 이름 패턴의 초기 부분을 지정하는데 사용됩니다. 위의 예에서는 사용자나 계정 부분입니다. 46 | 일반적으로 `base_name`인수를 지정할 필요는 없지만, custom `get_queryset`메서드를 정의한 viewset이 있는 경우, viewset에는 `.queryset` 속성 set이 없을 수 있습니다. 해당 viewset을 등록하려고하면 다음과 같은 오류가 표시됩니다. 47 | 48 | ``` 49 | 'base_name' argument not specified, and could not automatically determine the name from the viewset, as it does not have a '.queryset' attribute. 50 | ``` 51 | 즉, 모델 이름에서 자동으로 결정할 수 없으므로 viewset을 등록할 때 `base_name`인수를 명시적으로 설정해야 합니다. 52 | 53 | --- 54 | 55 | #### Using include with routers 56 | 라우터 인스턴스의 `.urls`속성은 URL 패턴의 표준 list일 뿐입니다. 이러한 URL을 포함할 수 있는 방법에는 여러 스타일이 있습니다. 57 | 예를 들어 `router.urls`를 views 목록에 추가할 수 있습니다. 58 | 59 | ```python 60 | router = routers.SimpleRouter() 61 | router.register(r'users', UserViewSet) 62 | router.register(r'accounts', AccountViewSet) 63 | 64 | urlpatterns = [ 65 | url(r'^forgot-password/$', ForgotPasswordFormView.as_view()), 66 | ] 67 | 68 | urlpatterns += router.urls 69 | ``` 70 | 또는 Django의 `include` 함수를 사용할 수 있습니다. 71 | 72 | ```python 73 | urlpatterns = [ 74 | url(r'^forgot-password/$', ForgotPasswordFormView.as_view()), 75 | url(r'^', include(router.urls)), 76 | ] 77 | ``` 78 | 라우터 URL 패턴도 네임스페이스가 될 수 있습니다. 79 | 80 | ```python 81 | urlpatterns = [ 82 | url(r'^forgot-password/$', ForgotPasswordFormView.as_view()), 83 | url(r'^api/', include(router.urls, namespace='api')), 84 | ] 85 | ``` 86 | 하이퍼링크가 있는 serializer와 함께 네임 스페이스를 사용하는 경우 serializer의 `view_name` parameter가 네임 스페이스를 올바르게 반영하는지 확인해야 합니다. 위의 예제에서 사용자 detail view에 하이퍼링크 된 serializer 필드에 대해 `view_name='api:user-detail'`과 같은 parameter를 포함해야합니다. 87 | 88 | #### Extra link and actions 89 | `@detail_route`나 `@list_route`로 장식 된 viewset의 모든 메서드도 라우트됩니다. 예를 들어, `UserViewSet`클래스에서 다음과 같은 메서드가 제공됩니다. 90 | 91 | ```python 92 | from myapp.permissions import IsAdminOrIsSelf 93 | from rest_framework.decorators import detail_route 94 | 95 | class UserViewSet(ModelViewSet): 96 | ... 97 | 98 | @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf]) 99 | def set_password(self, request, pk=None): 100 | ... 101 | ``` 102 | 다음 URL패턴이 추가로 생성됩니다. 103 | 104 | - URL pattern: `^users/{pk}/set_password/$` Name: `'user-set-password'` 105 | 106 | custom 작업에 대해 생성 된 기본 URL을 사용하지 않으려면 대신 `url_path` parameter를 사용하여 custom 할 수 있습니다. 107 | 예를 들어 custom 액션의 URL을 `^users/{pk}/change-password/$`으로 변경하려면 다음과 같이 작성하세요. 108 | 109 | ```python 110 | from myapp.permissions import IsAdminOrIsSelf 111 | from rest_framework.decorators import detail_route 112 | 113 | class UserViewSet(ModelViewSet): 114 | ... 115 | 116 | @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf], url_path='change-password') 117 | def set_password(self, request, pk=None): 118 | ... 119 | ``` 120 | 위의 예제는 이제 다음 URL패턴을 생성합니다. 121 | 122 | - URL pattern: `^users/{pk}/change-password/$` Name: `'user-change-password'` 123 | 124 | custom 액션에 대해 생성된 기본 이름을 사용하지 않으려는 경우 `url_name`parameter를 사용하여 custom 할 수 있습니다. 125 | 예를 들어, custo,액션의 이름을 `'user-change-password'`로 변경하려면 다음과 같이 작성할 수 있습니다. 126 | 127 | ```python 128 | from myapp.permissions import IsAdminOrIsSelf 129 | from rest_framework.decorators import detail_route 130 | 131 | class UserViewSet(ModelViewSet): 132 | ... 133 | 134 | @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf], url_name='change-password') 135 | def set_password(self, request, pk=None): 136 | ... 137 | ``` 138 | 위의 예제는 이제 다음 URL패턴을 생성합니다. 139 | 140 | - URL pattern: `^users/{pk}/set_password/$` Name: `'user-change-password'` 141 | 142 | 또한 `url_path`와 `url_name` parameter를 함께 사용하여 custom view에 대한 URL생성을 제어할 수 있습니다. 143 | 더 자세한 내용은 [marking extra actions for routing](http://www.django-rest-framework.org/api-guide/viewsets/#marking-extra-actions-for-routing)참조하세요. 144 | 145 | ## API Guide 146 | ### SimpleRouter 147 | 이 라우터에는 `list`, `create`, `retrieve`, `update`, `partial_update`, `destroy` 표준 set 작업에 대한 경로가 포함됩니다. viewset은 `@detail_route`나 `@list_route`데코레이터를 사용하여 라우트 될 추가 메서드를 표시 할 수고 있습니다. 148 | ![](./images/SimpleRouter.png) 149 | 기본적으로 `SimpleRouter`로 만든 URL 뒤에는 슬래시가 추가됩니다. 이 동작은 라우터를 인스턴스화 할때 `trailing_slash` 인수를 `False`로 설정하여 수정할 수 있습니다. 예: 150 | 151 | ``` 152 | router = SimpleRouter(trailing_slash=False) 153 | ``` 154 | 뒤에 오는 슬래시는 Django에서는 일반적이지만 레일스와 같은 다른 프레임워크에서는 기본적으로 사용되지 않습니다. 어떤 자바스크립트 프레임워크가 특정 라우팅 스타일을 기대할지라도, 어떤 스타일을 선탣 하느냐는 대부분 환경 설정의 문제입니다. 155 | 라우터는 슬래시와 마침표를 제외한 문자가 포함 된 조회값을 매치시킵니다. 보다 제한적인(혹은 관대한) 검색 패턴의 경우, viewset에 `lookup_value_regex`속성을 설정하세요. 예를 들어, 조회를 유효한 `UUID`로 제한할 수 있습니다. 156 | 157 | ```python 158 | class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): 159 | lookup_field = 'my_model_id' 160 | lookup_value_regex = '[0-9a-f]{32}' 161 | ``` 162 | 163 | ### DefaultRouter 164 | 이 라우터는 위와 같이 `SimpleRouter`와 비슷하지만 모든 list views에 대한 하이퍼링크가 포함 된 response을 반환하는 기본 API root view를 추가로 포함합니다. 선택적 `.json` 스타일 형식 접미사에 대한 경로도 생성합니다. 165 | ![](./images/DefaultRouter.png) 166 | `SimpleRouter`과 마찬가지로 라우터를 인스턴스화 할때 `trailing_slash` 인수를 `False`로 설정하면 URL 경로에 따라오는 슬래시를 제거할 수 있습니다. 167 | 168 | ```python 169 | router = DefaultRouter(trailing_slash=False) 170 | ``` 171 | 172 | ## Custom Routers 173 | `custom router`를 구현하는 것은 자주해야 할 일은 아니지만 `API URL`이 어떻게 구성되는지에 대한 요구사항이 있는 경우 유용합니다. 이렇게 하면 재사용 할 수 있는 방식으로 URL구조를 캡슐화 할 수 있으므로 각 새로운 view에 대해 명시적으로 URL 패턴을 작성 할 필요가 없습니다. 174 | `custom router`를 구현하는 가장 간단한 방법은 기본 라우터 클래스 중 하나를 서브 클래스로 만드는 것입니다. `.routes` 속성은 각 viewset에 맵핑 될 URL 패턴을 template하는데 사용됩니다. `.routes`속성은 경로지정 튜플의 list입니다. 175 | `Route`라는 튜플에 대한 인수는 다음과 같습니다. 176 | 177 | **url** : 라우트 될 URL을 나타내는 문자열. 다음 타입의 문자열을 포함할 수 있습니다. 178 | 179 | - `{prefix}` : 이 경로 집합에 사용할 URL 접두사입니다. 180 | - `{lookup}` : 단일 인스턴스와 매치시키는데 사용되는 조회 필드입니다. 181 | - `{trailing_slash}` : `trailing_slash`인수에 따라 `'/'`나 빈 문자열입니다. 182 | 183 | **mapping** : HTTP 메서드 이름을 뷰 메서드에 매핑. 184 | 185 | **name** : `reverse` 호출에 사용되는 URL의 이름입니다. 다음 타입의 문자열을 포함 할 수 있씁니다. 186 | 187 | - `{basename}` : 생성된 URL 이름에 사용할 기준입니다. 188 | 189 | **initkwargs** : view를 인스턴스화 할 때 전달되어야하는 추가 인수의 dict. `suffix`인수는 뷰 이름과 탐색 경로 링크를 생성 할 떄 사용되는 viewset 유형을 식별하기 위해 예약되어 있습니다. 190 | 191 | ### Customizing dynamic routes 192 | `@list_route`와 `@detail_route`데코레이터가 라우팅되는 방법을 custom 할 수 있습니다. 이 데코레이터 중 하나나 모두를 라우트하려면 `.routes`목록에 `DynamicListRoute`와 `/`이나 `DynamicDetailRoute`라는 이름의 튜플을 포함하세요. 193 | `DynamicListRoute`와 `DynamicDetailRoute`의 인수는 다음과 같습니다. 194 | 195 | **url** : 라우트 될 URL을 나타내는 문자열. `Route`와 동일한 타입의 문자열을 포함할 수 있으며, `{methodname}`과 `{methodnamehyphen}`형식 문자열을 추가로 허용합니다. 196 | 197 | **name** : `reverse`호출에 사용되는 URL의 이름입니다. `{basename}`, `{methodname}` 및 `{methodnamehyphen}`과 같은 형식 문자열을 포함합니다. 198 | 199 | **initkwargs** : 뷰를 인스턴스화 할 때 전달되어야 하는 추가 인수의 dict 200 | 201 | ### Example 202 | 다음 예는 'list'와 'retrieve`의 액션에만 라우팅하며, 후행 슬래시 규칙은 사용하지 않습니다. 203 | 204 | ```python 205 | from rest_framework.routers import Route, DynamicDetailRoute, SimpleRouter 206 | 207 | class CustomReadOnlyRouter(SimpleRouter): 208 | """ 209 | A router for read-only APIs, which doesn't use trailing slashes. 210 | """ 211 | routes = [ 212 | Route( 213 | url=r'^{prefix}$', 214 | mapping={'get': 'list'}, 215 | name='{basename}-list', 216 | initkwargs={'suffix': 'List'} 217 | ), 218 | Route( 219 | url=r'^{prefix}/{lookup}$', 220 | mapping={'get': 'retrieve'}, 221 | name='{basename}-detail', 222 | initkwargs={'suffix': 'Detail'} 223 | ), 224 | DynamicDetailRoute( 225 | url=r'^{prefix}/{lookup}/{methodnamehyphen}$', 226 | name='{basename}-{methodnamehyphen}', 227 | initkwargs={} 228 | ) 229 | ] 230 | ``` 231 | `CustomReadOnlyRouter`가 간단한 viewset을 위해 생성 할 라우트를 살펴 보겠습니다. 232 | 233 | `views.py`: 234 | 235 | ```python 236 | class UserViewSet(viewsets.ReadOnlyModelViewSet): 237 | """ 238 | A viewset that provides the standard actions 239 | """ 240 | queryset = User.objects.all() 241 | serializer_class = UserSerializer 242 | lookup_field = 'username' 243 | 244 | @detail_route() 245 | def group_names(self, request): 246 | """ 247 | Returns a list of all the group names that the given 248 | user belongs to. 249 | """ 250 | user = self.get_object() 251 | groups = user.groups.all() 252 | return Response([group.name for group in groups]) 253 | ``` 254 | `urls.py` : 255 | 256 | ```python 257 | router = CustomReadOnlyRouter() 258 | router.register('users', UserViewSet) 259 | urlpatterns = router.urls 260 | ``` 261 | 다음과 같은 매칭이 생성됩니다... 262 | 263 | URL | HTTP Method| Action | URL Name 264 | ---|---|---|--- 265 | /users | GET | list | user-list 266 | /users/{username} | GET | retrieve | user-detail 267 | /users/{username}/group-names | GET | group_names | user-group-names 268 | 269 | `.routes`속성을 설정하는 다른 예제는 `SimpleRouter`클래스의 소스 코드를 참조하세요. 270 | 271 | ### Advanced custom routers 272 | 완전히 custom된 동작을 제공하려면 `BaseRouter`를 대체하고 `get_urls(self)`메서드를 대체할 수 있습니다. 이 메서드는 등록 된 viewset을 검사하고, URL 패턴 list를 리턴해야합니다. 등록된 prefix, viewset, basename 튜플은 `self.registry`속성에 액서스하여 검사할 수 있습니다. 273 | `get_default_base_name(self, viewset)`메서드를 오버라이드하거나, viewset을 라우터에 등록 할 때 항상 `base_name` 인수를 명시적으로 설정할 수 있습니다. 274 | 275 | ## Third Party Packages 276 | 다음의 타사 패키지도 제공됩니다. 277 | 278 | ### DRF Nested Routers 279 | [`drf-nested-routers`패키지](https://github.com/alanjds/drf-nested-routers)는 중첩된 리소스로 작업하기 위한 라우터와 관계 필드를 제공합니다. 280 | 281 | ### ModelRouter (wq.db.rest) 282 | [`wq.db 패키지`](https://wq.io/wq.db)는 `register_model()` API로 `DefaultRouter`를 확장하는 고급 [`ModelRouter`](https://wq.io/1.0/docs/router) 클래스(및 싱글 톤 인스턴스)를 제공합니다. Django의 `admin.site.register`와 마찬가지로 `rest.router.register_model`에 필요한 유일한 인수는 모델 클래스입니다. url prefix, serializer, viewset에 대한 합리적인 기본값은 모델과 전역구성에서 유추됩니다. 283 | 284 | ```python 285 | from wq.db import rest 286 | from myapp.models import MyModel 287 | 288 | rest.router.register_model(MyModel) 289 | ``` 290 | 291 | ### DRF-extensions 292 | [`DRF-extensions` package](http://chibisov.github.io/drf-extensions/docs/)는 [중첩된 viewset](http://chibisov.github.io/drf-extensions/docs/#nested-routes), [custom가 가능한 엔드포인트 이름](http://chibisov.github.io/drf-extensions/docs/#controller-endpoint-name)을 가진 [콜렉션 레벨 컨트롤러](http://chibisov.github.io/drf-extensions/docs/#collection-level-controllers)를 작성하기 위한 [라우터](http://chibisov.github.io/drf-extensions/docs/#routers)를 제공합니다. 293 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 07. Parsers.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Parsers 2 | 3 | --- 4 | 5 | _"Machine interacting web services tend to use more structured formats for sending data than form-encoded, since they're sending more complex data than simple forms"_ 6 | 7 | _"웹 서비스를 상호 작용하는 기계는 단순한 형식보다 복잡한 데이터를 전송하기 때문에 양식으로 인코딩 된 것보다 데이터 전송에 더 많은 구조화 된 형식을 사용하는 경향이 있습니다."_ 8 | 9 | _— Malcom Tredinnick, Django developers group_ 10 | 11 | --- 12 | 13 | ## Parsers 14 | REST 프레임워크에는 `Parser`클래스가 내장되어 있어 다양한 미디어 타입으로 requests를 수락할 수 있습니다. 또한 `custom parser`를 정의 할 수 있어서 API에서 허용하는 미디어 타입을 유연하게 디자인 할 수 있습니다. 15 | 16 | ### How the parser is determined 17 | 뷰에 대한 유효한 parser set은 항상 클래스 목록으로 정의됩니다. `request.data`에 액서스하면 REST 프레임워크는 들어오는 request의 `Content-Type` 헤더를 검사하고 request 내용을 parse하는데 사용할 `parser`를 결정합니다. 18 | 19 | --- 20 | **Note**: 클라이언트 응용 프로그램을 개발할 때는 항상 HTTP request로 데이터를 보낼때 `Content-Type`헤더를 설정해야 합니다. 21 | 콘텐트 타입을 설정하지 않으면 대부분의 클라이언트는 `'application/x-www-form-urlencoded'`를 기본값으로 사용합니다. 이는 원하지 않을 수 있습니다. 22 | 예를 들어, `.ajax()`메서드로 jQuery를 사용하여 `json`으로 인코딩 된 데이터를 보내는 경우, `contentType: 'application/json'`설정을 포함해야 합니다. 23 | 24 | --- 25 | 26 | ### Setting the parsers 27 | `parser`의 기본 set은 `DEFAULT_PARSER_CLASSES` 설정을 사용하여 전역으로 설정할 수 있습니다. 예를 들어, 다음 설정은 기본 JSON 이나 formdata 대신 JSON 컨텐트가 있는 requests만 허용합니다. 28 | 29 | ```python 30 | REST_FRAMEWORK = { 31 | 'DEFAULT_PARSER_CLASSES': ( 32 | 'rest_framework.parsers.JSONParser', 33 | ) 34 | } 35 | ``` 36 | `APIView`클래스의 기본 views를 사용하여 개별 view나 viewset에 사용되는 `parser`를 설정할 수도 있습니다. 37 | 38 | ```python 39 | from rest_framework.parsers import JSONParser 40 | from rest_framework.response import Response 41 | from rest_framework.views import APIView 42 | 43 | class ExampleView(APIView): 44 | """ 45 | A view that can accept POST requests with JSON content. 46 | """ 47 | parser_classes = (JSONParser,) 48 | 49 | def post(self, request, format=None): 50 | return Response({'received data': request.data}) 51 | ``` 52 | 또는 FBV와 함께 `@api_view`데코레이터를 사용하는 경우. 53 | 54 | ```python 55 | from rest_framework.decorators import api_view 56 | from rest_framework.decorators import parser_classes 57 | 58 | @api_view(['POST']) 59 | @parser_classes((JSONParser,)) 60 | def example_view(request, format=None): 61 | """ 62 | A view that can accept POST requests with JSON content. 63 | """ 64 | return Response({'received data': request.data}) 65 | ``` 66 | 67 | --- 68 | 69 | ## API Reference 70 | 71 | ### JSONParser 72 | `JSON` request content를 파싱합니다. 73 | **.media_type**: `application/json` 74 | 75 | ### FormParser 76 | HTMl form content를 파싱합니다. `request.data`는 데이터의 `QueryDict`로 채워집니다. 77 | 일반적으로 HTML form data를 완벽하게 지원하기 위해 `FormParser`와 `MultiPartParser`를 함께 사용하려고 합니다. 78 | **.media_type**: `application/x-www-form-urlencoded` 79 | 80 | ### MultiPartParser 81 | 파일 업로드를 지원하는 `Multi form content`를 파싱합니다. 두 `request.data` 모두 `QueryDict`로 채워집니다. 82 | 일반적으로 HTML form data를 완벽하게 지원하기 위해 `FormParser`와 `MultiPartParser`를 함께 사용하려고 합니다. 83 | **.media_type**: `multipart/form-data` 84 | 85 | ### FileUploadParser 86 | 가공되지 않은 file upload content를 파싱함니다. `request.data` 속성은 업로드 된 파일을 포함하는 단일 키`'file'`이 포함된 dict입니다. 87 | `FileUploadParser`와 함께 사용 된 view가 파일 이름 URL 키워드 인수로 호출되면 해당 인수가 filename 으로 사용됩니다. 88 | `filename` URL 키워드 인수없이 호출되면 클라이언트는 `Content-Disposition` HTTP 헤더에 filename을 설정해야 합니다. 예를 들면, `Content-disposition: attachment; filename=upload.jpg` 89 | **.media_type**: `*/*` 90 | 91 | ###### notes: 92 | 93 | - `FileUploadParser`는 파일을 가공되지 않은 데이터 request으로 업로드 할 수 있는 기본 클라이언트에서 사용하기 위한 것입니다. 웹 기반 업로드 또는 멀티 파트 업로드가 지원되는 기본 클라이언트의 경우 `MultiPartParser` 파서를 대신 사용해야합니다. 94 | - 이 파서의 `media_type`은 모든 콘텐트 타입과 일치하므로 `FileuploadParser`는 일반적으로 API view에 설정된 유일한 `parser` 이어야 합니다. 95 | - `FileUploadParser`는 Django의 표준 `FILE_UPLOAD_HANDLERS` 설정과 `request.upload_handlers` 속성을 고려합니다. 자세한 내용은 [Django 문서](https://docs.djangoproject.com/en/1.10/topics/http/file-uploads/#upload-handlers)를 참조하세요. 96 | 97 | ###### Basic usage example: 98 | 99 | ```python 100 | # views.py 101 | class FileUploadView(views.APIView): 102 | parser_classes = (FileUploadParser,) 103 | 104 | def put(self, request, filename, format=None): 105 | file_obj = request.data['file'] 106 | # ... 107 | # do some stuff with uploaded file 108 | # ... 109 | return Response(status=204) 110 | 111 | # urls.py 112 | urlpatterns = [ 113 | # ... 114 | url(r'^upload/(?P[^/]+)$', FileUploadView.as_view()) 115 | ] 116 | ``` 117 | --- 118 | 119 | ## Custom parsers 120 | `custom parser`를 구현하려면 `BaseParser`를 오버라이드하고 `.media_type`속성을 설정하고 `.parse(self, stream, media_type, parser_context)`메소드를 구현해야 합니다. 121 | 메서드는 `request.data`속성을 채우는데 사용할 데이터를 반환해야합니다. 122 | `.parse()`에 전달된 인수는 다음과 같습니다. 123 | 124 | ### stream 125 | request의 본문을 나타내는 스트림과 같은 객체입니다. 126 | 127 | ### media_type 128 | 선택사항. 제공되는 경우 들어오는 request content의 미디어 타입입니다. 129 | request의 `Content-Type:` 헤더에 따라 렌더러의 `media_type`속성보다 더 구체적일 수 있으며, 미디어 타입 parameter가 포함 될 수 있습니다. 예: `"text/plain; charset=utf-8"` 130 | 131 | ### parser_context 132 | 선택사항. 이 인수가 제공되면 request content을 파싱하는데 필요할 수 있는 추가 context를 포함하는 dict가 됩니다. 133 | 기본적으로 `view`, `request`, `args`, `kwargs` 키들이 포함됩니다. 134 | 135 | ### Example 136 | 다음은 request content를 나타내는 문자열로 `request.data`속성을 채우는 일반 텍스트 파서의 예입니다. 137 | 138 | ```python 139 | class PlainTextParser(BaseParser): 140 | """ 141 | Plain text parser. 142 | """ 143 | media_type = 'text/plain' 144 | 145 | def parse(self, stream, media_type=None, parser_context=None): 146 | """ 147 | Simply return a string representing the body of the request. 148 | """ 149 | return stream.read() 150 | ``` 151 | 152 | --- 153 | 154 | ## Third party packages 155 | 다음의 타사 패키지도 제공됩니다. 156 | 157 | ### YAML 158 | [REST 프레임 워크 YAML](http://jpadilla.github.io/django-rest-framework-yaml/)은 [YAML](http://www.yaml.org/) 파싱 및 렌더링 지원을 제공합니다. 이전에 REST 프레임워크 패키지에 직접 포함되어 있었으며 이제는 타사 패키지로 대신 지원됩니다. 159 | 160 | ###### 설치 및 구성 161 | pip를 사용하여 설치합니다. 162 | 163 | ``` 164 | $ pip install djangorestframework-yaml 165 | ``` 166 | REST 프레임워크 설정을 수정하세요. 167 | 168 | ```python 169 | REST_FRAMEWORK = { 170 | 'DEFAULT_PARSER_CLASSES': ( 171 | 'rest_framework_yaml.parsers.YAMLParser', 172 | ), 173 | 'DEFAULT_RENDERER_CLASSES': ( 174 | 'rest_framework_yaml.renderers.YAMLRenderer', 175 | ), 176 | } 177 | ``` 178 | 179 | ### XML 180 | 181 | [REST 프레임워크 XML](http://jpadilla.github.io/django-rest-framework-xml/)은 간단한 비공식 XML 형식을 제공합니다. 이전에 REST 프레임 워크 패키지에 직접 포함되어 있었으며 이제는 타사 패키지로 대신 지원됩니다. 182 | 183 | ###### 설치 및 구성 184 | pip를 사용하여 설치합니다. 185 | 186 | ``` 187 | $ pip install djangorestframework-xml 188 | ``` 189 | REST 프레임워크 설정을 수정하세요. 190 | 191 | ```python 192 | REST_FRAMEWORK = { 193 | 'DEFAULT_PARSER_CLASSES': ( 194 | 'rest_framework_xml.parsers.XMLParser', 195 | ), 196 | 'DEFAULT_RENDERER_CLASSES': ( 197 | 'rest_framework_xml.renderers.XMLRenderer', 198 | ), 199 | } 200 | ``` 201 | 202 | ### MessagePack 203 | [MessagePack](https://github.com/juanriaza/django-rest-framework-msgpack)은 빠르고 효율적인 바이너리 serializer 형식입니다. [Juan Riaza](https://github.com/juanriaza)는 MessagePack 렌더러와 REST 프레임 워크에 대한 파서 지원을 제공하는 [djangorestframework-msgpack 패키지](https://github.com/juanriaza/django-rest-framework-msgpack)를 유지 관리합니다. 204 | 205 | ### CamelCase JSON 206 | [djangorestframework-camel-case](https://github.com/vbabiy/djangorestframework-camel-case)는 REST 프레임워크를 위한 `parser`와 camel-case JSON 렌더러를 제공합니다. 이를 통해 serializer는 파이썬 스타일의 underscored 필드 이름을 사용할 수 있지만, 자바 스크립트 스타일의 camel case field names으로 API에 표시됩니다. 그것은 [Vitaly Babiy](https://github.com/vbabiy)에 의해 관리됩니다. 207 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 12. Validators.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Validators 2 | 3 | --- 4 | 5 | _"Validators can be useful for re-using validation logic between different types of fields."_ 6 | 7 | 8 | _"유효성 검사기는 다른 유형의 필드간에 유효성 검사논리를 다시 사용하는데 유용할 수 있습니다."_ 9 | 10 | _— Django documentation_ 11 | 12 | --- 13 | 14 | ## Validators(유효성 검사기) 15 | 대부분 REST 프레임워크에서 유효성 검사를 처리하는 경우 기본 필드 유효성 검사에 의존하거나 serializer 또는 필드 클래스에 대한 명시적인 `Validator` 메소드를 작성하기만 하면 됩니다. 16 | 그러나 때때로 유효성 검사 논리를 재사용 가능한 구성 요소에 배치하여 코드 베이스 전체에서 쉽게 재사용 할 수 있습니다. 이 작업은 Validator 함수와 Validators 클래스를 사용하여 수행할 수 있습니다. 17 | 18 | ### Validation in REST framework 19 | Django의 REST 프레임워크 serializer의 validation는 Django의 `ModelForm`클래스에서 validation이 작동하는 방식과 조금 다르게 처리됩니다. 20 | `ModelForm`을 사용하면 validation이 부분적으로 form에서 수행되고, 부분적으로 모델 인스턴스에서 수행됩니다. REST 프레임워크를 사용하면 validation은 전체적으로 serializer클래스에서 수행됩니다. 이는 다음과 같은 이유로 유리합니다. 21 | 22 | - 적절한 구분을 제공하여 코드 동작을 보다 명확하게 만듭니다. 23 | - shortcut `ModelSerializer`클래스를 사용하거나 명시적 serializer클래스를 사용하는 것은 쉽게 전환할 수 있습니다. `ModelSerializer`에 사용되는 모든 validation 동작은 복제가 간단합니다. 24 | - serializer 인스턴스의 `repr`을 출력(print)하면 validation 규칙이 정확하게 표시됩니다. 모델 인스턴스에서 추가 숨겨진 validation 동작이 호출되지 않습니다. 25 | `ModelSerializer`를 사용하면 모든 것이 자동으로 처리됩니다. 대신 Serializer클래스를 사용하여 드롭다운하려면 validation 규칙을 명시적으로 정의해야 합니다. 26 | 27 | #### Example 28 | REST 프레임워크가 명시적 validation을 사용하는 방법의 예로, 고유성 제약 조건이 있는 필드가 있는 간단한 모델 클래스를 사용합니다. 29 | 30 | ```python 31 | class CustomerReportRecord(models.Model): 32 | time_raised = models.DateTimeField(default=timezone.now, editable=False) 33 | reference = models.CharField(unique=True, max_length=20) 34 | description = models.TextField() 35 | ``` 36 | 다음은 `CustomReportRecord`인스턴스를 생성하거나 업데이트할 때 사용할 수 있는 기본 `ModelSerializer`입니다. 37 | 38 | ```python 39 | class CustomerReportSerializer(serializers.ModelSerializer): 40 | class Meta: 41 | model = CustomerReportRecord 42 | ``` 43 | `manage.py` shell을 사용하여 Django shell을 열면 이제 할 수 있습니다. 44 | 45 | ```python 46 | >>> from project.example.serializers import CustomerReportSerializer 47 | >>> serializer = CustomerReportSerializer() 48 | >>> print(repr(serializer)) 49 | CustomerReportSerializer(): 50 | id = IntegerField(label='ID', read_only=True) 51 | time_raised = DateTimeField(read_only=True) 52 | reference = CharField(max_length=20, validators=[]) 53 | description = CharField(style={'type': 'textarea'}) 54 | ``` 55 | 여기서 흥미로운 부분은 참조필드입니다. 고유성 제약이 serializer 필드의 validator에 의해 명시적으로 적용되고 있음을 알 수 있습니다. 56 | 더 명시적인 스타일 때문에 REST 프레임워크는 Django의 핵심에서 사용할 수 없는 몇가지 validator 클래스를 포함합니다. 이 클래스들은 아래에 자세히 설명되어 있습니다. 57 | 58 | --- 59 | 60 | ### UniqueValidator 61 | validator를 사용하여 모델 필드에 `unique=True`제약 조건을 적용 할 수 있습니다. 하나의 필수 인수와 선택적 `massages` 인수를 취합니다. 62 | 63 | - `queryset` (필수) : 유일성을 강요해야하는 queryset입니다. 64 | - `massege` : 검증이 실패했을 경우 사용하는 에러 메세지 65 | - `lookup` : 검증되고 있는 값을 가지고 기존의 인스턴스를 찾는데 사용합니다. 기본값은 `exact`입니다. 66 | 67 | 이 validator는 다음과 같이 serializer 필드에 적용되어야 합니다. 68 | 69 | ```python 70 | from rest_framework.validators import UniqueValidator 71 | 72 | slug = SlugField( 73 | max_length=100, 74 | validators=[UniqueValidator(queryset=BlogPost.objects.all())] 75 | ) 76 | ``` 77 | 78 | ### UniqueTogetherValidator 79 | 이 validator를 사용하여 모델 인스턴스에 `unique_together`제약 조건을 적용할 수 있습니다. 여기에는 두 개의 필수 인수와 단일 선택적 `messages`인수가 있습니다. 80 | 81 | - `queryset`(필수) : 유일성을 강요해야하는 queryset입니다. 82 | - `fields`(필수) : 고유한 set을 만들어야 하는 필드이름의 list 또는 tuple. 이들은 serializer 클래스의 필드로 존재해야 합니다. 83 | - `message` : 검증에 실패했을 경우 사용하는 에러 메세지 84 | 85 | validator는 다음과 같이 serializer 클래스에 적용되어야 합니다. 86 | 87 | ```python 88 | from rest_framework.validators import UniqueTogetherValidator 89 | 90 | class ExampleSerializer(serializers.Serializer): 91 | # ... 92 | class Meta: 93 | # ToDo items belong to a parent list, and have an ordering defined 94 | # by the 'position' field. No two items in a given list may share 95 | # the same position. 96 | validators = [ 97 | UniqueTogetherValidator( 98 | queryset=ToDoItem.objects.all(), 99 | fields=('list', 'position') 100 | ) 101 | ] 102 | ``` 103 | 104 | --- 105 | **Note**: `UniqueTogetherValidation`클래스는 항상 적용되는 모든 필드가 항상 필요한 것으로 처리된다는 암시적 제약조건을 부과합니다. `default`가 있는 필드는 사용자 입력에서 생략 된 경우에도 항상 값을 제공하므로 예외입니다. 106 | 107 | --- 108 | 109 | ### UniqueForDateValidator 110 | ### UniqueForMonthValidator 111 | ### UniqueForYearValidator 112 | 이 validator는 모델 인스턴스에 대해 `unique_for_date`, `unique_for_month`, `unique_for_year` 제약조건을 적용하는데 사용할 수 있습니다. 113 | 114 | - `queryset`(필수) : 유일성을 강요해야하는 queryset입니다. 115 | - `field`(필수) : 지정된 날짜 범위의 고유성에 대한 필드 이름입니다. 이것은 serializer 클래스의 필드로 존재해야합니다. 116 | - `date_field`(필수) : 고유성 제한 조건의 날짜 범위를 결정하는데 사용할 필드 이름입니다. 이것은 serializer클래스의 필드로 존재해야 합니다. 117 | - `massege` : 검증이 실패했을 경우에 사용하는 에러 메세지 118 | 119 | validator는 다음과 같이 serializer클래스에 적용되어야 합니다. 120 | 121 | ```python 122 | from rest_framework.validators import UniqueForYearValidator 123 | 124 | class ExampleSerializer(serializers.Serializer): 125 | # ... 126 | class Meta: 127 | # Blog posts should have a slug that is unique for the current year. 128 | validators = [ 129 | UniqueForYearValidator( 130 | queryset=BlogPostItem.objects.all(), 131 | field='slug', 132 | date_field='published' 133 | ) 134 | ] 135 | ``` 136 | validation에 사용되는 날짜 필드는 항상 serializer클래스에 있어야 합니다. validation이 실행될 때까지 기본값에 사용되는 값이 생성되지 않기 때문에 모델 클래스 `default=...`에 의존할 수 없습니다. 137 | API를 어떻게 동작시키는지에 따라 이 스타일을 사용할 수 있는 스타일이 몇가지 있습니다. `ModelSerializer`를 사용하는 경우 REST 프레임워크에서 생성하는 기본값을 사용하는 것이 좋지만 serializer를 사용하거나 보다 명시적인 제어를 원한다면 아래에 설명된 스타일을 사용하세요. 138 | 139 | #### Using with a writable date field. (쓰기 가능한 날짜 필드와 함께 사용하기) 140 | 날짜 필드를 쓰기 가능하게하려면, 기본 인수를 설정하거나 `required=True`를 설정하여 입력 데이터에서 항상 사용할 수 있도록 해야합니다. 141 | 142 | ``` 143 | published = serializers.DateTimeField(required=True) 144 | ``` 145 | 146 | #### Using with a read-only date field. (읽기 전용 날짜 필드와 함께 사용하기) 147 | 사용자가 날짜 필드를 볼 수는 있지만 편집할 수도 없도록 하려면 `read_only=True`로 설정하고 추가로 `default=...`인수를 설정하십시오. 148 | 149 | ``` 150 | published = serializers.DateTimeField(read_only=True, default=timezone.now) 151 | ``` 152 | 필드는 사용자에게 쓸 수 없지만 기본값은 여전히 `validated_data`로 전달됩니다. 153 | 154 | #### Using with a hidden date field. (숨겨진 날짜 필드와 함께 사용하기) 155 | 사용자가 날짜 필드를 완전히 숨기려면 `HiddenField`를 사용하세요. 이 필드 타입은 사용자 입력을 허용하지 않고 대신 항상 기본값을 serializer의 `validated_data`로 반환합니다. 156 | 157 | ``` 158 | published = serializers.HiddenField(default=timezone.now) 159 | ``` 160 | 161 | --- 162 | **Note**: `UniqueForValidation`클래스는 적용되는 필드가 항상 필요한 것으로 처리된다는 암시적 제약조건을 적용합니다. `default`가 있는 필드는 사용자 입력에서 생략된 경우에도 항상 값을 제공하므로 예외입니다. 163 | 164 | --- 165 | 166 | ## Advanced field defaults 167 | serializer의 여러 필드에 적용되는 valistor는 API 클라이언트가 제공해서는 안되지만 validator의 입력으로 사용할 수 있는 필드 입력이 필요할 수 있습니다. 168 | 이러한 유형의 validation에 사용할 수 있는 두가지 패턴은 다음과 같습니다. 169 | 170 | - `HiddenField`를 사용하는 것입니다. 이 필드는 `validated_data`에 있지만 serializer 출력 표현에서는 사용되지 않습니다. 171 | - `read_only=True`와 함께 표준 필드는 사용하지만 `default=...`인수도 포함합니다. 이 필드는 serializer 출력 표현에 사용되지만 사용자가 직접 설정할 수는 없습니다. 172 | 173 | REST 프레임워크는 이 컨텍스트에서 유용 할 수 있는 몇 가지 기본값을 포함합니다. 174 | 175 | ### CurrentUserDefault 176 | 현재 사용자를 나타내는데 사용할 수 있는 기본 클래스입니다. 이것을 사용하기 위해서는, serializer를 인스턴스화 할때 `request`가 컨텍스트 dict의 일부로 제공되어야 합니다. 177 | 178 | ```python 179 | owner = serializers.HiddenField( 180 | default=serializers.CurrentUserDefault() 181 | ) 182 | ``` 183 | 184 | ### CreateOnlyDefault 185 | 작성 조작 중 default의 인수만을 설정하는데 사용할 수 있는 기본 클래스. 업데이트 중 필드는 생략됩니다. 186 | 이것은 작성 작업중에 사용되는 기본값이거나 호출 가능한 단일 인수를 취합니다. 187 | 188 | ```python 189 | created_at = serializers.DateTimeField( 190 | read_only=True, 191 | default=serializers.CreateOnlyDefault(timezone.now) 192 | ) 193 | ``` 194 | 195 | --- 196 | ## Limitations of validators 197 | `ModelSerializer`이 생성하는 기본 serializer 클래스를 사용하는 대신 validation을 명시적으로 처리해야하는 모호한 경우가 있습니다. 198 | 이러한 경우 serializerz `Meta.valisators`속성에 대한 빈 목록을 지정하여 자동 생성 된 validator를 사용하지 않도록 설정할 수 있습니다. 199 | 200 | ### Optional fields 201 | 기본적으로 "unique together"validation는 모든 필드가 `required=True`인지 확인합니다. 경우에 따라 필드 중 하나에 명시적으로 `required=False`를 적용하면 원하는 validation 동작이 모호할 수 있습니다. 202 | 이 경우 일반적으로 serializer 클래스에서 validator를 제외하고, `.validate()`메서드나 뷰에서 validation 논리를 명시적으로 작성해야합니다. 203 | 204 | 예를 들어: 205 | 206 | ```python 207 | class BillingRecordSerializer(serializers.ModelSerializer): 208 | def validate(self, data): 209 | # Apply custom validation either here, or in the view. 210 | 211 | class Meta: 212 | fields = ('client', 'date', 'amount') 213 | extra_kwargs = {'client': {'required': 'False'}} 214 | validators = [] # Remove a default "unique together" constraint. 215 | ``` 216 | 217 | ### Updating nested serializers 218 | 기존 인스턴스에 업데이트를 적용할 때 고유성 validator는 현재 인스턴스를 고유성 검사에서 제외합니다. 현재 인스턴스는 고유성 검사의 컨텍스트에서 사용 할 수 있습니다. 이 속성은 serializer의 속성으로 존재하기 때문에 처음에는 serializer를 인스턴스화 할때 `instance=...`를 사용하여 전달되었습니다. 219 | 중첩 된 serializer에 대한 업데이트 작업의 경우 인스턴스를 사용할 수 없으므로 이 배제를 적용할 방법이 없습니다. 220 | 다시 말하면, serializer클래스에서 validator를 명시적으로 제거하고 validation 제약 조건에 대한 코드를 명시적으로 `.validate()`메서드나 뷰에 작성하려고 합니다. 221 | 222 | ### Debugging complex cases 223 | `ModelSerializer` 클래스가 어떤 동작을 하는지 확실히 모를 경우 `manage.py` 셸을 실행하고 serializer의 인스턴스를 인쇄하면 자동으로 생성되는 필드와 validator를 검사 할 수 있습니다. 224 | 225 | ```python 226 | >>> serializer = MyComplexModelSerializer() 227 | >>> print(serializer) 228 | class MyComplexModelSerializer: 229 | my_fields = ... 230 | ``` 231 | 또한 복잡한 경우에는 기본 `ModelSerializer` 동작을 사용하는 대신 serializer 클래스를 명시적으로 정의하는 것이 더 나을 수 있습니다. 232 | 233 | --- 234 | 235 | ## Writing custom validators 236 | Django의 기존 validator를 사용하거나 custom validator를 작성할 수 있습니다. 237 | 238 | ### Function based 239 | validator는 아마도 실패하면 `serializer.ValidationError`를 발생시켜 호출합니다. 240 | 241 | ```python 242 | def even_number(value): 243 | if value % 2 != 0: 244 | raise serializers.ValidationError('This field must be an even number.') 245 | ``` 246 | #### Field-level validation 247 | Serializer 서브 클래스에 `.validate_` 메소드를 추가하여 custom 필드 레벨 vallidation을 지정 할 수 있습니다. 248 | 249 | ### Class-based 250 | 클래스 기반 validator를 작성하려면 `__call__`메서드를 사용하세요. 클래스 기반 validator는 동작을 매개 변수화하고 다시 사용할 수 있으므로 유용합니다. 251 | 252 | ```python 253 | class MultipleOf(object): 254 | def __init__(self, base): 255 | self.base = base 256 | 257 | def __call__(self, value): 258 | if value % self.base != 0: 259 | message = 'This field must be a multiple of %d.' % self.base 260 | raise serializers.ValidationError(message) 261 | ``` 262 | 263 | #### Using `set_context()` 264 | 265 | 일부 고급 예제에서는 validator를 추가 컴텍스트로 사용되는 serializer 필드로 전달해야 할 수 있습니다. 클래스 기반의 validator에서 `set_context`메서드를 선언하여 그렇게 할 수 있습니다. 266 | 267 | ```python 268 | def set_context(self, serializer_field): 269 | # Determine if this is an update or a create operation. 270 | # In `__call__` we can then use that information to modify the validation behavior. 271 | self.is_update = serializer_field.parent.instance is not None 272 | ``` -------------------------------------------------------------------------------- /doc/Django REST Framework - 13. Authentication.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Authentication 2 | 3 | --- 4 | 5 | _"Auth needs to be pluggable."_ 6 | 7 | _"인증은 플러그가 가능해야 합니다."_ 8 | 9 | _— Jacob Kaplan-Moss, "REST worst practices"_ 10 | 11 | --- 12 | 13 | ## Authentication(입증) 14 | Authentication은 수신 요청을 요청한 사용자 또는 서명 된 토큰과 같은 식별 자격 증명 세트를 연결하는 메커니즘입니다. 그런 다음 [권한](http://www.django-rest-framework.org/api-guide/permissions/)과 [정책](http://www.django-rest-framework.org/api-guide/throttling/)은 이러한 자격 증명을 사용하여 요청을 허용해야 하는지 결정할 수 있습니다. 15 | REST 프레임워크는 여러가지 인증 스키마를 즉시 제공하며 custom 스키마를 구현할 수도 있습니다. 16 | Authentication은 항상 View의 맨 처음, 권한 및 제한 검사가 수행되기 전에 그리고 다른 코드가 진행되기 전에 실행됩니다. 17 | `request.user`속성은 일반적으로 `contrib.auth`패키지의 `User`클래스 인스턴스로 설정됩니다. 18 | `request.auth` 등록정보는 추가인증 정보에 사용됩니다. 예를 들어, request가 서명 된 인증 토큰을 나타내는데 사용될 수 있습니다. 19 | 20 | --- 21 | 22 | **Note**: 들어오는 request를 허용하거나 거부하지 않는 인증은 request가 수행된 자격 증명을 식별하기만하면 된다는 것을 잊지 마십시오. 23 | API에 대한 사용권한정책을 설정하는 방법에 대한 자세한 내용은 [permissions documentation](http://www.django-rest-framework.org/api-guide/permissions/)를 참조하세요. 24 | 25 | --- 26 | 27 | ### How authentication is determined 28 | 인증 체계는 항상 클래스 list으로 정의됩니다. REST 프레임워크는 list의 각 클래스에 대해 인증을 시도하고 성공적으로 인증한 첫 번째 클래스의 반환 값을 사용하여 `request.user` 및 `request.auth`를 설정합니다. 29 | 클래스가 인증되지 않으면 `request.user`는 `django.contrib.auth.AnonymousUser`의 인스턴스로 설정되고 `request.auth`는 `None`으로 설정됩니다. 30 | 인증되지 않은 요청에 대한 `request.user`, `request.auth`의 값은 `UNAUTHENTICATED_USER`, `UNAUTHENTICATED_TOKEN` 설정을 사용하여 수정할 수 있습니다. 31 | 32 | ### Setting the authentication scheme 33 | `DEFAULT_AUTHENTICATION_CLASSES` 설정을 사용하여 기본 인증 구성표를 전역으로 설정할 수 있습니다. 예를 들면. 34 | 35 | ```python 36 | REST_FRAMEWORK = { 37 | 'DEFAULT_AUTHENTICATION_CLASSES': ( 38 | 'rest_framework.authentication.BasicAuthentication', 39 | 'rest_framework.authentication.SessionAuthentication', 40 | ) 41 | } 42 | ``` 43 | 또한 `APIVIew` CBV를 사용하여 view 단위 또는 view단위로 인증 체계를 구성할 수 있습니다. 44 | 45 | ```python 46 | from rest_framework.authentication import SessionAuthentication, BasicAuthentication 47 | from rest_framework.permissions import IsAuthenticated 48 | from rest_framework.response import Response 49 | from rest_framework.views import APIView 50 | 51 | class ExampleView(APIView): 52 | authentication_classes = (SessionAuthentication, BasicAuthentication) 53 | permission_classes = (IsAuthenticated,) 54 | 55 | def get(self, request, format=None): 56 | content = { 57 | 'user': unicode(request.user), # `django.contrib.auth.User` instance. 58 | 'auth': unicode(request.auth), # None 59 | } 60 | return Response(content) 61 | ``` 62 | 또는 FBV와 함께 `@api_view`데코레이터를 사용하는 경우 63 | 64 | ```pyhon 65 | @api_view(['GET']) 66 | @authentication_classes((SessionAuthentication, BasicAuthentication)) 67 | @permission_classes((IsAuthenticated,)) 68 | def example_view(request, format=None): 69 | content = { 70 | 'user': unicode(request.user), # `django.contrib.auth.User` instance. 71 | 'auth': unicode(request.auth), # None 72 | } 73 | return Response(content) 74 | ``` 75 | 76 | ### Unauthorized and Forbidden responses(무단 및 금지된 응답) 77 | 인증되지 않은 요청에 권한이 거부되면 적절한 두 가지 오류 코드가 있습니다. 78 | 79 | - [HTTP 401 Unauthorized](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2) 80 | - [HTTP 403 Permission Denied](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.4) 81 | 82 | HTTP 401 응답에는 항상 클라이언트에 인증 방법을 지시하는 `WWW-Authenticate` 헤더가 포함되어야합니다. HTTP 403 응답에는 `WWW-Authenticate` 헤더가 포함되지 않습니다. 83 | 사용되는 response의 종류는 인증 체계에 따라 다릅니다. 여러 인증 스키마가 사용 중일 수 있지만, response의 타입을 결정하는데 하나의 스키마만 사용할 수 있습니다. **view에 설정된 첫번째 authentication 클래스는 response 타입을 결정 할 때 사용됩니다.** 84 | request가 성공적으로 인증 될 수 있지만, 여전히 request를 수행할 권한이 거부 된 경우, 인증 스키마에 관계없이 `403 Permission Denied`응답이 항상 사용됩니다. 85 | 86 | ### Apache mod_wsgi specific configuration 87 | mod_wsgi를 사용하여 Apache에 배포한다면, 권한 부여 헤더는 기본적으로 응용프로그램 수준이 아닌 Apache에서 인증을 처리한다고 가정하므로, 기본적으로 WSGI 응용프로그램에 전달되지 않습니다. 88 | Apache에 배포하고 비 세션 기반 인증을 사용하는 경우 `mod_wsgi`를 명시적으로 구성하여 필요한 헤더를 응용프로그램에 전달해야 합니다. 이는 적절한 컨텍스트에서 `WSGIPassAuthorization`지시문을 지정하고 `On`으로 설정하여 수행할 수 있습니다. 89 | 90 | ``` 91 | # 이것은 서버 설정, 가상 호스트, 디렉토리 또는 .htaccess 중 하나에 들어갈 수 있습니다. 92 | 93 | WSGIPassAuthorization On 94 | ``` 95 | 96 | --- 97 | 98 | ## API Reference 99 | 100 | ### BasicAuthentication 101 | 이 인증 체계는 사용자의 사용자 이름과 암호에 대해 서명 된 [HTTP basic Authentication](https://tools.ietf.org/html/rfc2617)을 사용합니다. 기본 인증은 일반적으로 테스트에만 적합합니다. 102 | 성공적으로 인증되면 `BasicAuthencation`은 다음 자격 증명을 제공합니다. 103 | 104 | - `request.user`는 Django `User`인스턴스가 될 것입니다. 105 | - `request.auth`는 `None`입니다. 106 | 107 | 권한이 거부 된 인증되지 않은 응답은 적절한 WWW-Authenticate 헤더와 함께 `HTTP 401 Unauthorized` 웅답이 됩니다. 108 | 109 | ``` 110 | WWW-Authenticate: Basic realm="api" 111 | ``` 112 | 113 | **Note**: 프로덕션 환경에서 `BasicAuthentication`을 사용하는 경우 `https`를 통해서만 API를 사용할 수 있어야 합니다. 또한 API 클라이언트가 로그인 할때 항상 사용자 이름과 비밀번호를 다시 요청하고 해당 세부정보를 영구 저장소에 저장하지 않도록 해야합니다. 114 | 115 | ### TokenAuthentication 116 | 이 인증체계는 간단한 토큰 기반 HTTP인증체계를 사용합니다. 토큰 인증은 네이티브 데스크톱 및 모바일 클라이언트와 같은 클라이언트 - 서버 설정에 적합합니다. 117 | `TokenAuthentication` 스키마를 사용하려면 `TokenAuthentication`을 포함하도록 [authentication클래스를 구성](http://www.django-rest-framework.org/api-guide/authentication/#setting-the-authentication-scheme)하고 `INSTALLED_APPS`설정에 `rest_framework.authtoken`를 추가해야 합니다. 118 | 119 | ``` 120 | INSTALLED_APPS = ( 121 | ... 122 | 'rest_framework.authtoken' 123 | ) 124 | ``` 125 | 126 | --- 127 | 128 | **Note**: 설정을 변경한 후에 `manage.py migrate`를 실행해야합니다. `rest_framework.authtoken`앱은 Django 데이터베이스 마이그레이션을 제공합니다. 129 | 130 | --- 131 | 132 | 또한 사용자를 위한 토큰을 만들어야 합니다. 133 | 134 | ```python 135 | from rest_framework.authtoken.models import Token 136 | 137 | token = Token.objects.create(user=...) 138 | print token.key 139 | ``` 140 | 클라이언트가 인증하려면 토큰 키가 `Authorization` HTTP 헤더에 포함되어야합니다. 키에는 두 문자열을 공백으로 구분하여 문자열 리터럴 "Token"을 prefix로 사용해야합니다. 예: 141 | 142 | ``` 143 | Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b 144 | ``` 145 | **Note**: `Bearer`와 같은 헤더에 다른 키워드를 사용하려면 단순히 `TokenAuthentication`을 서브 클래스화하고 `keyword` 클래스 변수를 설정하십시오. 146 | 성공적으로 인증되면 `TokenAuthentication`은 다음 자격 증명을 제공합니다. 147 | 148 | - `request.user`는 Django `User` 인스턴스가 될 것입니다. 149 | - `request.auth`는 `rest_framework.authtoken.models.Token` 인스턴스가 됩니다. 150 | 151 | 권한이 거부 된 인증되지 않은 응답은 적절한 WWW-Authenticate 헤더와 함께 `HTTP 401 Unauthorized` 응답이 됩니다. 예: 152 | 153 | ``` 154 | WWW-Authenticate: Token 155 | ``` 156 | `curl` command line tool은 토큰으로 인증된 API를 테스트 하는데 유용할 수 있습니다. 예: 157 | 158 | ``` 159 | curl -X GET http://127.0.0.1:8000/api/example/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' 160 | ``` 161 | 162 | --- 163 | **Note**: 프로덕션 환경에서 `TokenAuthentication`을 사용하는 경우 `https`를 통해서만 API를 사용할 수 있어야 합니다. 164 | 165 | --- 166 | #### Generating Tokens 167 | ##### By using signals 168 | 모든 사용자가 자동으로 생선 된 토큰을 갖기를 원하면 사용자의 `post_save`신호를 간단히 잡을 수 있습니다. 169 | 170 | ```python 171 | from django.conf import settings 172 | from django.db.models.signals import post_save 173 | from django.dispatch import receiver 174 | from rest_framework.authtoken.models import Token 175 | 176 | @receiver(post_save, sender=settings.AUTH_USER_MODEL) 177 | def create_auth_token(sender, instance=None, created=False, **kwargs): 178 | if created: 179 | Token.objects.create(user=instance) 180 | ``` 181 | 이 코드는 snippet이 설치된 `models.py` 모듈이나 시작시 Django가 가져올 다른 위치에 배치해야 합니다. 182 | 이미 일부 사용자를 만든 경우 다음과 같이 모든 기존 사용자에 대한 토큰을 생성 할 수 있습니다. 183 | 184 | ```python 185 | from django.contrib.auth.models import User 186 | from rest_framework.authtoken.models import Token 187 | 188 | for user in User.objects.all(): 189 | Token.objects.get_or_create(user=user) 190 | ``` 191 | ##### By exposing an api endpoint(api 엔드포인트를 노출시킴) 192 | `TokenAuthentication`을 사용할 때 클라이언트가 사용자 이름과 암호가 있는 토큰을 얻을 수 있는 메커니즘을 제공 할 수 있습니다. REST 프레임워크는 이 동작을 제공하는 built-in 뷰를 제공합니다. 그것을 사용하려면 URLconf에 `obtain_auth_token` 뷰를 추가하세요. 193 | 194 | ```python 195 | from rest_framework.authtoken import views 196 | urlpatterns += [ 197 | url(r'^api-token-auth/', views.obtain_auth_token) 198 | ] 199 | ``` 200 | 패턴의 URL 부분은 원하는대로 사용할 수 있습니다. 201 | `obtain_auth_token` 뷰는 유효한 `사용자 이름` 및 `암호` 필드가 양식 데이터 또는 JSON을 사용하여 뷰에 POST되면 JSON 응답을 리턴합니다. 202 | 203 | ``` 204 | { 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' } 205 | ``` 206 | 기본 `obtain_auth_token` 뷰는 설정에서 기본 renderer 및 parser 클래스를 사용하는 대신 JSON 요청 및 응답을 명시적으로 사용합니다. 207 | `obtain_auth_token`view의 custom 된 버전이 필요하면 `ObtainAuthToken`view 클래스를 대체하고 URL conf에 대신 사용하세요. 208 | 기본적으로 `obtain_auth_token` view에 적용된 사용 권한이나 제한이 없습니다. 제한을 적용하려면 view클래스를 재정의하고 `throttle_classes`속성을 사용하여 view클래스를 포함해야 합니다. 209 | 210 | ##### With Django admin 211 | 관리자 인터페이스를 통해 수동으로 토큰을 생성 할 수도 있습니다. 대규모 사용자 기반을 사용하는 경우, `user` 필드를 `raw_field`로 선언하여 `TokenAdmin` 클래스를 monkey 패치하여 필요에 맞게 custom하는 것이 좋습니다. 212 | 213 | `your_app/admin.py`: 214 | 215 | ```python 216 | from rest_framework.authtoken.admin import TokenAdmin 217 | 218 | TokenAdmin.raw_id_fields = ('user',) 219 | ``` 220 | 221 | ### SessionAuthentication 222 | 이 인증방식은 Django의 기본 세션 백엔드를 인증에 사용합니다. 세션 인증은 웹 사이트롸 동일한 세션 컨텍스트에서 실행되는 AJAX 클라이언트에 적합합니다. 223 | 성공적으로 인증되면 `SessionAuthentication`은 다음 자격 증명을 제공합니다. 224 | 225 | - `request.use`r는 Django `User` 인스턴스가 될 것입니다. 226 | - `request.auth`는 `None`입니다. 227 | 228 | 권한이 거부 된 인증되지 않은 응답은 `HTTP 403 Forbidden`응답이 됩니다. 229 | SessionAuthentication과 함께 AJAX 스타일 API를 사용하는 경우 `PUT`, `PATCH`, `POST` 또는 `DELETE` 요청과 같은 **"안전하지 않은"**HTTP 메소드 호출에 유효한 CSRF 토큰을 포함시켜야합니다. 자세한 내용은 [Django CSRF documentation](https://docs.djangoproject.com/en/1.10/ref/csrf/#ajax) 참조 230 | **Warning**: 로그인 페이지를 만들 때 항상 Django의 표준 로그인 view를 사용하세요. 이렇게 하면 로그인view가 올바르게 보호됩니다. 231 | REST 프레임워크의 CSRF 유효성 검사는 동일한 view에 대해 session 및 non-session 기반 인증을 모두 지원해야하므로 표준 Django와 약간 다르게 작동합니다. 즉, 인증 된 요청만 CSRF 토큰이 필요로 하며 익명 요청은 CSRF 토큰 없이 전송될 수 있습니다. 이 동작은 항상 CSRF 유효성 검사가 적용된 로그인 View에는 적합하지 않습니다. 232 | 233 | ## Custom authentication 234 | 사용자 정의 인증 체계를 구현하려면 `BaseAuthentication`을 서브 클래스화하고 `.authenticate(self, request)` 메소드를 대체하십시오. 이 메소드는 인증에 성공하면 2-tuple(user, auth)을 반환하고, 그렇지 않으면 `None`을 반환햐야 합니다. 235 | `None`을 반환하는 대신 상황에 따라 `.authenticate()` 메서드에서 `AuthenticationFailed` 예외를 발생 시킬 수 있습니다. 236 | 일반적으로 취해야 할 접근 방식은 다음과 같습니다. 237 | 238 | - 인증을 시도하지 않으면 `None`을 반환합니다. 사용중인 다른 인증 체계도 계속 검사됩니다. 239 | - 인증을 시도했지만 실패한 경우 `AuthenticationFailed` 예외를 발생시킵니다. 권한 확인과 관계없이 다른 인증 스키마를 확인하지 않고 즉시 오류 응답이 반환됩니다. 240 | 241 | 또한 `.authenticate_header(self, request)` 메소드를 대체 할 수 있습니다. 구현 된 경우 `HTTP 401 Unauthorized` 응답에서 `WWW-Authenticate` 헤더의 값으로 사용 될 문자열을 반환해야합니다. 242 | `.authenticate_header()` 메소드가 대체되지 않으면, 인증 스키마는 인증되지 않은 요청이 액세스를 거부 할 때 `HTTP 403 Forbidden` 응답을 리턴합니다. 243 | 244 | ### Example 245 | 다음 예제는 들어오는 요청을 'X_USERNAME'이라는 사용자 지정 request 헤더에서 사용자 이름으로 지정된 사용자로 인증합니다. 246 | 247 | ```python 248 | from django.contrib.auth.models import User 249 | from rest_framework import authentication 250 | from rest_framework import exceptions 251 | 252 | class ExampleAuthentication(authentication.BaseAuthentication): 253 | def authenticate(self, request): 254 | username = request.META.get('X_USERNAME') 255 | if not username: 256 | return None 257 | 258 | try: 259 | user = User.objects.get(username=username) 260 | except User.DoesNotExist: 261 | raise exceptions.AuthenticationFailed('No such user') 262 | 263 | return (user, None) 264 | ``` 265 | 266 | ## Third party packages 267 | 다음의 타사 패키지도 제공됩니다. 268 | 269 | ### Django OAuth Toolkit 270 | [Django OAuth Toolkit](https://github.com/evonove/django-oauth-toolkit) 패키지는 OAuth 2.0 지원을 제공하며 Python 2.7 및 Python 3.3 이상에서 작동합니다. 이 패키지는 [Evonove](https://github.com/evonove/)에서 유지 관리하며 우수한 [OAuthLib](https://github.com/idan/oauthlib)을 사용합니다. 이 패키지는 잘 문서화되어 잘 지원되며 현재 **OAuth 2.0 지원을위한 권장 패키지**입니다. 271 | 272 | #### 설치와 구성 273 | pip를 사용하여 설치합니다. 274 | 275 | ``` 276 | pip install django-oauth-toolkit 277 | ``` 278 | 패키지를 `INSTALLED_APPS`에 추가하고 REST 프레임워크 설정을 수정하십시오. 279 | 280 | ``` 281 | INSTALLED_APPS = ( 282 | ... 283 | 'oauth2_provider', 284 | ) 285 | 286 | REST_FRAMEWORK = { 287 | 'DEFAULT_AUTHENTICATION_CLASSES': ( 288 | 'oauth2_provider.ext.rest_framework.OAuth2Authentication', 289 | ) 290 | } 291 | ``` 292 | 자세한 내용은 [Django REST framework - Getting started](https://django-oauth-toolkit.readthedocs.io/en/latest/rest-framework/getting_started.html)를 참조하세요. 293 | 294 | ### Django REST framework OAuth 295 | Django [REST 프레임워크 OAuth](http://jpadilla.github.io/django-rest-framework-oauth/) 패키지는 REST 프레임워크에 대한 OAuth1 및 OAuth2 지원을 제공합니다. 이 패키지는 이전에 REST 프레임 워크에 직접 포함되었지만 이제는 타사 패키지로 지원 및 유지 관리됩니다. 296 | #### 설치와 구성 297 | pip를 사용하여 패키지를 설치합니다. 298 | 299 | ``` 300 | pip install djangorestframework-oauth 301 | ``` 302 | 설정과 사용에 대한 자세한 내용은 Django REST 프레임워크 OAuth문서에서 [인증](http://jpadilla.github.io/django-rest-framework-oauth/authentication/)과 [권한](http://jpadilla.github.io/django-rest-framework-oauth/permissions/)을 참조하세요. 303 | 304 | ### Digest Authentication 305 | HTTP 다이제스트 인증은 HTTP 기본 인증을 대체하기 위한 것으로 널리 구현 된 구성이며 간단한 암호화 된 인증 메커니즘을 제공합니다. [Juan Riaza](https://github.com/juanriaza)는 REST 프레임워크에 HTTP 다이제스트 인증 지원을 제공하는 [djangorestframework-digestauth](https://github.com/juanriaza/django-rest-framework-digestauth) 패키지를 유지 관리합니다. 306 | 307 | ### Django OAuth2 Consumer 308 | [Rediker Software](https://github.com/Rediker-Software)의 [Django OAuth2 Consumer](https://github.com/Rediker-Software/doac) 라이브러리는 [REST 프레임 워크에 대한 OAuth 2.0 지원](https://github.com/Rediker-Software/doac/blob/master/docs/integrations.md#)을 제공하는 또 다른 패키지입니다. 이 패키지에는 토큰에 대한 토큰 범위 지정 권한이 포함되어있어 API에 대한 세밀한 액세스가 가능합니다. 309 | 310 | ### JSON Web Token 311 | JSON Web Token은 토큰 기반 인증에 사용할 수있는 상당히 새로운 표준입니다. 내장 된 TokenAuthentication 체계와 달리 JWT 인증은 데이터베이스를 사용하여 토큰의 유효성을 검사 할 필요가 없습니다. [Blimp](https://github.com/GetBlimp)는 JWT 인증 클래스를 제공하는 [djangorestframework-jwt](https://github.com/GetBlimp/django-rest-framework-jwt) 패키지와 클라이언트가 사용자 이름과 비밀번호가 있는 JWT를 얻을 수 있는 메커니즘을 유지합니다. 312 | 313 | ### Hawk HTTP Authentication 314 | [HawkREST](https://hawkrest.readthedocs.io/en/latest/) 라이브러리는 [Mohawk](https://mohawk.readthedocs.io/en/latest/) 라이브러리를 기반으로 [Hawk](https://github.com/hueniverse/hawk)에서 서명 한 요청 및 응답을 API에서 사용할 수 있도록합니다. [Hawk](https://github.com/hueniverse/hawk)은 공유 키로 서명 된 메시지를 사용하여 두 당사자가 서로 안전하게 통신 할 수있게합니다. [HTTP MAC 액세스 인증](https://tools.ietf.org/html/draft-hammer-oauth-v2-mac-token-05) ([OAuth 1.0](https://oauth.net/core/1.0a/)의 일부를 기반으로 함)을 기반으로합니다. 315 | 316 | ### HTTP Signature 317 | HTTP 서명 (현재 [IETF 초안](https://datatracker.ietf.org/doc/draft-cavage-http-signatures/))은 HTTP 메시지에 대한 원본 인증 및 메시지 무결성을 달성하는 방법을 제공합니다. 많은 서비스에서 사용되는 [Amazon의 HTTP 서명 체계](http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html)와 유사하게 상태 비 저장 요청 별 인증을 허용합니다. [Elvio Toccalino](https://github.com/etoccalino/)는 사용하기 쉬운 HTTP 서명 인증 메커니즘을 제공하는 [djangorestframework-httpsignature](https://github.com/etoccalino/django-rest-framework-httpsignature) 패키지를 유지 관리합니다. 318 | 319 | ### Djoser 320 | [Djoser](https://github.com/sunscrapers/djoser) 라이브러리는 등록, 로그인, 로그 아웃, 비밀번호 재설정 및 계정 활성화와 같은 기본 작업을 처리하기 위한 일련의 보기를 제공합니다. 패키지는 custom 사용자 모델과 작동하며 토큰 기반 인증을 사용합니다. 이것은 Django 인증 시스템의 REST 구현을 사용할 준비가되었습니다. 321 | 322 | ### django-rest-auth 323 | [Django-rest-auth](https://github.com/Tivix/django-rest-auth) 라이브러리는 등록, 인증 (소셜 미디어 인증 포함), 비밀번호 재설정, 사용자 세부 정보 검색 및 업데이트 등을 위한 일련의 REST API 엔드포인트를 제공합니다. 이러한 API 엔드포인트를 사용하면 AngularJS, iOS, Android 및 기타 사용자는 사용자 관리를 위해 REST API를 통해 독립적으로 Django 백엔드 사이트와 통신 할 수 있습니다. 324 | 325 | ### django-rest-framework-social-oauth2 326 | [Django-rest-framework-social-oauth2](https://github.com/PhilipGarnero/django-rest-framework-social-oauth2) 라이브러리는 소셜 플러그인 (facebook, twitter, google 등)을 인증 시스템에 쉽게 통합하고 쉬운 oauth2 설정을 제공합니다. 이 라이브러리를 사용하면 외부 토큰 (예 : 페이스 북 액세스 토큰)을 기반으로 사용자를 인증하고 이러한 토큰을 "in-house" oauth2 토큰으로 변환하고 oauth2 토큰을 사용 및 생성하여 사용자를 인증 할 수 있습니다. 327 | 328 | ### django-rest-knox 329 | [Django-rest-knox](https://github.com/James1345/django-rest-knox) 라이브러리는 단일 페이지 응용 프로그램 및 모바일 클라이언트를 염두에 두고 기본 TokenAuthentication 체계보다 안전하고 확장 가능한 방식으로 토큰 기반 인증을 처리 할 수 있는 모델과 뷰를 제공합니다. 클라이언트 별 토큰 및 일부 다른 인증 (일반적으로 기본 인증)이 제공된 경우 생성하는 View, 토큰을 삭제 (서버 강제 로그 아웃 제공) 및 모든 토큰 삭제(사용자가 로그인 한 모든 클라이언트 로그 아웃) view를 제공합니다.). 330 | 331 | --- 332 | 333 | ## 추가 내용 (Token 등록 및 삭제) 334 | 335 | **`member_myuser`** 336 | ![](./images/token1.png) 337 | **`authtoken_token`** 338 | ![](./images/token2.png) 339 | **`postman`에서 토큰 생성** 340 | ![](./images/token3.png) 341 | 342 | `token`의 `user_id` 값은 `member_myuser`의 `id` 값으로 등록됩니다. 343 | postman에서 생성한 test5(username)의 `myuser`테이블에서의 id 값은 8이고, 해당 토큰값으로 `token`테이블을 비교해보면 `user_id`가 같은 것을 확인할 수 있습니다. 344 | 345 | `token` 삭제는 해당 토큰값의 계정으로 로그인해야 삭제가 가능합니다. 346 | 347 | ![](./images/token_delete.png) 348 | > `request.user`를 프린트해보면 `username`값이 조회됩니다. 349 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 14. Permissions.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Permissions 2 | 3 | --- 4 | _"Authentication or identification by itself is not usually sufficient to gain access to information or code. For that, the entity requesting access must have authorization."_ 5 | 6 | _"정보 또는 코드에 대한 액서스 권한을 얻으려면 일반적으로 인증이나 식별만으로는 충분하지 않습니다. 이를 위해서는 액서스를 요청하는 개체에 권한이 있어야합니다."_ 7 | 8 | _— Apple Developer Documentation_ 9 | 10 | --- 11 | 12 | ## Permissions 13 | [인증](http://www.django-rest-framework.org/api-guide/authentication/) 및 [제한](http://www.django-rest-framework.org/api-guide/throttling/)과 함께 사용 권한은 request에 액서스를 허용할지 또는 거부 할지를 결정합니다. 14 | 권한 검사는 다른 코드가 진행되기 전에 view의 맨 처음에 항상 실행됩니다. 권한 검사는 일반적으로 들어오는 request를 허용해야 하는지를 결정하기 위해 `request.user`및 `request.auth` 등록 정보의 인증 정보를 사용합니다. 15 | 권한은 다른 클래스의 사용자가 API의 다른 부분에 액서스 하는 것을 허용하거나 거부하는게 사용됩니다. 16 | 가장 간단한 사용 권한 스타일은 인증 된 사용자에게 멕서스를 허용하고 인증되지 않은 모든 사용자에 대한 엑서스를 거부하는 것입니다. 이것은 REST프레임워크의 `IsAuthenticated`클래스에 해당합니다. 17 | 약간 덜 엄격한 권한 스타일은 인증 된 사용자에게 모든 권한을 허용하지만 인증되지 않은 사용자에게는 읽기전용 권한을 허용하는 것입니다. 이것은 REST 프레임워크의 `IsAuthenticatedOrReadOnly` 클래스에 해당합니다. 18 | 19 | ### How permissions are determined 20 | REST 프레임워크의 권한은 항상 클래스 list로 정의됩니다. 21 | 뷰의 본문을 실행하기 전에 list의 각 권한이 검사됩니다. 권한 확인에 실패하면 `exceptions.PermissionDenied` 또는 `exceptions.NotAuthenticated` 예외가 발생하고 view 본문이 실행되지 않습니다. 22 | 권한 검사가 실패하면 다음 규칙에 따라 "403 Forbidden"또는 "401 Unauthorized"응답이 반환됩니다. 23 | 24 | - 요청이 성공적으로 인증되었지만 권한이 거부되었습니다. - HTTP 403 Forbidden 응답이 리턴됩니다. 25 | - 요청이 성공적으로 인증되지 않았고 최상위 우선 순위 인증 클래스는 `WWW-Authenticate` 헤더를 사용하지 않습니다. - HTTP 403 Forbidden 응답이 리턴됩니다. 26 | - 요청이 성공적으로 인증되지 않았고 최상위 우선 순위 인증 클래스는 `WWW-Authenticate` 헤더를 사용합니다. - 적절한 `WWW-Authenticate` 헤더가 있는 HTTP 401 Unauthorized 응답이 반환됩니다. 27 | 28 | ### Object level permissions 29 | REST 프레임워크 권한은 또한 오브젝트 레벨 권한 부여를 지원합니다. 개체 수준 권한은 사용자가 특정 개체(일반적으로 모델 인스턴스)에 대한 작업을 허용해야하는지 여부를 결정하는 데 사용됩니다. 30 | 객체 레벨 권한은 `.get_object()`가 호출 될 때 REST 프레임워크의 generic view에 의해 실행됩니다. 뷰 수준 권한과 마찬가지로, 사용자가 지정된 객체를 처리할 수 없는 경우 `exceptions.PermissionDenied` 예외가 발생합니다. 31 | 자신 만의 뷰를 작성하고 오브젝트 레벨 권한을 적용하려는 경우 또는 generic 뷰에서 `get_object` 메소드를 겹쳐 쓰는 경우에는, 개체를 검색 한 시점에서 뷰에서 `.check_object_permissions(request, obj)` 메소드를 명시적으로 호출해야합니다. 32 | `PermissionDenied` 또는 `NotAuthenticated` 예외가 발생하거나 view에 적절한 권한이 있는 경우 반환됩니다. 33 | 예: 34 | 35 | ```python 36 | def get_object(self): 37 | obj = get_object_or_404(self.get_queryset()) 38 | self.check_object_permissions(self.request, obj) 39 | return obj 40 | ``` 41 | #### Limitations of object level permissions(개체 수준 사용 권한의 제한 사항) 42 | 성능 상의 이유로 generic view는 오브젝트 목록을 리턴 할 때 queryset의 각 인스턴스에 오브젝트 레벨 권한을 자동으로 적용하지 않습니다. 43 | 객체 레벨 권한을 사용하는 경우 종종 [쿼리 세트를 적절히 필터링](http://www.django-rest-framework.org/api-guide/filtering/)하여 사용자가 볼 수있는 인스턴스에 대한 가시성만 확보하도록 하는 것이 좋습니다. 44 | 45 | ### Setting the permission policy 46 | 기본 권한 정책은 `DEFAULT_PERMISSION_CLASSES` 설정을 사용하여 전역으로 설정할 수 있습니다. 예를 들면. 47 | 48 | ```python 49 | REST_FRAMEWORK = { 50 | 'DEFAULT_PERMISSION_CLASSES': ( 51 | 'rest_framework.permissions.IsAuthenticated', 52 | ) 53 | } 54 | ``` 55 | 지정하지 않으면이 설정은 기본적으로 무제한 액세스를 허용합니다. 56 | 57 | ```python 58 | 'DEFAULT_PERMISSION_CLASSES': ( 59 | 'rest_framework.permissions.AllowAny', 60 | ) 61 | ``` 62 | 또한 `APIView` CBV를 사용하여 view 별 또는 view 별 기준별로 인증 정책을 설정할 수 있습니다. 63 | 64 | ```python 65 | from rest_framework.permissions import IsAuthenticated 66 | from rest_framework.response import Response 67 | from rest_framework.views import APIView 68 | 69 | class ExampleView(APIView): 70 | permission_classes = (IsAuthenticated,) 71 | 72 | def get(self, request, format=None): 73 | content = { 74 | 'status': 'request was permitted' 75 | } 76 | return Response(content) 77 | ``` 78 | 또는 FBV와 함께 @api_view` 데코레이터를 사용하는 경우. 79 | 80 | ```python 81 | from rest_framework.decorators import api_view, permission_classes 82 | from rest_framework.permissions import IsAuthenticated 83 | from rest_framework.response import Response 84 | 85 | @api_view(['GET']) 86 | @permission_classes((IsAuthenticated, )) 87 | def example_view(request, format=None): 88 | content = { 89 | 'status': 'request was permitted' 90 | } 91 | return Response(content) 92 | ``` 93 | **Note**: 클래스 속성이나 데코레이터를 통해 새 권한 클래스를 설정하면 **settings.py** 파일을 통해 설정된 기본 목록을 무시하도록 뷰에 지시합니다. 94 | 95 | --- 96 | 97 | ## API Reference 98 | ### AllowAny 99 | `AllowAny` 권한 클래스는 **요청이 인증되었거나 인증되지 않았는지 여부에 관계없이** 제한되지 않은 액세스를 허용합니다. 100 | 사용 권한 설정에 빈 목록이나 튜플을 사용하여 동일한 결과를 얻을 수 있기 때문에 이 사용 권한은 반드시 필요한 것은 아니지만 의도를 명시적으로 지정하기 때문에 이 클래스를 지정하는 것이 유용 할 수 있습니다. 101 | 102 | ### IsAuthenticated 103 | `IsAuthenticated` 권한 클래스는 인증되지 않은 사용자에게 권한을 거부하고 그렇지 않은 경우에는 권한을 허용합니다. 104 | 이 권한은 등록 된 사용자만 API에 액세스 할 수 있게 하려는 경우 적합합니다. 105 | 106 | ### IsAdminUser 107 | `IsAdminUser` 권한 클래스는 `user.is_staff`가 `True` 인 경우를 제외하고 모든 사용자에 대한 사용 권한을 거부합니다. 108 | 109 | 이 권한은 신뢰할 수 있는 관리자의 하위 집합에서만 API에 액세스 할 수 있게 하려는 경우 적합합니다. 110 | 111 | ### IsAuthenticatedOrReadOnly 112 | `IsAuthenticatedOrReadOnly`를 사용하면 인증 된 사용자가 모든 요청을 수행 할 수 있습니다. 113 | 권한이 없는 사용자에 대한 요청은 요청 방법이 **"안전한"**방법 중 하나일 경우에만 허용됩니다. `GET`, `HEAD` 또는 `OPTIONS`. 114 | 이 권한은 API에서 익명 사용자에게 읽기 권한을 허용하고 인증 된 사용자에게만 쓰기 권한을 허용하려는 경우에 적합합니다. 115 | 116 | ### DjangoModelPermissions 117 | 이 퍼미션 클래스는 Django의 표준 `django.contrib.auth` [모델 퍼미션](https://docs.djangoproject.com/en/1.10/topics/auth/customizing/#custom-permissions)과 관련이 있습니다. 이 권한은 `.queryset` 속성이 설정된 view에만 적용해야합니다. 권한 부여는 사용자가 인증되고 관련 모델 권한이 할당 된 경우에만 부여됩니다. 118 | 119 | - `POST` request를 사용하려면 사용자에게 모델에 대한 `add` 권한이 있어야합니다. 120 | - `PUT` 및 `PATCH` request는 사용자가 모델에 대한 변경 권한을 요구합니다. 121 | - `DELETE` request는 사용자에게 모델에 대한 삭제 권한이 있어야합니다. 122 | 123 | 기본 동작을 재정의하여 사용자 지정 모델 권한을 지원할 수도 있습니다. 예를 들어 `GET` 요청에 대한 view 모델 권한을 포함 할 수 있습니다. 124 | custom 모델 권한을 `DjangoModelPermissions`을 오버라이드하고 `.perms_map` property를 설정하여 사용합니다. 125 | 126 | #### Using with views that do not include a queryset attribute. (queryset 속성을 포함하지 않는 뷰를 사용할 때) 127 | 재정의 된 `get_queryset()` 메서드를 사용하는 뷰에서 이 권한을 사용하는 경우 뷰에 `queryset` 속성이 없을 수 있습니다. 이 경우에는 sentinel queryset으로 뷰를 표시하여 이 클래스가 필요한 권한을 결정할 수 있도록하는 것이 좋습니다. 예 : 128 | 129 | ``` 130 | queryset = User.objects.none() # Required for DjangoModelPermissions 131 | ``` 132 | 133 | ### DjangoModelPermissionsOrAnonReadOnly 134 | `DjangoModelPermissions`와 유사하지만 인증되지 않은 사용자는 API에 대한 읽기 전용 액세스만 허용합니다. 135 | 136 | ### DjangoObjectPermissions 137 | 이 퍼미션 클래스는 모델에 대한 객체 별 권한을 허용하는 Django의 표준 [객체 권한 프레임워크](https://docs.djangoproject.com/en/1.10/topics/auth/customizing/#handling-object-permissions)와 관련이있다. 이 권한 클래스를 사용하려면 [`django-guardian`](https://github.com/django-guardian/django-guardian)과 같은 객체 수준 권한을 지원하는 권한 백엔드를 추가해야합니다. 138 | `DjangoModelPermissions`와 마찬가지로 이 권한은 `.queryset` 속성이나 `.get_queryset()` 메소드가 있는 뷰에만 적용되어야합니다. 권한 부여는 사용자가 인증되고 관련 객체 별 권한 및 관련 모델 권한이 할당 된 경우에만 부여됩니다. 139 | 140 | - `POST` request는 사용자에게 모델 인스턴스에 대한 추가 권한이 필요합니다. 141 | - `PUT` 및 `PATCH` request는 사용자가 모델 인스턴스에 대한 변경 권한을 요구합니다. 142 | - `DELETE` 요청은 사용자에게 모델 인스턴스에 대한 삭제 권한이 있어야합니다. 143 | 144 | `DjangoObjectPermissions`는 `django-guardian` 패키지를 **필요로 하지 않으며** 다른 객체 레벨 백엔드도 똑같이 잘 지원해야합니다. 145 | `DjangoModelPermissions`와 마찬가지로 `DjangoObjectPermissions`를 재정의하고 `.perms_map` 속성을 설정하여 사용자 정의 모델 권한을 사용할 수 있습니다. 자세한 내용은 소스 코드를 참조하십시오. 146 | 147 | --- 148 | **Note**: `GET`, `HEAD` 및 `OPTIONS` request에 대한 객체 수준 view 권한이 필요하면 `DjangoObjectPermissionsFilter` 클래스를 추가하여 목록 엔드포인트가 사용자에게 적절한 뷰 권한이 있는 객체를 포함하여 결과만 반환하도록 해야합니다. 149 | 150 | --- 151 | 152 | ## Custom permissions 153 | Custom 권한을 구현하려면, `BasePermission`를 무시하고 다음 중 하나 또는 두가지 방법을 구현합니다. 154 | 155 | - `.has_permission(self, request, view)` 156 | - `.has_object_permission(self, request, view, obj) ` 157 | 158 | request에 액세스 권한이 부여되면 메서드는 `True`를 반환하고 그렇지 않으면 `False`를 반환해야합니다. 159 | request가 읽기 작업인지 쓰기 작업인지 테스트해야하는 경우 `'GET'`, `'OPTIONS'`및 `'HEAD'`가 포함 된 튜플 인 `SAFE_METHODS` 상수와 비교하여 request 메소드를 확인해야합니다. 예: 160 | 161 | ```python 162 | if request.method in permissions.SAFE_METHODS: 163 | # 읽기 전용 액세스 권한을 확인하려면 164 | else: 165 | # 쓰기 액세스 권한을 확인하려면 166 | ``` 167 | 168 | --- 169 | **Note**: 뷰 수준 `has_permission` 검사가 이미 통과 된 경우에만 인스턴스 수준의 `has_object_permission` 메소드가 호출됩니다. 또한 인스턴스 수준 검사를 실행하려면 view 코드에서 `.check_object_permissions(request, obj)`를 명시적으로 호출해야 합니다. generic view를 사용하는 경우 기본적으로 이 옵션이 처리됩니다. 170 | 171 | --- 172 | 173 | 테스트가 실패 할 경우 custom 권한은 `PermissionDenied` 예외를 발생시킵니다. 예외와 관련된 오류 메시지를 변경하려면 custom 권한에 직접 `massege` 속성을 구현하십시오. 그렇지 않으면 `PermissionDenied`의 `default_detail` 속성이 사용됩니다. 174 | 175 | ```python 176 | from rest_framework import permissions 177 | 178 | class CustomerAccessPermission(permissions.BasePermission): 179 | message = 'Adding customers not allowed.' 180 | 181 | def has_permission(self, request, view): 182 | ... 183 | ``` 184 | 185 | ### Examples 186 | 다음은 들어오는 request의 IP 주소를 블랙리스트와 대조하여 IP가 블랙리스트에 올랐으면 request를 거부하는 권한 클래스의 예입니다. 187 | 188 | ```python 189 | from rest_framework import permissions 190 | 191 | class BlacklistPermission(permissions.BasePermission): 192 | """ 193 | Global permission check for blacklisted IPs. 194 | """ 195 | 196 | def has_permission(self, request, view): 197 | ip_addr = request.META['REMOTE_ADDR'] 198 | blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists() 199 | return not blacklisted 200 | ``` 201 | 들어오는 모든 request에 ​​대해 실행되는 전역 권한뿐 아니라 특정 개체 인스턴스에 영향을 주는 작업에 대해서만 실행되는 개체 수준 사용 권한을 만들 수도 있습니다. 예 : 202 | 203 | ```python 204 | class IsOwnerOrReadOnly(permissions.BasePermission): 205 | """ 206 | Object-level permission to only allow owners of an object to edit it. 207 | Assumes the model instance has an `owner` attribute. 208 | """ 209 | 210 | def has_object_permission(self, request, view, obj): 211 | # 읽기 권한은 모든 요청에 ​​허용되며, 212 | # 그래서 GET, HEAD, OPTIONS 요청을 허용 할 것입니다. 213 | if request.method in permissions.SAFE_METHODS: 214 | return True 215 | 216 | # 인스턴스에는`owner`라는 속성이 있어야합니다. 217 | return obj.owner == request.user 218 | ``` 219 | generic view는 적절한 개체 수준 사용 권한을 검사하지만 custom view를 작성하는 경우 개체 수준 사용 권한 검사를 직접 확인해야합니다. 객체 인스턴스가 있으면 뷰에서 `self.check_object_permissions(request, obj)`를 호출하여 그렇게 할 수 있습니다. 개체 수준의 권한 체크가 실패했을 경우,이 호출은 적절한 `APIException`을 송출하고, 그렇지 않은 경우는 단순히 반환됩니다. 220 | 또한 generic view는 단일 모델 인스턴스를 검색하는 뷰의 오브젝트 레벨의 권한만을 체크합니다. 221 | 목록 뷰의 개체 수준 필터링이 필요한 경우는 별도로 쿼리 세트를 필터링해야합니다. 자세한 내용은 [filtering documentation](http://www.django-rest-framework.org/api-guide/filtering/) 참조 222 | 223 | ## Third party packages 224 | 다음 타사 패키지도 제공됩니다. 225 | 226 | ### Composed Permissions 227 | [Composed Permissions](https://github.com/niwinz/djangorestframework-composed-permissions) 패키지는 작고 재사용 가능한 구성 요소를 사용하여 (논리 연산자를 사용하여) 복잡한 멀티 심도 권한 객체를 쉽게 정의하는 방법을 제공합니다. 228 | 229 | ### REST Condition 230 | [REST Condition](https://github.com/caxap/rest_condition) 패키지는 복잡한 권한을 쉽고 편리하게 구축하기 위한 또 다른 확장 기능입니다. 확장 기능을 사용하면 권한을 논리 연산자와 결합 할 수 있습니다. 231 | 232 | ### DRY Rest Permissions 233 | [DRY Rest Permissions](https://github.com/dbkaplan/dry-rest-permissions) 패키지는 개별 기본 및 custom 액션에 대해 서로 다른 권한을 정의하는 기능을 제공합니다. 이 패키지는 응용 프로그램의 데이터 모델에 정의 된 관계에서 파생 된 권한을 가진 애플리케이션 용으로 만들어져 있습니다. 또한 API serializer를 통해 클라이언트 응용 프로그램에 반환되는 권한 검사도 지원하고 있습니다. 또한 사용자마다 취득하는 데이터를 제한하기 위해 기본 및 custom 목록 액션에 권한을 추가도 지원합니다. 234 | 235 | ### Django Rest Framework Roles 236 | [Django Rest Framework Roles](https://github.com/computer-lab/django-rest-framework-roles) 패키지를 사용하면 여러 유형의 사용자에 대해 API를 쉽게 매개 변수화 할 수 있습니다. 237 | 238 | ### Django Rest Framework API Key 239 | [Django Rest Framework API Key](https://github.com/manosim/django-rest-framework-api-key) 패키지를 사용하면 서버에 대한 모든 요청에 ​​API 키 헤더가 필요함을 확인할 수 있습니다. 당신은 django 관리 인터페이스에서 생성 할 수 있습니다. 240 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 15. Throttling.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Throttling 2 | 3 | --- 4 | 5 | _"HTTP/1.1 420 Enhance Your Calm"_ 6 | 7 | _Twitter API rate limiting response_ 8 | 9 | --- 10 | 11 | ## Throttling (제한) 12 | Throttling은 request가 승인되어야하는지 여부를 결정한다는 점에서 permissions와 유사합니다. Throttling은 임시상태를 나타내며 클라이언트가 API에 대해 수행 할 수 있는 request 빈도수를 제어하는데 사용됩니다. 13 | permissions과 마찬가지로, 여러 Throttle을 사용할 수 있습니다. API에는 인증되지 않은 요청에 대해 제한적으로 Throttle과 인증 된 요청에 대한 제한적인 Throttle이 있을 수 있습니다. 14 | 특정 서비스가 특히 리소스를 잡아먹기 때문에 API의 다양한 부분에 다른 제약을 부과해야하는 경우, 여러 throttle을 사용하는 다른 시나리오가 있습니다. 15 | 버스트 빈도수 제한와 지속적인 빈도수 제한을 동시에 적용하려는 경우, 여러 throttle을 사용할 수 있습니다. 예를 들어, 분당 최대 60개의 요청과 하루에 1000개의 요청으로 사용자를 제한 할 수 있습니다. 16 | throttle은 반드시 rate 제한 요청을 참조하는 것은 아닙니다. 예를 들어, 스토리지 서비스는 대역폭에 대해 조정해야 할 수고 있으며, 유료 데이터 서비스는 액서스되는 특정 레코드 수에 대해 조정할 수 있습니다. 17 | 18 | ### How throttling is determined 19 | 사용 권한 및 인증과 마찬가지로 REST 프레임워크의 Throttling은 항상 클래스 목록으로 정의됩니다. 20 | 뷰의 본문을 실행하기 전에 list의 각 throttle이 점검됩니다. throttle 확인이 실패하면 `exceptions.Throttled`예외가 발생하고, 뷰 본문은 실행되지 않습니다. 21 | 22 | ### Setting the throttling policy 23 | 기본 throttling 정책은 `DEFAULT_THROTTLE_CLASSES`와 `DEFAULT_THROTTLE_RATES` 설정을 사용하여 전역으로 설정할 수 있습니다. 예를 들면. 24 | 25 | ```python 26 | REST_FRAMEWORK = { 27 | 'DEFAULT_THROTTLE_CLASSES': ( 28 | 'rest_framework.throttling.AnonRateThrottle', 29 | 'rest_framework.throttling.UserRateThrottle' 30 | ), 31 | 'DEFAULT_THROTTLE_RATES': { 32 | 'anon': '100/day', 33 | 'user': '1000/day' 34 | } 35 | } 36 | ``` 37 | `DEFAULT_THROTTLE_RATES`에 사용 된 rate에는 throttle 기간으로 `second`, `minute`, `hour`, `day`이 포함 될 수 있습니다. 38 | 또한 APIView CBV를 사용하여 뷰 단위 또는 뷰 단위별 조절 정책을 설정할 수 있습니다. 39 | 40 | ```python 41 | from rest_framework.response import Response 42 | from rest_framework.throttling import UserRateThrottle 43 | from rest_framework.views import APIView 44 | 45 | class ExampleView(APIView): 46 | throttle_classes = (UserRateThrottle,) 47 | 48 | def get(self, request, format=None): 49 | content = { 50 | 'status': 'request was permitted' 51 | } 52 | return Response(content) 53 | ``` 54 | 또는 FBV와 함께 `@api_view`데코레이터를 사용하는 경우 55 | 56 | ```python 57 | @api_view(['GET']) 58 | @throttle_classes([UserRateThrottle]) 59 | def example_view(request, format=None): 60 | content = { 61 | 'status': 'request was permitted' 62 | } 63 | return Response(content) 64 | ``` 65 | 66 | ### How clients are identified(클라이언트 식별 방법) 67 | `X-Forwarded_For`와 `Remote-Addr` HTTP 헤더는 throttling을 위해 클라이언트 IP주소를 고유하게 식별하는데 사용됩니다. 68 | `X-Forwarded_For`헤더가 있으면 사용되고, 없으면 `Remote-Addr` 헤더 값이 사용됩니다. 69 | 고유한 클라이언트 IP주소를 엄격하게 식별해야하는 경우, 우선 `NUM-PROXIES`설정을 하여 API가 실행되는 응용 프로그램 프록시의 수를 구성해야 합니다. 이 설정은 0 이상의 정수이어야 합니다. 0 이 아닌 값으로 설정된 경우, 클라이언트 IP는 응용 프로그램 프록시 IP 주소가 먼저 제외되면 `X-Forwarded-For` 헤더의 마지막 IP 주소로 식별됩니다. 0 으로 설정하면 `Remote-Addr`헤더가 항상 식별 IP주소로 사용됩니다. 70 | `NUM_PROXIES`설정을 구성하면 고유한 `NAT'd` 게이트웨이 뒤에 있는 모든 클라이언트가 단일 클라이언트로 처리 된다는 것을 이해하는 것이 중요합니다. 71 | `X-Forwarded-For`헤더의 작동 방식 및 원격 클라이언트 IP 식별 방법에 대한 자세한 내용은 [여기](http://oxpedia.org/wiki/index.php?title=AppSuite:Grizzly#Multiple_Proxies_in_front_of_the_cluster)를 참조하세요. 72 | 73 | ### Setting up the cache 74 | REST 프레임워크가 제공하는 throttle 클래스는 Django의 캐시 백엔드를 사용합니다. 적절한 [캐시 설정](https://docs.djangoproject.com/en/1.10/ref/settings/#caches)을 지정했는지 확인해야합니다. `LocMemCache`백엔드의 기본값은 간단한 설정으로 괜찮습니다. 자세한 내용은 [cache documentation](https://docs.djangoproject.com/en/1.10/topics/cache/#setting-up-the-cache)을 참조하세요. 75 | `default`가 아닌 캐시를 사용해야하는 경우, custom throttle 클래스를 만들고 캐시 속성을 설정하면 됩니다. 예를 들어: 76 | 77 | ```python 78 | class CustomAnonRateThrottle(AnonRateThrottle): 79 | cache = get_cache('alternate') 80 | ``` 81 | `DEFAULT_THROTTLE_CLASSES` 설정 키 또는 `throttle_classes` 뷰 속성을 사용하여 custom throttle 클래스를 기억해야만 합니다. 82 | 83 | ## API Reference 84 | 85 | ### AnonRateThrottle 86 | `AnonRateThrottle`은 인증되지 않은 사용자만 차단합니다. 들어오는 request의 IP 주소는 제한할 고유 키를 생성하는데 사용됩니다. 87 | 허용 된 request 등급은 다음 중 하나(선호도순)로 결정됩니다. 88 | 89 | - 클래스의 `rate` property는 `AnonRateThrottle`을 오버라이드하고 property를 설정하여 제공 될 수 있다. 90 | - `DEFAULT_THROTTLE_RATES ['anon']` 설정입니다. 91 | 92 | `AnonRateThrottle`는 알 수 없는 출처에서의 request의 빈도수를 제한하려는 경우에 적합합니다. 93 | 94 | ### UserRateThrottle 95 | `UserRateThrottle`은 API를 통해 주어진 request rate로 사용자를 제한합니다. user ID는 제한할 고유 키를 생성하는데 사용됩니다. 인증되지 않은 request는 들어오는 request의 IP 주소에 고유한 제한 키를 다시 생성하여 걸러냅니다. 96 | 허용 된 request rate는 다음 중 하나(선호도 순)로 결정됩니다. 97 | 98 | - 클래스의 `rate`속성은 `UserRateThrottle`을 오버라이드하고 property를 설정하여 제공 될 수 있습니다. 99 | - `DEFAULT_THROTTLE_RATES ['anon']` 설정입니다. 100 | 101 | API에는 동시에 여러 `UserRAteThrottles`이 있을 수 있습니다. 이렇게 하려면 `UserRateThrottle`을 무시하고 각 클래스에 대해 고유한 `scope`(범위)를 설정하세요. 102 | 예를 들어, 여러 사용자 throttle rate는 다음 클래스를 사용하여 구현할 수 있습니다. 103 | 104 | ```python 105 | class BurstRateThrottle(UserRateThrottle): 106 | scope = 'burst' 107 | 108 | class SustainedRateThrottle(UserRateThrottle): 109 | scope = 'sustained' 110 | ``` 111 | ...그리고 다음 설정입니다. 112 | 113 | ```python 114 | REST_FRAMEWORK = { 115 | 'DEFAULT_THROTTLE_CLASSES': ( 116 | 'example.throttles.BurstRateThrottle', 117 | 'example.throttles.SustainedRateThrottle' 118 | ), 119 | 'DEFAULT_THROTTLE_RATES': { 120 | 'burst': '60/min', 121 | 'sustained': '1000/day' 122 | } 123 | } 124 | ``` 125 | `UserRateThrottle`은 사용자별로 간단한 전역 rate를 원할 때 적합합니다. 126 | 127 | ### ScopedRateThrottle 128 | `ScopeRateThrottle`클래스를 사용하여 API의 특정 부분에 대한 액서스를 제한 할 수 있습니다. 이 throttle은 액서스되는 뷰에 `.throttle_scope`속성이 포함 된 경우에만 적용됩니다. 고유한 throttle 키는 request의 "scope"를 고유한 user ID 또는 IP 주소와 연결하여 형성합니다. 129 | 허용 된 request rate는 request "scope"의 키를 사용하여 `DEFAULT_THROTTLE_RATES`설정에 의해 결정됩니다. 130 | 예를 들어, 다음의 뷰가 주어진 경우... 131 | 132 | ```python 133 | class ContactListView(APIView): 134 | throttle_scope = 'contacts' 135 | ... 136 | 137 | class ContactDetailView(APIView): 138 | throttle_scope = 'contacts' 139 | ... 140 | 141 | class UploadView(APIView): 142 | throttle_scope = 'uploads' 143 | ... 144 | ``` 145 | ...그리고 다음 설정입니다. 146 | 147 | ```python 148 | REST_FRAMEWORK = { 149 | 'DEFAULT_THROTTLE_CLASSES': ( 150 | 'rest_framework.throttling.ScopedRateThrottle', 151 | ), 152 | 'DEFAULT_THROTTLE_RATES': { 153 | 'contacts': '1000/day', 154 | 'uploads': '20/day' 155 | } 156 | } 157 | ``` 158 | `ContactListView` 또는 `ContactDetailView`에 대한 사용자 요청은 하루에 총 1000 개의 요청으로 제한됩니다. `UploadView`에 대한 사용자 요청은 하루에 20 건으로 제한됩니다. 159 | 160 | ## Custom throttles 161 | custom throttle을 만들려면 `BaseThrottle`을 재정의하고 `.allow_request(self, request, view)`를 구현하십시오. 이 메소드는 요청을 허용해야하는 경우 `True`를 반환하고 그렇지 않으면 `False`를 반환해야합니다. 162 | 선택적으로 `.wait()` 메서드를 재정의 할 수도 있습니다. 구현 된 경우 `.wait()`는 다음 요청을 시도하기 전에 기다리는 권장 시간(초)을 반환하거나 `None`을 반환해야합니다. `.wait()` 메서드는 `.allow_request()`가 이전에 `False`를 반환 한 경우에만 호출됩니다. 163 | `.wait()` 메서드가 구현되고 요청이 제한되면 `Retry-After` 헤더가 응답에 포함됩니다. 164 | 165 | ### Example 166 | 다음은 10의 요청마다 1을 무작위로 조절하는 rate throttle의 예입니다. 167 | 168 | ```python 169 | import random 170 | 171 | class RandomRateThrottle(throttling.BaseThrottle): 172 | def allow_request(self, request, view): 173 | return random.randint(1, 10) != 1 174 | ``` 175 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 17. Pagination.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Pagination 2 | 3 | --- 4 | 5 | _"Django provides a few classes that help you manage paginated data – that is, data that’s split across several pages, with “Previous/Next” links."_ 6 | 7 | _"Django는 페이지가 매겨진 데이터, 즉 "이전 / 다음" 링크를 사용하여 여러 페이지로 나누어 진 데이터를 관리하는데 도움이 되는 몇가지 클래스를 제공합니다."_ 8 | 9 | _— Django documentation_ 10 | 11 | --- 12 | 13 | ## Pagination 14 | 15 | REST 프레임워크는 custom 가능한 pagination 스타일을 지원합니다. 이렇게 하면 큰 result sets을 개별 데이터 페이지로 분할하는 방법을 수정할 수 있습니다. 16 | 17 | pagination API는 다음 중 하나를 지원할 수 있습니다. 18 | 19 | - resopnse 내용의 일부로 제공되는 pagination 링크 20 | - `Content-Range` 또는 `Link`와 같은 response header에 포함 된 pagination 링크 21 | 22 | 내장된 스타일은 현재 response 내용의 일부로 포함된 링크를 사용합니다. 이 스타일은 browsable API를 사용할 때 더 쉽게 액서스 할 수 있습니다. 23 | pagination은 generic view 또는 viewset를 사용하는 경우에만 자동으로 수행됩니다. 일반 `APIView`를 사용하는 경우 pagination 된 response를 반환하도록 pagination API를 직접 호출해야 합니다. 예를 들어, `mixins.ListModelMixin` 및 `generics.GenericAPIView` 클래스의 소스 코드를 참조하세요. 24 | pagination 클래스를 `None`으로 설정하면 pagination을 끌 수 있습니다. 25 | 26 | ### Setting the pagination style 27 | 기본 pagination 스타일은 `DEFAULT_PAGINATION_CLASS` 및 `PAGE_SIZE` 설정 키를 사용하여 전체적으로 설정할 수 있습니다. 예를 들어 내장 된 limit / offset pagination을 사용하려면 다음과 같이 하면 됩니다. 28 | 29 | ```python 30 | REST_FRAMEWORK = { 31 | 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', 32 | 'PAGE_SIZE': 100 33 | } 34 | ``` 35 | 36 | pagination 클래스와 사용할 페이지 크를 모두 설정해야 합니다. 37 | 38 | `pagination_class`속성을 사용하여 개별 view에서 pagination 클래스를 설정 할 수도 있습니다. 일반적으로 API 전체에서 동일한 pagination 스타일을 사용하고 싶지만 view마다 기본 페이지 또는 최대 페이지 크기가 같은 pagination의 개별적인 측면을 바꿀 수도 있습니다. 39 | 40 | ### Modifying the pagination style 41 | pagination 스타일의 특정 측면을 수정하려면 pagination 클래스 중 하나를 오버라이드하고 변경하려는 속성을 설정해야 합니다. 42 | 43 | ```python 44 | class LargeResultsSetPagination(PageNumberPagination): 45 | page_size = 1000 46 | page_size_query_param = 'page_size' 47 | max_page_size = 10000 48 | 49 | class StandardResultsSetPagination(PageNumberPagination): 50 | page_size = 100 51 | page_size_query_param = 'page_size' 52 | max_page_size = 1000 53 | ``` 54 | 그런 다음 `.pagination_class` 속성을 사용하여 뷰에 새 스타일을 적용 할 수 있습니다. 55 | 56 | ```python 57 | class BillingRecordsView(generics.ListAPIView): 58 | queryset = Billing.objects.all() 59 | serializer_class = BillingRecordsSerializer 60 | pagination_class = LargeResultsSetPagination 61 | ``` 62 | 또는 `DEFAULT_PAGINATION_CLASS` 설정 키를 사용하여 스타일을 전역적으로 적용하세요. 예: 63 | 64 | ```python 65 | REST_FRAMEWORK = { 66 | 'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination' 67 | } 68 | ``` 69 | 70 | --- 71 | 72 | ## API Reference 73 | 74 | ### PageNumberPagination 75 | 이 pagination 스타일은 request 쿼리 parameter에 단일 숫자 페이지 번호를 허용합니다. 76 | 77 | **Request**: 78 | 79 | ``` 80 | GET https://api.example.org/accounts/?page=4 81 | ``` 82 | 83 | **Response**: 84 | 85 | ``` 86 | HTTP 200 OK 87 | { 88 | "count": 1023 89 | "next": "https://api.example.org/accounts/?page=5", 90 | "previous": "https://api.example.org/accounts/?page=3", 91 | "results": [ 92 | … 93 | ] 94 | } 95 | ``` 96 | 97 | #### Setup 98 | `PageNumberPagination`스타일을 전역적으로 사용하려면 다음 구성을 사용하여 `PAGE_SIZE`를 원하는대로 수정하세요. 99 | 100 | ```python 101 | REST_FRAMEWORK = { 102 | 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 103 | 'PAGE_SIZE': 100 104 | } 105 | ``` 106 | 107 | `GenericAPIView` 서브 클래스에서 `pagination_class`속성을 설정하여 페이지 단위로 `PageNumberPagination`을 선택할 수도 있습니다. 108 | 109 | #### Configuration (구성) 110 | `PageNumberPagination`클래스는 pagination 스타일을 수정하기 위해 오버라이드 될 수 있는 여러 속성을 포함합니다. 111 | 이러한 속성을 설정하려면 `PageNumberPagination`클래스를 오버라이드 한 다음 위와 같이 custom pagination 클래스를 활성화해야합니다. 112 | 113 | - `django_paginator_class` : 사용할 Django Paginator 클래스입니다. 기본값은 `django.core.paginator.Paginator`입니다. 대부분의 사용 사례에서 괜찮습니다. 114 | - `page_size` : 페이지 크기를 나타내는 숫자 값입니다. 설정된 경우 `PAGE_SIZE` 설정보다 우선합니다. 기본값은 `PAGE_SIZE` 설정 키와 동일한 값입니다. 115 | - `page_query_param` : pagination 컨트롤에 사용할 쿼리 parameter의 이름을 나타내는 문자열 값입니다. 116 | - `page_size_query_param` : 설정된 경우 클라이언트가 request 별로 페이지 크기를 설정할 수 있도록하는 쿼리 parameter의 이름을 나타내는 문자열 값입니다. 기본값은 `None`으로, 클라이언트가 요청 된 페이지 크기를 제어 할 수 없음을 나타냅니다. 117 | - `max_page_size` : 설정되면 request 된 최대 페이지 크기를 나타내는 숫자 값입니다. 이 속성은 `page_size_query_param`도 설정되어있는 경우에만 유효합니다. 118 | - `last_page_strings` : `page_query_param`과 함께 사용되어 최종 페이지를 요청할 수있는 값을 나타내는 문자열 값의 list 또는 tuple 입니다. 기본값은 `('last',)` 입니다. 119 | - `template` : browsable API에서 pagination 컨트롤을 렌더링 할 때 사용할 템플릿의 이름입니다. 렌더링 스타일을 수정하기 위해 오버라이드 되거나 HTML pagination 컨트롤을 완전히 비활성화하려면 `None`으로 설정 할 수 있습니다. 기본값은 `"rest_framework / pagination / numbers.html"`입니다. 120 | 121 | --- 122 | 123 | ### LimitOffsetPagination 124 | 이 pagination 스타일은 여러 데이터베이스 레코드를 찾을 때 사용되는 구문을 반영합니다. 클라이언트에는 "limit"와 "offset" 쿼리 parameter가 모두 포함됩니다. **limit** 는 반환 할 최대 항목 수를 나타내며 다른 스타일의 `page_size`와 같습니다. **offset**은 unpaginated 된 항목의 완성된 set과 관련하여 쿼리의 시작 위치를 나타냅니다. 125 | 126 | **Request**: 127 | 128 | ``` 129 | GET https://api.example.org/accounts/?limit=100&offset=400 130 | ``` 131 | 132 | **response**: 133 | 134 | ```python 135 | HTTP 200 OK 136 | { 137 | "count": 1023 138 | "next": "https://api.example.org/accounts/?limit=100&offset=500", 139 | "previous": "https://api.example.org/accounts/?limit=100&offset=300", 140 | "results": [ 141 | … 142 | ] 143 | } 144 | ``` 145 | 146 | #### Setup 147 | `LimitOffsetPagination` 스타일을 전역적으로 사용하려면 다음 구성을 사용하세요. 148 | 149 | ```python 150 | REST_FRAMEWORK = { 151 | 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination' 152 | } 153 | ``` 154 | 선택적으로 `PAGE_SIZE` 키를 설정 할 수도 있습니다. `PAGE_SIZE` parameter도 사용되는 경우 `limit` 쿼리 parameter는 선택사항이며 클라이언트가 생략할 수 있습니다. 155 | `GenericAPIView` 서브 클래스에서는 `pagination_class`속성을 설정하여 각 뷰별로 `LimitOffsetPagination`을 선택할 수 있습니다. 156 | 157 | #### Configuration 158 | `LimitOffsetPagination` 클래스에는pagination 스타일을 수정하기 위해 오버라이드 할 수 있는 많은 속성이 포함되어 있습니다. 159 | 이러한 속성을 설정하려면 `LimitOffsetPagination`클래스를 오버라이드 한 다음 위와 같이 custom pagination 클래스를 활성화해야 합니다. 160 | 161 | - `default_limit` : 쿼리 parameter에서 클라이언트가 제공하지 않을 경우 사용할 제한을 나타내는 숫자 값입니다. 기본값은 `PAGE_SIZE` 설정 키와 동일한 값입니다. 162 | - `limit_query_param` : "limit" 쿼리 parameter의 이름을 나타내는 문자열 값입니다. 기본값은 `'limit'`입니다. 163 | - `offset_query_param` : "offset" 쿼리 parameter의 이름을 나타내는 문자열 값입니다. 기본값은 `'offset'`입니다. 164 | - `max_limit` : 설정된 경우 클라이언트가 요청할 수있는 최대 허용 한계를 나타내는 숫자 값입니다. 기본값은 `None`입니다. 165 | - `template` : browsable API에서 페이지 매김 컨트롤을 렌더링 할 때 사용할 템플릿의 이름입니다. 렌더링 스타일을 수정하기 위해 오버라이드 되거나 HTML pagination 컨트롤을 완전히 비활성화하려면 `None`으로 설정 될 수 있습니다. 기본값은 `"rest_framework / pagination / numbers.html"`입니다. 166 | 167 | --- 168 | 169 | ### CursorPagination 170 | cursor 기반 pagination은 클라이언트가 result set를 통해 페이지 할 때 사용할 수 있는 불투명한 "cursor" 지시자를 제공합니다. 이 pagination 스타일은 정방향 및 역방향 컨트롤만 제공하며 클라이언트가 임의의 위치로 이동할 수 없도록 합니다. 171 | cursor를 기반으로 pagination을 수행하려면 result set에 items의 순서가 변경되지 않아야 합니다. 일반적으로 이 순서는 레코드에 대한 생성 timestamp 일 수 있습니다. 이는 pagination 순서를 일관되게 유지하기 때문입니다. 172 | cursor 기반 pagination은 다른 스키마보다 복잡합니다. 또한 result set이 고정 된 순서를 제공해야하며 클라이언트가 임의로 result set에 색인을 작성할 수 없도록 해야합니다. 그러나 다음과 같은 이점을 제공합니다. 173 | 174 | - 일관된 pagination 을 제공합니다. 제대로 사용하면 `CursorPagination`은 pagination 과정에서 다른 클라이언트가 새 항목을 삽입하는 경우에도 클라이언트가 레코드를 페이징 할 때 동일한 item을 두번 보지 못하게 합니다. 175 | - 매우 큰 데이터 set 사용을 지원합니다. 극도로 큰 데이터 set의 경우 offset 기반 pagination 스타일을 사용하는 pagination이 비효율적이거나 사용할 수 없게 될 수 있습니다. 대신 cursor 기반 pagination 스키마는 고정 시간 속성을 가지며 데이터 set 크기가 커질수록 속도가 느려지지 않습니다. 176 | 177 | #### Details and limitations 178 | cursor 기반의 pagination을 올바르게 사용하려면 세부 사항에 약간의 주의가 필요합니다. 우리는 계획을 적용하기를 원하는 순서에 대해 생각할 필요가 있습니다. 기본값은 `"-created"`입니다. 여기에는 모델 인스턴스에 **'created' timestamp 필드가 꼭 있어야하며** 가장 최근에 추가 된 항목이 먼저 나오는 "timeline" 스타일 pagination view가 제공됩니다. 179 | pagination 클래스의 `'ordering'`속성을 무시하거나 `OrderingFilter` 필터 클래스를 `CursorPagination`과 함께 사용하여 순서를 수정할 수 있습니다. `OrderingFilter`와 함께 사용하는 경우 사용자가 주문 할 수 있는 입력란을 제한하는 것이 좋습니다. 180 | 181 | 커서 pagination 을 올바르게 사용하려면 다음을 만족시키는 ordering 필드가 있어야 합니다. 182 | 183 | - 생성시 timestamp, slug 또는 한번만 설정되는 다른 필드와 같은 변경되지 않은 값이어야 합니다. 184 | - 고유하거나 거의 고유해야합니다. Millisecond 정밀도 timestamp가 좋은 예입니다. 이 cursor pagination의 구현은 똑똑한 "position plus offset"스타일을 사용하여 엄격하게 고유하지 않은 값을 순서대로 올바르게 지원할 수 있습니다. 185 | - null이 허용하지 않는 값이어야 합니다.(문자열로 강제 변환 될 수 있습니다.) 186 | - 필드에는 데이터베이스 색인이 있어야합니다. 187 | 188 | 이러한 제약 조건을 만족시키지 못하는 ordering field를 사용하면 일반적으로 작동하지만 cursor pagination의 이점을 일부 상실하게 됩니다. 189 | cursor pagination에 사용되는 구현에 대한 자세한 정보는 ["Building cursors for the Disqus API"](http://cramer.io/2011/03/08/building-cursors-for-the-disqus-api)블로그 게시물에서 기본 접근 방법에 대한 개요를 제공합니다. 190 | 191 | #### Setup 192 | `CursorPagination` 스타일을 전역적으로 사용하려면 다음 구성을 사용하여 `PAGE_SIZE`를 원하는대로 수정하십시오. 193 | 194 | ```python 195 | REST_FRAMEWORK = { 196 | 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination', 197 | 'PAGE_SIZE': 100 198 | } 199 | ``` 200 | `GenericAPIView` 서브 클래스에서 `pagination_class` 속성을 설정하여 뷰 단위로 `CursorPagination`을 선택할 수도 있습니다. 201 | 202 | #### Configuration 203 | `CursorPagination` 클래스에는 pagination 스타일을 수정하기 위해 오버라이드 될 수 있는 많은 속성이 포함되어 있습니다. 204 | 205 | 이러한 속성을 설정하려면 `CursorPagination`클래스를 오버라이드 한 다음 위와 같이 custom pagination 클래스를 활성화해야 합니다. 206 | 207 | - `page_size` : 페이지 크기를 나타내는 숫자 값입니다. 설정된 경우 `PAGE_SIZE` 설정보다 우선합니다. 기본값은 `PAGE_SIZE` 설정 키와 동일한 값입니다 208 | - `cursor_query_param` : "cursor" 쿼리 parameter의 이름을 나타내는 문자열 값입니다. 기본값은 `'cursor'`입니다. 209 | - `ordering` : cursor 기반의 pagiation이 적용될 필드를 나타내는 문자열 또는 문자열 list 이어야합니다. (예: `ordering = 'slug'`) 기본값은 `-created`입니다. 뷰에서 `OrderingFilter`를 사용하여 이 값을 오버라이드 할 수도 있습니다. 210 | - `template` : browsable API에서 pagination 컨트롤을 렌더링 할 때 사용할 템플릿의 이름입니다. 렌더링 스타일을 수정하기 위해 오버라이드 되거나 HTML pagination 컨트롤을 완전히 비활성화하려면 `None`으로 설정 될 수 있습니다. 기본값은 `"rest_framework/pagination/previous_and_next.html"`입니다. 211 | 212 | --- 213 | 214 | ## Custom pagination styles 215 | Custom pagination serializer 클래스를 생성하려면 `pagination.BasePagination`을 서브 클래스화하고 `paginate_queryset(self, queryset, request, view = None)` 및 `get_paginated_response(self, data)` 메소드를 오버라이드 해야합니다. 216 | 217 | - `paginate_queryset` 메소드는 초기 쿼리셋을 전달 받고 요청 된 페이지의 데이터만 포함하는 반복 가능한 객체를 반환해야합니다. 218 | - `get_paginated_response` 메소드는 serializer 된 페이지 데이터를 전달 받고 Response 인스턴스를 반환해야합니다. 219 | 220 | `paginate_queryset` 메소드는 페이지 설정 인스턴스에 상태를 설정할 수 있으며 나중에 `get_paginated_response` 메소드에서 사용할 수 있습니다. 221 | 222 | ### Example 223 | 기본 pagination output 스타일을 중첩 된 'links' 키 아래의 다음 링크와 이전 링크를 포함하는 수정된 형식으로 바꾸려한다고 가정합니다. 다음과 같이 custom pagination 클래스를 지정할 수 있습니다. 224 | 225 | ```python 226 | class CustomPagination(pagination.PageNumberPagination): 227 | def get_paginated_response(self, data): 228 | return Response({ 229 | 'links': { 230 | 'next': self.get_next_link(), 231 | 'previous': self.get_previous_link() 232 | }, 233 | 'count': self.page.paginator.count, 234 | 'results': data 235 | }) 236 | ``` 237 | 그런 다음 구성에서 custom 클래스를 설정해야합니다 238 | 239 | ```python 240 | REST_FRAMEWORK = { 241 | 'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.CustomPagination', 242 | 'PAGE_SIZE': 100 243 | } 244 | ``` 245 | browsable API의 response에서 키의 순서가 어떻게 표시되는지 신경 쓰면 pagination 된 response의 본문을 구성할 때 `OrderedDict`를 사용하도록 선택할 수 있지만 선택사항입니다. 246 | 247 | ### Header based pagination 248 | 내장 된 `PageNumberPagination` 스타일을 수정하여 response 본문에 pagination 링크를 포함하는 대신 [GitHub API와 비슷한 스타일](https://developer.github.com/guides/traversing-with-pagination/)로 `link` 헤더를 포함합니다. 249 | 250 | ```python 251 | class LinkHeaderPagination(pagination.PageNumberPagination): 252 | def get_paginated_response(self, data): 253 | next_url = self.get_next_link() 254 | previous_url = self.get_previous_link() 255 | 256 | if next_url is not None and previous_url is not None: 257 | link = '<{next_url}>; rel="next", <{previous_url}>; rel="prev"' 258 | elif next_url is not None: 259 | link = '<{next_url}>; rel="next"' 260 | elif previous_url is not None: 261 | link = '<{previous_url}>; rel="prev"' 262 | else: 263 | link = '' 264 | 265 | link = link.format(next_url=next_url, previous_url=previous_url) 266 | headers = {'Link': link} if link else {} 267 | 268 | return Response(data, headers=headers) 269 | ``` 270 | 271 | ### Using your custom pagination class 272 | custom pagination 클래스를 기본적으로 사용하려면 `DEFAULT_PAGINATION_CLASS` 설정을 사용하세요. 273 | 274 | ```python 275 | REST_FRAMEWORK = { 276 | 'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.LinkHeaderPagination', 277 | 'PAGE_SIZE': 100 278 | } 279 | ``` 280 | 이제 endpoint에 대한 API response에는 페이지 본문 링크를 response 본문의 일부로 포함하는 대신 `link`헤더가 포함됩니다. 281 | 282 | ### Pagination & schemas 283 | 또한 `coreapi.Field` 인스턴스의 list를 반환해야하는 `get_schema_fields()` 메소드를 구현하여 REST 프레임워크가 제공하는 스키마 자동 생성에서 pagination 컨트롤을 사용할 수 있게 만들 수 있습니다. 284 | 285 | --- 286 | 287 | ![](./images/linkheader.png) 288 | `link`헤더를 사용하는 custom pagination 스타일 289 | 290 | --- 291 | 292 | ## HTML pagination controls 293 | 294 | 기본적으로 pagination 클래스를 사용하면 browsable API에 HTML pagination 컨트롤이 표시됩니다. 두 가지 내장 디스플레이 스타일이 있습니다. `PageNumberPagination` 및 `LimitOffsetPagination` 클래스는 이전 및 다음 컨트롤이 포함 된 페이지 번호 목록을 표시합니다. `CursorPagination` 클래스는 이전 및 다음 컨트롤만 표시하는 보다 단순한 스타일을 표시합니다. 295 | 296 | ### Customizing the controls 297 | HTML pagination 컨트롤을 렌더링하는 템플릿을 오버라이드 할 수 있습니다. 두 가지 기본 제공 스타일은 다음과 같습니다. 298 | 299 | - rest_framework/pagination/numbers.html 300 | - rest_framework/pagination/previous_and_next.html 301 | 302 | 전역 템플릿 디렉토리에 이러한 경로 중 하나가 있는 템플릿을 제공하면 관련 pagination 클래스의 기본 렌더링이 무시됩니다. 303 | 또는 기존 클래스를 하위 클래스로 분류하고 클래스의 속성으로 `template = None`을 설정하여 HTML pagination 컨트롤을 완전히 비활성화 할 수 있습니다. 그런 다음 custom 클래스를 기본 pagination 스타일로 사용하려면 `DEFAULT_PAGINATION_CLASS` 설정 키를 구성해야합니다. 304 | 305 | #### Low-level API 306 | pagination 클래스가 컨트롤을 표시할지 어떨지를 결정하기 위한 저레벨의 API는, pagination 인스턴스의 `display_page_controls` 속성으로서 공개되고 있습니다. HTML pagination 컨트롤을 표시해야하는 경우 `paginate_queryset` 메서드에서 custom pagination 클래스를 `True`로 설정해야합니다. 307 | `.to_html()` 및 `.get_html_context()` 메소드는 컨트롤이 렌더링되는 방식을 추가로 custom하기 위해 custom pagination 클래스에서 오버라이드 될 수도 있습니다. 308 | 309 | ## Third party packages 310 | 다음의 타사 패키지도 제공됩니다. 311 | 312 | ### DRF-extensions 313 | [`DRF-extensions` 패키지](http://chibisov.github.io/drf-extensions/docs/)에는 [`PaginateByMaxMixin` mixin 클래스](http://chibisov.github.io/drf-extensions/docs/#paginatebymaxmixin)가 포함되어있어 API 클라이언트가 허용되는 최대 페이지 크기를 얻기 위해`?page_size=max`를 지정할 수 있습니다. 314 | 315 | ### drf-proxy-pagination 316 | [`drf-proxy-pagination` 패키지](https://github.com/tuffnatty/drf-proxy-pagination)는 쿼리 parameter로 pagination 클래스를 선택할 수 있는 `ProxyPagination` 클래스를 포함합니다. 317 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 18. Versioning.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Versioning 2 | 3 | --- 4 | 5 | _"Versioning an interface is just a "polite" way to kill deployed clients."_ 6 | 7 | _"인터페이스의 버전 관리는 배치 된 클라이언트를 죽이는 "정중한" 방법 일 뿐입니다."_ 8 | 9 | _— Roy Fielding._ 10 | 11 | --- 12 | 13 | ## Versioning (버전관리) 14 | API 버전 관리를 통해 서로 다른 클라이언트 간의 동작을 변경할 수 있습니다. REST 프레임워크는 다양한 버전 관리 체계를 제공합니다. 15 | 버전 지정은 수신 클라이언트 요청에 의해 결정되며 request URL을 기반으로하거나 request 헤더를 기반으로 할 수 있습니다. 16 | 버전 관리에 접근하는데는 여러가지 유효한 방법이 있습니다. 특히 버전을 벗어난 여러 클라이언트를 가진 매우 장기적인 시스템을 엔지니어링하는 경우에는 [버전이 없는 시스템도 적합](https://www.infoq.com/articles/roy-fielding-on-versioning)할 수 있습니다. 17 | 18 | ### Versioning with REST framework 19 | API 버전 관리가 활성화되면 `request.version`속성에는 들어오는 클라이언트 request에서 요청 된 버전에 해당하는 문자열이 포함됩니다. 20 | 기본적으로 버전 관리는 활성화되어있지 않으며 `request.version`은 항상 `None`을 반환합니다. 21 | 22 | #### Varying behavior based on the version 23 | API동작을 변경하는 방법은 우리에게 달려있지만 일반적인 한가지 예는 최신 버전의 다른 serializer 스타일로 전환하는 것입니다. 예: 24 | 25 | ```python 26 | def get_serializer_class(self): 27 | if self.request.version == 'v1': 28 | return AccountSerializerVersion1 29 | return AccountSerializer 30 | ``` 31 | 32 | #### Reversing URLs for versioned APIs 33 | REST 프레임워크에 포함 된 역순 함수는 버전 관리체계와 관련되어 있습니다. 현재 request를 키워드 인수로 포함시켜야 합니다. 34 | 35 | ```python 36 | from rest_framework.reverse import reverse 37 | 38 | reverse('bookings-list', request=request) 39 | ``` 40 | 위의 함수는 요청 버전에 적합한 모든 URL 변환을 적용합니다. 예: 41 | 42 | - `NamespacedVersioning`이 사용되고 API 버전이 'v1'인 경우 사용 된 URL 조회는 `http://example.org/v1/bookings/`과 같은 URL로 해석 될 수있는 `'v1 : bookings-list'`입니다. 43 | - `QueryParameterVersioning`이 사용되고 API 버전이 `1.0` 인 경우 반환 된 URL은 `http://example.org/bookings/?version=1.0`과 같을 수 있습니다. 44 | 45 | #### Versioned APIs and hyperlinked serializers 46 | 하이퍼 링크 된 serializer 스타일을 URL 기반 버전 관리 scheme와 함께 사용하는 경우 해당 요청을 컨텍스트로 serializer에 포함해야 합니다. 47 | 48 | ```python 49 | def get(self, request): 50 | queryset = Booking.objects.all() 51 | serializer = BookingsSerializer(queryset, many=True, context={'request': request}) 52 | return Response({'all_bookings': serializer.data}) 53 | ``` 54 | 이렇게 하면 반환 된 모든 URL에 적절한 버전이 포함될 수 있습니다. 55 | 56 | ### Configuring the versioning scheme 57 | 버전 관리 scheme는 `DEFAULT_VERSIONING_CLASS`설정 키로 정의됩니다. 58 | 59 | ```python 60 | REST_FRAMEWORK = { 61 | 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning' 62 | } 63 | ``` 64 | 명시적으로 설정하지 않으면 `DEFAULT_VERSIONING_CLASS`의 값은 `None`이 됩니다. 이 경우 `request.version` 속성은 항상 `None`을 반환합니다. 65 | 개별 view에서 versioning scheme를 설정할 수도 있습니다. 일반적으로 전역적으로 single versioning scheme를 사용하는 것이 더 합리적이므로 이 작업을 수행할 필요가 없습니다. 그렇게 해야한다면 `versioning_class` 속성을 사용하세요. 66 | 67 | ```python 68 | class ProfileList(APIView): 69 | versioning_class = versioning.QueryParameterVersioning 70 | ``` 71 | 72 | #### Other versioning settings 73 | 다음 설정 키는 versioning를 제어하는데도 사용됩니다. 74 | 75 | - `DEFAULT_VERSION` : 버전 정보가 없는 경우 `request.version`에 사용해야 하는 값입니다. 기본값은 `None`입니다. 76 | - `ALLOWED_VERSIONS` : 이 값을 설정하면 versioning scheme에서 반환 할 수 있는 버전 집합이 제한되며 제공된 버전이 이 집합에 없는 경우 오류가 발생합니다. `DEFAULT_VERSION` 설정에 사용 된 값은 항상 `ALLOWED_VERSIONS` set의 일부로 간주됩니다 (단, `None`이 아닌 경우). 기본값은 `None`입니다. 77 | - `VERSION_PARAM` : 미디어 유형 또는 URL 쿼리 parameter와 같이 모든 버전 지정 parameter에 사용해야하는 문자열입니다. 기본값은 `'version'`입니다. 78 | 79 | 또한 고유한 versioning scheme를 정의하고 `default_version`, `allowed_version` 및 `version_param`클래스 변수를 사용하여 버전 별 또는 뷰 set 별로 세 가지 값을 더한 버전 클래스를 설정할 수 있습니다. 예를 들어, `URLPathVersioning`를 사용하려면 다음과 같이 하십시오. 80 | 81 | ```python 82 | from rest_framework.versioning import URLPathVersioning 83 | from rest_framework.views import APIView 84 | 85 | class ExampleVersioning(URLPathVersioning): 86 | default_version = ... 87 | allowed_versions = ... 88 | version_param = ... 89 | 90 | class ExampleView(APIVIew): 91 | versioning_class = ExampleVersioning 92 | ``` 93 | 94 | --- 95 | 96 | ## API Reference 97 | 98 | ### AcceptHeaderVersioning 99 | 이 scheme는 클라이언트가 `Accept` 헤더의 미디어 타입의 일부로 버전을 지정하도록 요구합니다. 이 버전은 기본 미디어 타입을 보완하는 미디어 타입 parameter로 포함됩니다. 100 | 다음 accept 헤더 versioning 스타일을 사용하는 HTTP request의 예입니다. 101 | 102 | ``` 103 | GET /bookings/ HTTP/1.1 104 | Host: example.com 105 | Accept: application/json; version=1.0 106 | ``` 107 | 위의 예제 request에서 `request.version`속성은 `'1.0'`문자열을 반환합니다. 108 | Accept 헤더에 기반한 versioning는 [일반적](http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http#i_want_my_api_to_be_versioned)으로 [모범 사례](https://github.com/interagent/http-api-design/blob/master/en/foundations/require-versioning-in-the-accepts-header.md)로 간주되지만 클라이언트 요구 사항에 따라 다른 스타일이 적합할 수도 있습니다. 109 | 110 | #### Using accept headers with vendor media types 111 | 엄밀히 말하자면 `json` 미디어 타입은 [추가 parameter](http://tools.ietf.org/html/rfc4627#section-6)를 포함하는 것으로 지정되지 않습니다. 잘 정의 된 공개 API를 작성하는 경우 [vendor media type](https://en.wikipedia.org/wiki/Internet_media_type#Vendor_tree)을 사용하는 것이 좋습니다. 이렇게 하려면 custom 미디어 타입으로 `JSON` 기반 렌더러를 사용하도록 렌더러를 구성하세요. 112 | 113 | ```python 114 | class BookingsAPIRenderer(JSONRenderer): 115 | media_type = 'application/vnd.megacorp.bookings+json' 116 | ``` 117 | 클라이언트의 request는 다음과 같습니다. 118 | 119 | ``` 120 | GET /bookings/ HTTP/1.1 121 | Host: example.com 122 | Accept: application/vnd.megacorp.bookings+json; version=1.0 123 | ``` 124 | 125 | ### URLPathVersioning 126 | 이 스키마는 클라이언트가 URL 경로의 일부로 버전을 지정하도록 요구합니다. 127 | 128 | ``` 129 | GET /v1/bookings/ HTTP/1.1 130 | Host: example.com 131 | Accept: application/json 132 | ``` 133 | URL conf에는 `'version'`키워드 인수가 있는 버전과 일치하는 패턴이 포함되어야하므로 이 정보를 versioning scheme에서 사용할 수 있습니다. 134 | 135 | ```python 136 | urlpatterns = [ 137 | url( 138 | r'^(?P(v1|v2))/bookings/$', 139 | bookings_list, 140 | name='bookings-list' 141 | ), 142 | url( 143 | r'^(?P(v1|v2))/bookings/(?P[0-9]+)/$', 144 | bookings_detail, 145 | name='bookings-detail' 146 | ) 147 | ] 148 | ``` 149 | 150 | ### NamespaceVersioning 151 | 클라이언트에서 이 scheme는 `URLPathVersioning`과 동일합니다. 유일한 차이점은 URL 키워드 인수 대신 URL 네임스페이스를 사용하므로 Django 애플리케이션에서 어떻게 구성되어 있는지입니다. 152 | 153 | ``` 154 | GET /v1/something/ HTTP/1.1 155 | Host: example.com 156 | Accept: application/json 157 | ``` 158 | 이 scheme에서 `request.version`속성은 틀어오는 request 경로와 일치하는 네임스페이스를 기반으로 결정됩니다. 159 | 다음 예제에서는 서로 다른 네임 스페이스 아래에 각각 다른 두가지 URL 접두어가 있는 일련의 view를 제공합니다. 160 | 161 | ```python 162 | # bookings/urls.py 163 | urlpatterns = [ 164 | url(r'^$', bookings_list, name='bookings-list'), 165 | url(r'^(?P[0-9]+)/$', bookings_detail, name='bookings-detail') 166 | ] 167 | 168 | # urls.py 169 | urlpatterns = [ 170 | url(r'^v1/bookings/', include('bookings.urls', namespace='v1')), 171 | url(r'^v2/bookings/', include('bookings.urls', namespace='v2')) 172 | ] 173 | ``` 174 | 175 | 간단한 versioning scheme가 필요하다면 `URLPathVersioning`과 `NamespaceVersioning` 모두 합리적입니다. 176 | 177 | ### HostNameVersioning 178 | hostname versioning scheme에서는 클라이어튼가 요청된 버전을 URL의 hostname의 일부로 지정해야합니다. 179 | 예를 들어 다음은 `http://v1.example.com/bookings/` URL에 대한 HTTP 요청입니다. 180 | 181 | ``` 182 | GET /bookings/ HTTP/1.1 183 | Host: v1.example.com 184 | Accept: application/json 185 | ``` 186 | 기본적으로 이 구현은 hostname이 다음과 같은 간단한 정규식과 일치 할 것으로 기대합니다. 187 | 188 | ``` 189 | ^([a-zA-Z0-9]+)\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$ 190 | ``` 191 | 첫 번째 그룹은 대괄호로 묶여 있으며 hostname의 일치하는 부분임을 나타냅니다. 192 | 일반적으로 `127.0.0.1`과 같은 기존 IP주소에 액서스하므로 `HostNameVersioning` scheme는 디버그 모드에서 사용하기가 어려울 수 있습니다. 이 경우 도움이 될 수 있는 [`custom subdomain`으로 localhost에 액서스](https://reinteractive.com/posts/199-developing-and-testing-rails-applications-with-subdomains)하는 다양한 온라인 서비스가 있습니다. 193 | hostname versioning scheme는 여러 API 버전에 대해 서로 다른 DNS 레코드를 구성할 수 있으므로 들어오는 request를 버전에 따라 다른 서버로 라우팅해야하는 경우에 특히 유용합니다. 194 | 195 | ### QueryParameterVersioning 196 | 이 스키마는 URL에 쿼리 parameter로 버전을 포함하는 간단한 스타일입니다. 예: 197 | 198 | ``` 199 | GET /something/?version=0.1 HTTP/1.1 200 | Host: example.com 201 | Accept: application/json 202 | ``` 203 | 204 | --- 205 | 206 | ## Custom versioning schemes 207 | custom versioning scheme를 구현하려면 `BaseVersioning`를 서브 클래스화하고 `.determine_version`메서드를 대체하세요. 208 | 209 | ### Example 210 | 다음 예에서는 custom `X-API-Version` 헤거를 사용하여 요청한 버전을 확인합니다. 211 | 212 | ```python 213 | class XAPIVersionScheme(versioning.BaseVersioning): 214 | def determine_version(self, request, *args, **kwargs): 215 | return request.META.get('HTTP_X_API_VERSION', None) 216 | ``` 217 | versioning scheme가 request URL을 기반으로 하는 경우 버전이 지정된 URL의 결정 방법도 변경해야합니다. 이렇게 하려면 클래스의 `.reverse()`메서드를 오버라이드해야합니다. 예제는 소스코드를 참조하세요. 218 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 19. Content negotiation.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Content negotiation 2 | 3 | --- 4 | 5 | _"HTTP has provisions for several mechanisms for "content negotiation" - the proce반s of selecting the best representation for a given response when there are multiple representations available."_ 6 | 7 | _"HTTP는 "내용 협상 (content negotiation)"에 대한 몇 가지 메커니즘에 대한 규정을 제공합니다. 이는 여러 표현을 사용할 수 있는 경우 주어진 응답에 대한 최상의 표현을 선택하는 프로세스입니다."_ 8 | 9 | _— RFC 2616, Fielding et al._ 10 | 11 | --- 12 | 13 | ## Content negotiation 14 | content negotiation은 클라이언트 또는 서버 환경 설정에 따라 클라이언트로 리턴할 수 있는 여러 표현 중 하나를 선택하는 프로세스입니다. 15 | 16 | ### Determining the accepted renderer 17 | REST 프레임워크는 간단한 스타일의 content negotiation을 사용하여 사용 가능한 renderer. 각 렌더러의 우선 순위 및 클라이언트의 `Accept:` 헤더를 기반으로 클라이언트에 반환해야하는 미디어 유형을 결정합니다. 사용되는 스타일은 부분적으로 클라이언트 / 서버 중심적입니다. 18 | 19 | 1. 더 구체적인 미디어 유형은 덜 구체적인 미디어 유형보다 우선합니다. 20 | 2. 복수의 미디어 타입이 같은 특이성을 가지는 경우, 지정된 뷰에 대해서 설정된 렌더러의 순서에 따라 우선권이 주어집니다. 21 | 22 | 예를 들어, 다음 `Accept` 헤더가 제공됩니다. 23 | 24 | ``` 25 | application/json; indent=4, application/json, application/yaml, text/html, */* 26 | ``` 27 | 28 | 각 미디어 유형의 우선 순위는 다음과 같습니다. 29 | 30 | - `application/json; indent=4` 31 | - `application/json`, `application/yaml` and `text/html` 32 | - `*/*` 33 | 34 | 요청 된 뷰가 `YAML`과 `HTML`용 렌더러로만 구성된 경우 REST 프레임워크는 `renderer_classes` list 또는 ` DEFAULT_RENDERER_CLASSES` 설정에서 먼저 나열된 렌더러를 선택합니다. 35 | 36 | HTTP Accept 헤더에 대한 자세한 내용은 [`RFC 2616`](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html)을 참조하십시오. 37 | 38 | --- 39 | 40 | **Note** : 환경 설정에서 REST 프레임워크가 `"q"`값을 고려하지 않습니다. `"q"`값의 사용은 캐싱에 부정적인 영향을 주며 저자의 의견으로는 content negotiation에 불필요하고 복잡해지는 접근방식입니다. 41 | 42 | 이는 HTTP 사양이 의도적으로 서버가 클라이언트 기반 환경설정에 대해 서버 기잔 환경설정에 가중치를 부여하는 방법을 명시하지 않기 때문에 유효한 접근 방식입니다. 43 | 44 | --- 45 | 46 | ## Custom content negotiation 47 | REST 프레임워크에 대해 custom content negotiation scheme를 제공하는 것은 거의 불가능하지만 필요한 경우 그렇게 할 수 있습니다. custom content negotiation scheme를 구현하려면 `BaseContentNegotiation`을 오버라이드합니다. 48 | 49 | REST 프레임워크의 content negotiation 클래스는 요청에 대한 적절한 파서 및 응답에 적합한 렌더러 모두를 처리하므로 `.select_parser(request, parser)` 및 `.select_renderer(request, renderers, format_suffix)` 메서드를 모두 구현해야합니다. 50 | 51 | `select_parser()`메서드는 파서 인스턴스 중 하나를 사용 가능한 파서 목록에서 반환하거나 파서가 들어오는 요청을 처리 할 수 없는 경우 `None`을 반환해야합니다. 52 | 53 | `select_renderer()`메서드는 (renderer instance, media type)의 두 tuple을 반환하거나 `NotAcceptable` 예외를 발생시킵니다. 54 | 55 | ### Example 56 | 다음은 적절한 파서 또는 렌더러를 선택할 때 클라이언트 요청을 무시하는 custom content negotiation 클래스입니다. 57 | 58 | ```python 59 | from rest_framework.negotiation import BaseContentNegotiation 60 | 61 | class IgnoreClientContentNegotiation(BaseContentNegotiation): 62 | def select_parser(self, request, parsers): 63 | """ 64 | Select the first parser in the `.parser_classes` list. 65 | """ 66 | return parsers[0] 67 | 68 | def select_renderer(self, request, renderers, format_suffix): 69 | """ 70 | Select the first renderer in the `.renderer_classes` list. 71 | """ 72 | return (renderers[0], renderers[0].media_type) 73 | ``` 74 | 75 | ### Setting the content negotiation 76 | 기본 content negotiation 클래스는 `DEFAULT_CONTENT_NEGOTIATION_CLASS`설정을 사용하여 전역으로 설정 할 수 있습니다. 예를 들어, 다음 설정은 예제 `IgnoreClientContentNegotitaion`클래스를 사용합니다. 77 | 78 | ```python 79 | REST_FRAMEWORK = { 80 | 'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'myapp.negotiation.IgnoreClientContentNegotiation', 81 | } 82 | ``` 83 | `APIView` CBV를 사용하여 개별 view 또는 viewset에 사용 된 content negotiation을 설정할 수도 있습니다. 84 | 85 | ```python 86 | from myapp.negotiation import IgnoreClientContentNegotiation 87 | from rest_framework.response import Response 88 | from rest_framework.views import APIView 89 | 90 | class NoNegotiationView(APIView): 91 | """ 92 | An example view that does not perform content negotiation. 93 | """ 94 | content_negotiation_class = IgnoreClientContentNegotiation 95 | 96 | def get(self, request, format=None): 97 | return Response({ 98 | 'accepted media type': request.accepted_renderer.media_type 99 | }) 100 | ``` -------------------------------------------------------------------------------- /doc/Django REST Framework - 20. Metadata.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Metadata 2 | 3 | --- 4 | 5 | _"[The OPTIONS] method allows a client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval."_ 6 | 7 | _"[OPTIONS] 메소드는 클라이언트가 자원 동작을 암시하거나 자원 검색을 시작하지 않고 자원 또는 서버의 기능과 관련된 옵션 및 `/` 또는 요구 사항을 결정할 수 있게 합니다."_ 8 | 9 | _— RFC7231, Section 4.3.7._ 10 | 11 | --- 12 | 13 | ## Metadata 14 | REST 프레임워크는 API가 `OPTIONS` 요청에 어떻게 응답해야 하는지를 결정하기 위한 구성 가능한 메커니즘을 포함합니다. API 스키마 또는 기타 리소스 정보를 반환 할 수 있습니다. 15 | 현재 HTTP OPTIONS 요청에 대해 어떤 스타일의 response를 반환해야하는지에 대해 널리 채택 된 규칙이 없으므로 유용한 정보를 반환하는 특별 스타일을 제공합니다. 16 | 다음은 기본적으로 반환되는 정보를 보여주는 예제 response입니다. 17 | 18 | ```python 19 | HTTP 200 OK 20 | Allow: GET, POST, HEAD, OPTIONS 21 | Content-Type: application/json 22 | 23 | { 24 | "name": "To Do List", 25 | "description": "List existing 'To Do' items, or create a new item.", 26 | "renders": [ 27 | "application/json", 28 | "text/html" 29 | ], 30 | "parses": [ 31 | "application/json", 32 | "application/x-www-form-urlencoded", 33 | "multipart/form-data" 34 | ], 35 | "actions": { 36 | "POST": { 37 | "note": { 38 | "type": "string", 39 | "required": false, 40 | "read_only": false, 41 | "label": "title", 42 | "max_length": 100 43 | } 44 | } 45 | } 46 | } 47 | ``` 48 | 49 | ### Setting the metadata scheme 50 | `DEFAULT_METADATA_CLASS`설정 키를 사용하여 메타 데이터 클래스를 전역으로 설정할 수 있습니다. 51 | 52 | ```python 53 | REST_FRAMEWORK = { 54 | 'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata' 55 | } 56 | ``` 57 | 또는 view에 대해 개별적으로 메타 데이터 클래스를 설정할 수 있습니다. 58 | 59 | ```python 60 | class APIRoot(APIView): 61 | metadata_class = APIRootMetadata 62 | 63 | def get(self, request, format=None): 64 | return Response({ 65 | ... 66 | }) 67 | ``` 68 | REST 프레임워크 패키지는 `SimpleMetadata`라는 단일 메타 데이터 클래스 구현만 포함됩니다. 다른 스타일을 사용하려면 custom 메타 데이터 클래스를 구현해야합니다. 69 | 70 | ### Creating schema endpoints 71 | 일반 `GET` 요청으로 액서스되는 schema endpoint을 만들기 위한 특정 요구사항이 있는 경우 그렇게 하기 위해 메타 데이터 API를 다시 사용할 수 있습니다. 72 | 예를 들어, 다음과 같은 추가 라우트를 vViewSet에 사용하여 linkable schema endpoint에 제공할 수 있습니다. 73 | 74 | ```python 75 | @list_route(methods=['GET']) 76 | def schema(self, request): 77 | meta = self.metadata_class() 78 | data = meta.determine_metadata(request, self) 79 | return Response(data) 80 | ``` 81 | `OPTIONS` 응답을 [캐싱할 수 없다는 것](https://www.mnot.net/blog/2012/10/29/NO_OPTIONS)을 포함하여 이 접근 방식을 선택할 수 있는 몇가지 이유가 있습니다. 82 | 83 | --- 84 | 85 | ## Custom metadata classes 86 | custom metadata 클래스를 제공하려면 `BaseMetadata`를 대체하고 `decide_metadata(self, request, view)` 메서드를 구현해야합니다. 87 | 유용한 정보로는 schema 정보 리턴, [JSON schema](http://json-schema.org/)와 같은 형식 사용 또는 관리자에세 디버그 정보 리턴 등이 있습니다. 88 | 89 | ### Example 90 | 다음 클래스는 `OPTIONS` 요청에 반환되는 정보를 제한하는데 사용될 수 있습니다. 91 | 92 | ```python 93 | class MinimalMetadata(BaseMetadata): 94 | """ 95 | Don't include field and other information for `OPTIONS` requests. 96 | Just return the name and description. 97 | """ 98 | def determine_metadata(self, request, view): 99 | return { 100 | 'name': view.get_view_name(), 101 | 'description': view.get_view_description() 102 | } 103 | ``` 104 | 그런 다음 이 custom 클래스를 사용하도록 설정을 구성하세요. 105 | 106 | ```python 107 | REST_FRAMEWORK = { 108 | 'DEFAULT_METADATA_CLASS': 'myproject.apps.core.MinimalMetadata' 109 | } 110 | ``` 111 | 112 | ## Third party packages 113 | 다음의 타사 패키지는 추가 메나 데이터 구현을 제공합니다. 114 | 115 | ### DRF-schema-adapter 116 | [drf-schema-adapter]()는 프론트엔드 프레임워크 및 라이브러리에 스키마 정보를 보다 쉽게 제공할 수 있게 해주는 도구 set입니다. metadata mixin 뿐만 아니라 다양한 라이브러리에 의해 읽을 수 있는 스키마 정보뿐만 아니라 [json-schema](http://json-schema.org/)를 생성하는데 적합한 2개의 metadara 클래스와 여러 어댑터를 제공합니다. 117 | 특정 프론트엔드에서 작동하도록 어댑터를 작성할 수도 있습니다. 그렇게 하고 싶다면 스키마 정보를 json 파일로 내보낼 수 있는 내보내기 기능을 제공합니다. 118 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 21. Schemas.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Schemas 2 | 3 | --- 4 | 5 | _"A machine-readable [schema] describes what resources are available via the API, what their URLs are, how they are represented and what operations they support."_ 6 | 7 | _"기계 판독 가능한 [스키마]는 API를 통해 사용할 수있는 리소스, 해당 URL의 의미, 표현 방법 및 지원 작업을 설명합니다."_ 8 | 9 | _— Heroku, JSON Schema for the Heroku Platform API_ 10 | 11 | --- 12 | 13 | ## Schemas 14 | API schema는 참조 문서를 생성하거나 API와 상호 작용 할 수 있는 동적 클라이언트 라이브러리를 구동하는 등 다양한 사용 사례를 허용하는 유용한 도구입니다. 15 | 16 | ### Representing schemas internally (내부적으로 스키마 표현하기) 17 | REST 프레임워크는 형식 독립적인 표현으로 스키마 정보를 모델링하기 위해 [Core API](http://www.coreapi.org/)를 사용합니다. 이 정보는 다양한 스키마 형식으로 렌더링되거나 API 문서를 생성하는데 사용됩니다. 18 | Core API를 사용하는 경우 스키마는 API에 대한 정보의 최상위 컨테이너 객체인 문서로 표시됩니다. 사용 가능한 API 상호작용은 링크 객체를 사용하여 표시됩니다. 각 링크는 URL, HTTP 메서드를 포함하며 API 엔드포인트에서 승인 할 수 있는 매개변수를 설명하는 `Field` 인스턴스 목록을 포함할 수 있습니다. `Link`와 `Field` 인스턴스에는 API 스키마를 사용자 문서로 렌더링 할 수 있는 설명이 포함될 수도 있습니다. 19 | 다음은 단일 검색 엔드포인트를 포함하는 API 설명의 예입니다. 20 | 21 | ```python 22 | coreapi.Document( 23 | title='Flight Search API', 24 | url='https://api.example.org/', 25 | content={ 26 | 'search': coreapi.Link( 27 | url='/search/', 28 | action='get', 29 | fields=[ 30 | coreapi.Field( 31 | name='from', 32 | required=True, 33 | location='query', 34 | description='City name or airport code.' 35 | ), 36 | coreapi.Field( 37 | name='to', 38 | required=True, 39 | location='query', 40 | description='City name or airport code.' 41 | ), 42 | coreapi.Field( 43 | name='date', 44 | required=True, 45 | location='query', 46 | description='Flight date in "YYYY-MM-DD" format.' 47 | ) 48 | ], 49 | description='Return flight availability and prices.' 50 | ) 51 | } 52 | ) 53 | ``` 54 | 55 | ### Schema output formats 56 | HTTP response으로 표시되려면 내부 표현이 response에 사용 된 실제 바이트로 렌더링되어야 합니다. 57 | [Core JSON]()은 Core API와 함께 사용하기 위한 표준 형식으로 설계되었습니다. REST 프레임워크에는 이 미디어 유형을 처리하기 위한 렌더러 클래스가 포함되어 있으며, 이 렌더러클래스는 `CoreJSONRenderer`로 사용할 수 있습니다. 58 | [Open API](https://openapis.org/)("Swagger"), [JSON HyperSchema](http://json-schema.org/latest/json-schema-hypermedia.html), [API Blueprint](https://apiblueprint.org/)와 같은 다른 스키마 형식도 custom renderer 클래스를 구현하여 지원할 수 있습니다. 59 | 60 | ### Schemas vs Hypermedia 61 | Core API는 API 스키마에 대한 대안적인 상호작용 스타일을 제시하는 하이퍼 미디어 응답을 모델링하는데 사용될 수 있다는 점을 여기서 지적 할 필요가 있습니다. 62 | API 스키마를 사용할 수 있는 전체 인터페이스가 단일 엔드포인트로 제공됩니다. 개별 API 엔드포인트에 대한 응답은 일반적으로 각 response에 추가 상호 작용없이 일반 데이터로 표시됩니다. 63 | Hypermedia를 사용하면 클라이언트에 데이터와 사용 가능한 상호 작용이 모두 포함된 문서가 제공됩니다. 각 상호 작용을 통해 현재 상태와 사용 가능한 상호 작용을 자세히 설명하는 새 문서가 생성됩니다. 64 | REST 프레임워크를 사용하여 Hypermedia API를 빌드하는데 대한 자세한 정보와 지원은 향후 버전에서 계획됩니다. 65 | 66 | --- 67 | 68 | ## Adding a schema 69 | REST 프레임워크에 대한 스키마 지원을 추가하려면 `coreapi` 패키지를 설치해야합니다. 70 | 71 | ``` 72 | pip install coreapi 73 | ``` 74 | REST 프레임워크에는 스키마 자동 생성 기능이 포함되어 있거나 명시적을 스키마를 지정할 수 있습니다. 필요한 항목에 따라 API에 스키마를 추가하는 몇가지 방법이 있습니다. 75 | 76 | ### The get_schema_view shortcut 77 | 프로젝트에 스키마를 포함시키는 가장 간단한 방법은 `get_schema_view()`함수를 사용하는 것입니다. 78 | 79 | ```python 80 | schema_view = get_schema_view(title="Server Monitoring API") 81 | 82 | urlpatterns = [ 83 | url('^$', schema_view), 84 | ... 85 | ] 86 | ``` 87 | view가 추가되면 자동 생성 스키마 정의를 검색하기 위한 API 요청을 할 수 있습니다. 88 | 89 | ```python 90 | $ http http://127.0.0.1:8000/ Accept:application/vnd.coreapi+json 91 | HTTP/1.0 200 OK 92 | Allow: GET, HEAD, OPTIONS 93 | Content-Type: application/vnd.coreapi+json 94 | 95 | { 96 | "_meta": { 97 | "title": "Server Monitoring API" 98 | }, 99 | "_type": "document", 100 | ... 101 | } 102 | ``` 103 | `get_schema_view()`에 대한 인수는 다음과 같습니다. 104 | 105 | - `title` : 스키마 정의를 설명하는 제목을 제공하는데 사용할 수 있습니다. 106 | - `url` : 스키마의 표준 URL을 전달하는데 사용될 수 있습니다. 107 | 108 | ```python 109 | schema_view = get_schema_view( 110 | title='Server Monitoring API', 111 | url='https://www.example.org/api/' 112 | ) 113 | ``` 114 | 115 | - `urlconf` : API 스키마를 생성하려는 URL conf의 가져오기 경로를 나타내는 문자열입니다. 기본값은 Django의 `ROOT_URLCONF` 설정 값입니다. 116 | 117 | ```python 118 | schema_view = get_schema_view( 119 | title='Server Monitoring API', 120 | url='https://www.example.org/api/', 121 | urlconf='myproject.urls' 122 | ) 123 | ``` 124 | 125 | - `renderer_classes` : API root 엔드포인트의 렌더링에 사용할 수 있는 렌더러 클래스 셋을 전달하는데 사용할 수 있습니다. 126 | 127 | ```python 128 | from rest_framework.renderers import CoreJSONRenderer 129 | from my_custom_package import APIBlueprintRenderer 130 | 131 | schema_view = get_schema_view( 132 | title='Server Monitoring API', 133 | url='https://www.example.org/api/', 134 | renderer_classes=[CoreJSONRenderer, APIBlueprintRenderer] 135 | ) 136 | ``` 137 | 138 | ### Using an explicit schema view 139 | `get_schema_view()` shortcut이 제공하는 것보다 더 많은 컨트롤이 필요한 경우 `SchemaGenerator` 클래스를 직접 사용하여 Document 인스턴스를 자동으로 생성하고 뷰에서 이를 반환 할 수 있습니다. 140 | 이 옵셥을 사용하면 원하는 모든 동작으로 스키마 엔드포인트를 설정할 수 있습니다. 예를 들어, 스키마 엔드포인트에 다른 사용 권한, 제한 또는 인증 정책을 적용 할 수 있습니다. 141 | 다음은 `SchemaGenerator`를 뷰와 함께 사용하려 스키마를 반환하는 예제입니다. 142 | 143 | get_schema_view () 바로 가기가 제공하는 것보다 더 많은 컨트롤이 필요한 경우 SchemaGenerator 클래스를 직접 사용하여 Document 인스턴스를 자동으로 생성하고 뷰에서이를 반환 할 수 있습니다. 144 | 145 | **views.py**: 146 | 147 | ```python 148 | from rest_framework.decorators import api_view, renderer_classes 149 | from rest_framework import renderers, response, schemas 150 | 151 | generator = schemas.SchemaGenerator(title='Bookings API') 152 | 153 | @api_view() 154 | @renderer_classes([renderers.CoreJSONRenderer]) 155 | def schema_view(request): 156 | schema = generator.get_schema(request) 157 | return response.Response(schema) 158 | ``` 159 | 160 | **urls.py**: 161 | 162 | ```python 163 | urlpatterns = [ 164 | url('/', schema_view), 165 | ... 166 | ] 167 | ``` 168 | 사용 가능한 권한에 따라 다른 사용자에게 다른 스키마를 제공할 수도 있습니다. 이 접근법은 인증되지 않은 요청이 인증된 요청과 다른 스키마로 제공되거나 API의 다른 부분이 해당 역할에 따라 다른 사용자에게 표시되도록하는데 사용할 수 있습니다. 169 | 사용자 권한으로 필터링 된 엔드포인트가 있는 스키마를 표시하려면 `get_schema()`메서드에 `request` 인수를 전달해야 합니다. 예를 들면 다음과 같습니다. 170 | 171 | ```python 172 | @api_view() 173 | @renderer_classes([renderers.CoreJSONRenderer]) 174 | def schema_view(request): 175 | generator = schemas.SchemaGenerator(title='Bookings API') 176 | return response.Response(generator.get_schema(request=request)) 177 | ``` 178 | 179 | ### Explicit schema definition 180 | 자동 생성 방식의 대안은 코드베이스에 `Document` 객체를 선언하여 API 스키마를 명시적으로 지정하는 것입니다. 그렇게 하는것은 조금 더 작업 할 수 있지만 스키마 표현을 완전히 제어 할 수 있습니다. 181 | 182 | ```python 183 | import coreapi 184 | from rest_framework.decorators import api_view, renderer_classes 185 | from rest_framework import renderers, response 186 | 187 | schema = coreapi.Document( 188 | title='Bookings API', 189 | content={ 190 | ... 191 | } 192 | ) 193 | 194 | @api_view() 195 | @renderer_classes([renderers.CoreJSONRenderer]) 196 | def schema_view(request): 197 | return response.Response(schema) 198 | ``` 199 | 200 | ### Static schema file 201 | 마지막 옵션은 Core JSON 또는 Open API 와 같은 사용 가능한 형식 중 하나를 사용하여 API schema를 static 파일로 작성하는 것입니다. 202 | 203 | 다음 중 하나를 수행 할 수 있습니다. 204 | 205 | - 스키마 정의를 static 파일로 작성하고 [static 파일을 직접 제공하세요](https://docs.djangoproject.com/en/1.10/howto/static-files/). 206 | - Core API를 사용하여 로드 된 스키마 정의를 작성한 다음 클라이언트 요청에 따라 여러가지 사용 가능한 형식중 하나로 렌더링합니다. 207 | 208 | --- 209 | 210 | ## Schemas as documentation 211 | API 스키마의 일반적인 사용법 중 하나는 문서 페이지를 작성하는데 사용합니다. 212 | REST 프레임워크의 스키마 생성은 docstring을 사용하여 스키마 문서의 설명을 자동으로 채웁니다. 213 | 214 | 이 설명은 다음을 기반으로 합니다. 215 | 216 | - 해당 메소드 docstring이 있는 경우는 그것을 돌려줍니다. 217 | - docstring 클래스 내의 명명된 섹션으로, 한 줄 또는 여러 줄이 될 수 있습니다. 218 | - The class docstring. 219 | 220 | ### Examples 221 | 명시적인 메서드 docstring이 있는 `APIView`입니다. 222 | 223 | ```python 224 | class ListUsernames(APIView): 225 | def get(self, request): 226 | """ 227 | Return a list of all user names in the system. 228 | """ 229 | usernames = [user.username for user in User.objects.all()] 230 | return Response(usernames) 231 | ``` 232 | 설명하는 액션 docstring이 있는 `ViewSet`입니다. 233 | 234 | ```python 235 | class ListUsernames(ViewSet): 236 | def list(self, request): 237 | """ 238 | Return a list of all user names in the system. 239 | """ 240 | usernames = [user.username for user in User.objects.all()] 241 | return Response(usernames) 242 | ``` 243 | 단일 행 스타일을 사용하여 docstring 클래스의 섹션이 있는 generic view입니다. 244 | 245 | ```python 246 | class UserList(generics.ListCreateAPIView): 247 | """ 248 | get: List all the users. 249 | post: Create a new user. 250 | """ 251 | queryset = User.objects.all() 252 | serializer_class = UserSerializer 253 | permission_classes = (IsAdminUser,) 254 | ``` 255 | 다중 회선 스타일을 사용하여 docstring 클래스의 섹션이 있는 generic viewset입니다. 256 | 257 | ```python 258 | class UserViewSet(viewsets.ModelViewSet): 259 | """ 260 | API endpoint that allows users to be viewed or edited. 261 | 262 | retrieve: 263 | Return a user instance. 264 | 265 | list: 266 | Return all users, ordered by most recently joined. 267 | """ 268 | queryset = User.objects.all().order_by('-date_joined') 269 | serializer_class = UserSerializer 270 | ``` 271 | 272 | --- 273 | 274 | ## Alternate schema formats 275 | 대체 스키마 형식을 지원하려면 `Document` 인스턴스를 바이트 표현으로 변환하는 처리를 담당하는 custom의 rederer 클래스를 구현해야합니다. 276 | 사용할 형식을 인코딩을 지원하는 Core API 코덱패키지가 있는 경우 해당 코덱을 사용하여 rederer 클래스를 구현 할 수 있습니다. 277 | 278 | ### Example 279 | 예를 들어 `openapi_codec` 패키지는 Open API("Swagger") 형식의 인코딩 또는 디코딩을 지원합니다. 280 | 281 | ```python 282 | from rest_framework import renderers 283 | from openapi_codec import OpenAPICodec 284 | 285 | class SwaggerRenderer(renderers.BaseRenderer): 286 | media_type = 'application/openapi+json' 287 | format = 'swagger' 288 | 289 | def render(self, data, media_type=None, renderer_context=None): 290 | codec = OpenAPICodec() 291 | return codec.dump(data) 292 | ``` 293 | 294 | --- 295 | 296 | ## API Reference 297 | 298 | ### SchemaGenerator 299 | 스키마를 생성하는데 사용 할 수 있는 API view를 검토하는 클래스입니다. 300 | 일반적으로 다음과 같이 단일 인수로 `SchemaGenerator`를 인스턴스화합니다. 301 | 302 | ``` 303 | generator = SchemaGenerator(title='Stock Prices API') 304 | ``` 305 | 306 | Arguments: 307 | 308 | - `title` **required** : API의 이름. 309 | - `url` : API 스키마의 루트 URL입니다. 스키마가 경로 접두어에 포함되지 않으면 이 옵션이 필요하지 않습니다. 310 | - `patterns` : 스키마를 생성 할 때 검사 할 URL 목록입니다. 기본값은 프로젝트의 URL conf입니다. 311 | - `urlconf` : 스키마를 생성 할 때 사용할 URL conf 모듈 이름입니다. 기본값은 `settings.ROOT_URLCONF`입니다. 312 | 313 | #### get_schema(self, request) 314 | API 스키마를 나타내는 `coreapi.Document` 인스턴스를 반환합니다. 315 | 316 | ```python 317 | @api_view 318 | @renderer_classes([renderers.CoreJSONRenderer]) 319 | def schema_view(request): 320 | generator = schemas.SchemaGenerator(title='Bookings API') 321 | return Response(generator.get_schema()) 322 | ``` 323 | `request` 인수는 선택 사항이며, 결과 스키마 생성에 사용자 별 권한을 적용하려는 경우에 사용할 수 있습니다. 324 | 325 | #### get_links(self, request) 326 | API 스키마에 포함되어야 하는 모든 링크가 포함된 중첩된 dict를 반환합니다. 327 | 다른 레이아웃으로 새 dict를 빌드할 수 있으므로 생성된 스키마의 결과 구조를 수정하려는 경우 이를 대체하는 것이 좋습니다. 328 | 329 | #### get_link(self, path, method, view) 330 | 주어진 뷰에 해당하는 `coreapi.Link`인스턴스를 반환합니다. 331 | 특정 뷰에 대해 custom 동작을 제공해야하는 경우 이 설정을 오버라이드 할 수 있습니다. 332 | 333 | #### get_description(self, path, method, view) 334 | 링크 설명으로 사용할 문자열을 반환합니다. 기본적으로 이는 위의 "Schemas as Documentation" 섹션에서 설명한대로 docstring을 기반으로합니다. 335 | 336 | #### get_encoding(self, path, method, view) 337 | 지정된 뷰와 상호 작용할 때 모든 request 본문에 대한 인코딩을 나타내는 문자열을 반환합니다. 338 | 예: `application/json`. request 본문을 기대하지 않는 뷰에 빈 문자열을 반환할 수 있습니다. 339 | 340 | #### get_path_fields(self, path, method, view): 341 | `coreapi.Link()`인스턴스의 list를 반환합니다. URL의 각 경로 parameter에 하나씩. 342 | 343 | #### get_serializer_fields(self, path, method, view) 344 | `coreapi.Link()` 인스턴스의 list를 반환합니다. 뷰가 사용하는 serializer 클래스의 각 필드에 하나씩. 345 | 346 | #### get_pagination_fields(self, path, method, view) 347 | 뷰가 사용하는 pagination 클래스의 `get_schema_fields()` 메소드가 반환 한 `coreapi.Link()` 인스턴스의 list를 반환합니다. 348 | 349 | #### get_filter_fields(self, path, method, view) 350 | 뷰에 의해 사용 된 filter 클래스의 `get_schema_fields()` 메소드에 의해 돌려 주어지는 `coreapi.Link()` 인스턴스의 list를 돌려줍니다. 351 | 352 | --- 353 | 354 | ### Core API 355 | 356 | 이 문서는 API 스키마를 표현하는데 사용되는 `coreapi` 패키지 내의 구성 요소에 대한 간략한 개요를 제공합니다. 357 | 이러한 클래스는 `rest_framework` 패키지가 아니라 `coreapi`패키지에서 가져옵니다. 358 | 359 | #### Document 360 | API 스키마 컨테이너를 나타냅니다. 361 | `title` : API의 이름 362 | `url` : API의 표준 URL 363 | `content` : 스키마에 포함 된 `Link` 개체를 포함하는 dict입니다. 364 | 365 | 스키마에 더 많은 구조를 제공하기 위해 content dict는 일반적으로 두번째 레벨로 중첩 될 수 있습니다. 366 | 예: 367 | 368 | ```python 369 | content={ 370 | "bookings": { 371 | "list": Link(...), 372 | "create": Link(...), 373 | ... 374 | }, 375 | "venues": { 376 | "list": Link(...), 377 | ... 378 | }, 379 | ... 380 | } 381 | ``` 382 | 383 | #### Link 384 | 개별 API 엔드포인트를 나타냅니다. 385 | 386 | `url` : 엔드포인트의 URL. `/users/{username}/`와 같은 URI 템플릿 일 수 있습니다. 387 | `action` : 엔드포인트와 연관된 HTTP 방법. 하나 개 이상의 HTTP 메서드를 지원하는 URL은, 각각 하나의 `Link`에 해당해야합니다. 388 | `fields` : 입력에 사용 할 수 있는 parameter를 설명하는 `Field`인스턴스의 list입니다. 389 | `description` : 엔드포인트의 의미와 용도에 대해 간단한 설명. 390 | 391 | #### Field 392 | 지정된 API 엔드포인트에서 단일 입력 매개변수를 나타냅니다. 393 | 394 | `name` : 입력을 설명하는 이름입니다. 395 | `required` : 클라이언트가 값을 포함하는 경우 또는 parameter를 생략할 수 있는지 여부를 나타내는 boolean 입니다. 396 | `location` : 정보가 request에 어떻게 인코딩되는지 결정합니다. 다음 문자열 중 하나이어야 합니다. 397 | > 398 | **"path"** 399 | 템플릿 화 된 URL에 포함됩니다. 예를 들어 `/products/slim-fit-jeans/`와 같은 URL path에서 API 입력을 처리하기 위해 `/products/{product_code}/`의 URL 값을 `"path"` 입력란과 함께 사용할 수 있습니다. 400 | 이 필드는 대개 [프로젝트 URL conf의 명명 된 인수](https://docs.djangoproject.com/en/1.10/topics/http/urls/#named-groups)와 일치합니다. 401 | > 402 | **"query"** 403 | URL 쿼리 매개변수로 포함됩니다. 예: `?search=sale`. 일반적으로 `GET` 요청에 사용됩니다. 404 | 이러한 필드는 일반적으로 뷰의 pagination 및 필터링 컨트롤과 일치합니다. 405 | > 406 | **"form"** 407 | request 본문에 JSON 객체 또는 HTML 양식의 단일 항목으로 포함됩니다. 예 : `{"color":"blue",...}`. 일반적으로 `POST`, `PUT` 및 `PATCH` 요청에 사용됩니다. 여러 `"form"`입력란은 단일 링크에 포함될 수 있습니다. 408 | 이러한 필드는 일반적으로 뷰의 serializer 필드와 일치합니다. 409 | > 410 | **"body"** 411 | 전체 request 본문에 포함됩니다. 일반적으로 `POST`, `PUT`및 `PATCH` 요청에 사용됩니다. 링크에는 둘 이상의 `"body"` 필드가 존재 할 수 없습니다. `"form"`필드와 함께 사용 할 수 없습니다. 412 | 이러한 필드는 보통 `ListSerializer`를 사용하는 request 입력의 유효성을 검사하거나 파일 업로드 뷰를 사용하는 view와 일치합니다. 413 | 414 | `encoding` 415 | > 416 | **"application/json"** 417 | JSON 인코딩 된 request 컨텐츠. `JSONParser`를 사용하는 뷰에 해당합니다. 하나 이상의 `location="form"`필드 또는 단일 `location="body"`필드가 링크에 포함 된 경우에만 유효합니다. 418 | > 419 | **"multipart/form-data"** 420 | 멀티 파트로 인코딩 된 request content. `MultiPartParser`를 사용하는 뷰에 해당합니다 하나 이상의 `location="form"`필드가 링크에 포함 된 경우에만 유효합니다. 421 | > 422 | **"application/x-www-form-urlencoded"** 423 | URL로 인코딩 된 requetst content. `FormParser`를 사용하는 뷰에 해당합니다. 하나 이상의 `location="form"`필드가 링크에 포함 된 경우에만 유효합니다. 424 | > 425 | **"application/octet-stream"** 426 | 이진 업로드 request content. `FileUploadParser`를 사용하는 뷰에 해당합니다. `location="body"`필드가 링크에 포함된 경우에만 유효합니다. 427 | 428 | `description` : 입력 필드의 의미와 용도에 대한 간단한 설명 429 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 22. Format suffixes.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Format suffixes 2 | 3 | --- 4 | 5 | _"Section 6.2.1 does not say that content negotiation should be used all the time."_ 6 | 7 | 8 | _"섹션 6.2.1은 content negotiation이 항상 사용되어야한다고 말하지 않는다. "_ 9 | 10 | _— Roy Fielding, REST discuss mailing list_ 11 | 12 | --- 13 | 14 | ## Format suffixes 15 | 웹 API의 일반적인 패턴은 URL에서 파일 이름 확장자를 사용하여 특정 미디어 유형에 대한 엔드포인트를 제공하는 것입니다. 예를 들어, 'http://example.com/api/users.json'은 JSON 표현을 제공합니다. 16 | API의 URLconf에 있는 각 개별 항목에 형식 접미사 패턴을 추가하는 것은 오류가 발생하기 쉽고 DRY가 아니므로 REST 프레임워크는 이러한 패턴을 URLconf에 추가하는 방법을 제공합니다. 17 | 18 | ### format_suffix_patterns 19 | **Signature**: format_suffix_patterns(urlpatterns, suffix_required=False, allowed=None) 20 | 21 | 제공된 각 URL 패턴에 추가 된 형식 접미사 패턴을 포함하는 URL 패턴 list를 반환합니다. 22 | 23 | Arguments: 24 | 25 | - `urlpatterns` : **필수**. URL 패턴 목록. 26 | - `suffix_required` : 선택사항. URL의 접미사를 옵션으로 하는지, 필수로 하는지를 나타내는 boolean입니다. 디폴트는 `False`입니다. 접미사는 기본적으로 선택사항입니다. 27 | - `allowed` : 선택사항. 유효한 형식 접미사의 list 또는 tuple입니다. 제공되지 않으면 와일드 카드 형식 접미사 패턴이 사용됩니다. 28 | 29 | 예: 30 | 31 | ```python 32 | from rest_framework.urlpatterns import format_suffix_patterns 33 | from blog import views 34 | 35 | urlpatterns = [ 36 | url(r'^/$', views.apt_root), 37 | url(r'^comments/$', views.comment_list), 38 | url(r'^comments/(?P[0-9]+)/$', views.comment_detail) 39 | ] 40 | 41 | urlpatterns = format_suffix_patterns(urlpatterns, allowed=['json', 'html']) 42 | ``` 43 | `format_suffix_patterns`를 사용하는 경우 `'format'`키워드 인수를 해당 부에 추가해야합니다. 예: 44 | 45 | ```python 46 | @api_view(('GET', 'POST')) 47 | def comment_list(request, format=None): 48 | # do stuff... 49 | ``` 50 | 또는 class-bassed-views: 51 | 52 | ```python 53 | class CommentList(APIView): 54 | def get(self, request, format=None): 55 | # do stuff... 56 | 57 | def post(self, request, format=None): 58 | # do stuff... 59 | ``` 60 | 사용 된 kwarg의 이름은 `FORMAT_SUFFIX_KWARG`설정을 사용하여 수정할 수 있습니다. 61 | 또한 `format_suffix_patterns`는 `include`URL 패턴으로 내림차순을 지원하지 않습니다. 62 | 63 | #### Using with `i18n_patterns` 64 | Django에서 제공하는 `i18n_patterns`함수와 `format_suffix_patterns`를 사용하는 경우 `i18n_patterns` 함수가 최종 함수 또는 가장 바깥쪽 함수로 적용되는지 확인해야합니다. 예: 65 | 66 | ```python 67 | url patterns = [ 68 | … 69 | ] 70 | 71 | urlpatterns = i18n_patterns( 72 | format_suffix_patterns(urlpatterns, allowed=['json', 'html']) 73 | ) 74 | ``` 75 | 76 | --- 77 | 78 | ### Query parameter formats 79 | format suffixe의 대신 요청 된 쿼리 parameter에 포함시키는 것입니다. REST 프레임워크는 기본적으로 옵션을 제공하며, browsable API에서 사용 가능한 다양한 표현을 전환하는데 사용됩니다. 80 | 짧은 형식을 사용하여 표현을 선택하려면 `format` 쿼리 parameter를 사용하십시오. 예 : `http://example.com/organizations/?format=csv` 81 | 이 쿼리 parameter의 이름은 `URL_FORMAT_OVERRIDE`설정을 사용하여 수정할 수 있습니다. 이 동작을 사용하지 않으려면 값을 `None`으로 설정하세요. 82 | 83 | ### Accept headers vs. format suffixes 84 | 파일 이름 확장자는 RESTfull 패턴이 아니면 HTTP Accept 헤더가 항상 대신 사용되어야 한다는 웹 커뮤니티의 견해가 있는 것 같습니다. 85 | 그것은 실제론 오해입니다. 예를 들어 Roy Fileding은 쿼리 parameter 미디어 타입 표시기와 파일 확장 미디어 타입 표시기의 상대적 장점에 대해 다음과 같이 설명합니다. 86 | _"그래서 나는 항상 확장 프로그램을 선호합니다. 어느 선택도 REST와는 아무런 관련이 없습니다. "- Roy Fielding, REST 토론 메일 링리스트_ 87 | 88 | 인용문에는 Accept Headers가 언급되어 있지 않지만 format suffix는 허용되는 패턴으로 간주되어야 한다는 점을 분명히 합니다. -------------------------------------------------------------------------------- /doc/Django REST Framework - 23. Returning URLs.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Returning URLs 2 | 3 | --- 4 | 5 | _"The central feature that distinguishes the REST architectural style from other network-based styles is its emphasis on a uniform interface between components."_ 6 | 7 | _"REST 아키텍처 스타일을 다른 네트워크 기반 스타일과 구별하는 핵심 기능은 구성 요소 간의 균일한 인터페리스에 중점을 둡니다."_ 8 | 9 | _— Roy Fielding, Architectural Styles and the Design of Network-based Software Architectures_ 10 | 11 | --- 12 | 13 | ## Returning URLs 14 | 일반적으로 `/foobar`와 같은 상대URL를 반환하는 것이 아니라 `http://example.com/foobar`와 같이 웹 API에서 절대 URI를 반환하는 것이 좋습니다. 15 | 16 | 이렇게 하는 이점은 다음과 같습니다. 17 | 18 | - 이것이 더 명시적입니다. 19 | - 당신의 API 클라이언트에 대한 작업을 적게 남겨둡니다. 20 | - 네이티브 URI 유형이 없는 JSON과 같은 표현에서 문자열의 의미에 대한 모호성이 없습니다. 21 | - 하이퍼링크를 사용하여 마크업 HTML 표현과 같은 작업을 쉽게 수행할 수 있습니다. 22 | 23 | REST 프레임워크는 웹 API에서 절대 URI를 리턴하는 것을 보다 간단하게 해주는 두가지 유틸리티 함수를 제공합니다. 24 | 사용자가 직접 사용하도록 요구할 필요는 없지만 사용자가 직접 입력하면 자체 설명 API가 출력을 자동으로 하이퍼링크로 연결할 수 있으므로 API를 훨씬 쉽게 찾을 수 있습니다. 25 | 26 | ### reverse 27 | **Signature**: `reverse(viewname, *args, **kwargs)` 28 | [`django.urls.reverse`](https://docs.djangoproject.com/en/1.10/topics/http/urls/#reverse)와 동일한 동작을 하지만 호스트와 포트를 결정하기 위한 요청을 사용하여 정규화 된 URL을 반환합니다. 29 | 함수에 대한 **키워드 인수로 request을 포함**해야합니다. 예: 30 | 31 | ```python 32 | from rest_framework.reverse import reverse 33 | from rest_framework.views import APIView 34 | from django.utils.timezone import now 35 | 36 | class APIRootView(APIView): 37 | def get(self, request): 38 | year = now().year 39 | data = { 40 | ... 41 | 'year-summary-url': reverse('year-summary', args=[year], request=request) 42 | } 43 | return Response(data) 44 | ``` 45 | 46 | ### reverse_lazy 47 | 48 | **Signature**: `reverse_lazy(viewname, *args, **kwargs)` 49 | `django.urls.reverse_lazy`와 동일한 동작을 하지만 호스트와 포트를 결정하기위한 요청을 사용하여 정규화 된 URL을 반환한다는 점만 다릅니다. 50 | `reverse` 함수와 마찬가지로 함수에 대한 **키워드 인수로 request를 포함**해야합니다. 예: 51 | 52 | ``` 53 | api_root = reverse_lazy('api-root', request=request) 54 | ``` 55 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 24. Exceptions.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Exceptions 2 | 3 | --- 4 | 5 | _"Exceptions… allow error handling to be organized cleanly in a central or high-level place within the program structure."_ 6 | 7 | _"예외... 프로그램 구조 내의 중앙 또는 상위 위치에서 오류 처리를 명확하게 구성 할 수 있습니다."_ 8 | 9 | _— Doug Hellmann, Python Exception Handling Techniques_ 10 | --- 11 | 12 | ## Exceptions 13 | 14 | ### Exception handling in REST framework views 15 | REST 프레임워크의 뷰는 다양한 예외를 처리하고 적절한 오류 응답을 반환합니다. 16 | 17 | 처리되는 예외는 다음과 같습니다. 18 | 19 | - REST 프레임워크 내에서 발생하는 `APIException`의 서브클래스입니다. 20 | - Django의 `Http404` exception. 21 | - Django의 `PermissionDenied` exception. 22 | 23 | 각각의 경우에 REST 프레임워크는 적절한 상태 코드 및 내용 유형이 포함된 응답을 반환합니다. response 본문에는 오류의 성격에 관한 추가 세부 정보가 포함됩니다. 24 | 대부분의 오류 응답에는 response 본문의 `detail`정보가 포함됩니다. 25 | 26 | 예를 들어, 다음 요청은: 27 | 28 | ``` 29 | DELETE http://api.example.com/foo/bar HTTP/1.1 30 | Accept: application/json 31 | ``` 32 | 해당 리소스에서 `DELETE` 메서드가 허용되지 않는다는 오류 응답을 받을 수 있습니다. 33 | 34 | ```python 35 | HTTP/1.1 405 Method Not Allowed 36 | Content-Type: application/json 37 | Content-Length: 42 38 | 39 | {"detail": "Method 'DELETE' not allowed."} 40 | ``` 41 | 유효성 검사 오류는 약간 다르게 처리되며 필드 이름을 응답의 키로 포함합니다. 유효성 검사 오류가 특정 필드에만 해당되지 않으면 `"non_field_errors"`키를 사용하거나 `NON_FIELD_ERRORS_KEY` 설정에 대해 설정된 문자열 값을 사용합니다. 42 | 모든 유효성 검증 오류는 다음과 같습니다. 43 | 44 | ```python 45 | HTTP/1.1 400 Bad Request 46 | Content-Type: application/json 47 | Content-Length: 94 48 | 49 | {"amount": ["A valid integer is required."], "description": ["This field may not be blank."]} 50 | ``` 51 | 52 | ### Custom exception handling 53 | API view에서 발생한 예외를 response 객체로 변환하는 handler 함수를 만들어 custom exception를 구현할 수 있습니다. 이를 통해 API에서 사용되는 오류 응답 스타일을 제어할 수 있습니다. 54 | 55 | 함수는 한쌍의 인수를 취해야하며, 첫번째는 처리할 예외이고, 두번째는 현재 처리중인 뷰와 같은 추가 context를 포함하는 dict입니다. exception handler 함수는 `Response` 객체를 반환하거나 예외를 처리 할 수 없는 경우 `None`을 반환해야합니다. handler가 `None`을 반환하면 예외가 다시 발생하고 Django는 표준 HTTP 500 'server error'응답을 반환합니다. 56 | 57 | 예를 들어, 모든 오류 응답에 다음과 같이 HTTP 본문 코드에 HTTP 상태 코드가 포함되도록 할 수 있습니다. 58 | 59 | ```python 60 | HTTP/1.1 405 Method Not Allowed 61 | Content-Type: application/json 62 | Content-Length: 62 63 | 64 | {"status_code": 405, "detail": "Method 'DELETE' not allowed."} 65 | ``` 66 | response 스타일을 변경하기 위해 다음과 같은 custom exception handler를 작성 할 수 있습니다. 67 | 68 | ```python 69 | from rest_framework.views import exception_handler 70 | 71 | def custom_exception_handler(exc, context): 72 | # Call REST framework's default exception handler first, 73 | # to get the standard error response. 74 | response = exception_handler(exc, context) 75 | 76 | # Now add the HTTP status code to the response. 77 | if response is not None: 78 | response.data['status_code'] = response.status_code 79 | 80 | return response 81 | ``` 82 | context 인수는 기본 handler에서 사용되지 않지만 exception handler가 `context['view']`로 액서스 할 수 있는 현재 처리중인 뷰와 같은 추가 정보를 필요로 할 때 유용할 수 있습니다. 83 | `EXCEPTION_HANDLER`설정 키를 사용하여 설정에서 exception handler를 구성해야합니다. 예: 84 | 85 | ```python 86 | REST_FRAMEWORK = { 87 | 'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler' 88 | } 89 | ``` 90 | 지정하지 않으면 `EXCEPTION_HANDLER` 설정의 기본값은 REST 프레임워크에서 제공하는 표준 exception handler로 설정됩니다. 91 | 92 | ```python 93 | REST_FRAMEWORK = { 94 | 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler' 95 | } 96 | ``` 97 | exception handler는 발생하는 예외에 의해 생성 된 응답에 대해서만 호출됩니다. serializer 유효성 검사가 실패 할 때 generic view에서 반환되는 `HTTP_400_BAD_REQUEST`응답과 같이 뷰에서 직접 반환 된 응답에는 사용되지 않습니다. 98 | 99 | --- 100 | 101 | ## API Reference 102 | 103 | ### APIException 104 | **Signature**: `APIException()` 105 | `APIView`클래스 또는 `@api_view`내부에서 발생한 모든 예외에 대한 기본 클래스입니다. 106 | custom exception을 제공하려면, `APIException`을 서브클래스화하고 클래스의 `.status_code`, `.default_detail` 및 `default_code`속성을 설정하세요. 107 | 예를 들어, API가 가끔 도달 할 수 없는 제3자 서비스에 의존하는 경우, "503 Service Unavailable" HTTP response 코드에 대한 예외를 구현할 수 있습니다. 우리는 이렇게 할 수 있습니다. 108 | 109 | ```python 110 | from rest_framework.exceptions import APIException 111 | 112 | class ServiceUnavailable(APIException): 113 | status_code = 503 114 | default_detail = 'Service temporarily unavailable, try again later.' 115 | default_code = 'service_unavailable' 116 | ``` 117 | 118 | #### Inspecting API exceptions 119 | API exception을 검사하는데 사용할 수 있는 여러 속성이 있습니다. 이를 사용하여 프로젝트에 대한 custom exception를 빌드 할 수 있습니다. 120 | 사용 가능한 속성 및 메서드는 다음과 같습니다. 121 | 122 | - `.detail` : 오류의 텍스트 설명을 리턴합니다. 123 | - `.get_codes()` : 오류의 코드 식별자를 반환합니다. 124 | - `.get_full_details()` : 텍스트 설명과 코드 식별자를 반환합니다. 125 | 126 | 대부분의 경우 오류 세부 사항은 간단한 항목입니다. 127 | 128 | ```python 129 | >>> print(exc.detail) 130 | You do not have permission to perform this action. 131 | >>> print(exc.get_codes()) 132 | permission_denied 133 | >>> print(exc.get_full_details()) 134 | {'message':'You do not have permission to perform this action.','code':'permission_denied'} 135 | ``` 136 | 유효성 검사 오류의 경우 오류 세부 정보는 list나 dict입니다. 137 | 138 | ```python 139 | >>> print(exc.detail) 140 | {"name":"This field is required.","age":"A valid integer is required."} 141 | >>> print(exc.get_codes()) 142 | {"name":"required","age":"invalid"} 143 | >>> print(exc.get_full_details()) 144 | {"name":{"message":"This field is required.","code":"required"},"age":{"message":"A valid integer is required.","code":"invalid"}} 145 | ``` 146 | 147 | ### ParseError 148 | **Signature**: `ParseError(detail=None, code=None)` 149 | `request.data`에 엑서스 할 때 request에 잘못된 데이터가 포함 된 경우 발생합니다. 150 | 기본적으로 이 예외는 HTTP status code "400 Bad Request"로 응답합니다. 151 | 152 | ### AuthenticationFailed 153 | **Signature**: `AuthenticationFailed(detail=None, code=None)` 154 | 들어오는 request에 잘못된 인증이 포함될 떄 발생합니다. 155 | 기본적으로 이 예외로 인해 HTTP status code "401 Unauthenticated"가 반환되지만, 사용중인 인증 방식에 따라 "403 Forbidden" 응답이 발생할 수도 있습니다. 자세한 내용은 [인증 문서](http://www.django-rest-framework.org/api-guide/authentication/)를 참조하세요. 156 | 157 | ### NotAuthenticated 158 | **Signature**: `NotAuthenticated(detail=None, code=None)` 159 | 인증되지 않은 요청이 권한 검사에 실패하면 발생합니다. 160 | 기본적으로 이 예외로 인해 HTTP status code "401 Unauthenticated"가 반환되지만 사용중인 인증 방식에 따라 "403 Forbidden"응답이 발생 할 수도 있습니다. 자세한 내용은 [인증 문서](http://www.django-rest-framework.org/api-guide/authentication/)를 참조하세요. 161 | 162 | ### PermissionDenied 163 | **Signature**: `PermissionDenied(detail=None, code=None)` 164 | 인증 된 요청이 권한 검사에 실패하면 발생합니다. 165 | 기본적으로 이 예외는 HTTP status code "403 Forbidden"으로 응답하니다. 166 | 167 | ### NotFound 168 | **Signature**: `NotFound(detail=None, code=None)` 169 | 주어진 URL에 resource가 없을 때 발생합니다. 이 예외는 표준 `Http404` Django exception과 동일합니다. 170 | 기본적으로 이 예외는 HTTP status code "404 Not Found"으로 응답합니다. 171 | 172 | ### MethodNotAllowed 173 | **Signature**: `MethodNotAllowed(method, detail=None, code=None)` 174 | 뷰의 handler 메서드에 매핑되지 않는 들어오는 request가 발생했을 떄 발생합니다. 175 | 기본적으로 이 예외는 HTTP status code "405 Method Not Allowed"로 응답합니다. 176 | 177 | ### NotAcceptable 178 | **Signature**: `NotAcceptable(detail=None, code=None)` 179 | 사용 가능한 randerer에서 만족 할 수 없는 `Accept`헤더로 들어오는 request가 발생할때 발생합니다. 180 | 기본적으로 이 예외는 HTTP status code "406 Not Acceptable"으로 응답합니다. 181 | 182 | ### UnsupportedMediaType 183 | **Signature**: `UnsupportedMediaType(media_type, detail=None, code=None)` 184 | `request.data`에 엑서스 할 때 request 데이터의 내용 유형을 처리 할 수 있는 parser가 없는 경우 발생합니다. 185 | 기본적으로 이 예외는 HTTP status code "415 Unsupported Media Type"으로 응답합니다. 186 | 187 | ### Throttled 188 | **Signature**: `Throttled(wait=None, detail=None, code=None)` 189 | 들어오는 request가 throttle 검사에 실패하면 발생합니다. 190 | 기본적으로 이 예외는 HTTP status code "429 Too Many Requests"으로 응답합니다. 191 | 192 | ### ValidationError 193 | **Signature**: `ValidationError(detail, code=None)` 194 | `ValidationError` 예외는 다른 `APIException`클래스와 약간 다릅니다. 195 | 196 | - `detail` 인수는 필수입니다. 선택사항이 아닙니다. 197 | - `detail`인수는 오류 세부 사항 list 또는 dict 일 수 있으며, 중첩된 데이터 구조 일 수도 있습니다. 198 | - 규약에 따라 serializer 모듈을 가져와 정규화 된 `ValidationError` 스타일을 사용하여 Django의 기본 유효성 검사 오류와 구별해야합니다. 예: `raise serializers.ValidationError('이 필드는 정수(Integer)값이어야 합니다.')` 199 | 200 | `ValidationError` 클래스는 serializer 및 필드 유효성 검사 및 유효성 검사기 클래스에 사용해야합니다. 또한 `raise_exception` 키워드 인수로 `serializer.is_valid`를 호출 할 때 발생합니다. 201 | 202 | ``` 203 | serializer.is_valid(raise_exception=True) 204 | ``` 205 | generic view는 `raise_exception=True`플래그를 사용합니다. 즉, API에서 유효성 검증 오류 응답의 스타일을 대체할 수 있습니다. 이렇게 하려면 위에서 설명한대로 custom exception handler를 사용하세요. 206 | 기본적으로 이 예외는 HTTP status code "400 Bad Request"으로 응답합니다. 207 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 25. Status Codes.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Status Codes 2 | 3 | --- 4 | 5 | _"418 I'm a teapot - Any attempt to brew coffee with a teapot should result in the error code "418 I'm a teapot". The resulting entity body MAY be short and stout."_ 6 | 7 | _"418 저는 주전자입니다 - 주전자로 커피를 양조하려고하면 "418 나는 주전자입니다"라는 오류 코드가 나타납니다. 그 결과로 생성 된 실제 몸체는 짧고 튼튼 할 수 있다."_ 8 | 9 | _— RFC 2324, Hyper Text Coffee Pot Control Protocol_ 10 | 11 | --- 12 | 13 | ## Status Codes 14 | 응답에 베어 상태 코드를 사용하는 것은 좋지 않습니다. REST 프레임워크에는 더 많은 코드를 보다 명확하고 읽기 쉽게 만드는데 사용 할 수 있는 명명 된 상수 set이 포함되어 있습니다. 15 | 16 | ```python 17 | from rest_framework import status 18 | from rest_framework.response import Response 19 | 20 | def empty_view(self): 21 | content = {'please move along': 'nothing to see here'} 22 | return Response(content, status=status.HTTP_404_NOT_FOUND) 23 | ``` 24 | `status` 모듈에 포함된 HTTP status code의 full set은 다음과 같습니다. 25 | 모듈에는 status code가 주어진 범위에 있는지 테스트하기 위한 helper 함수 set가 포함되어 있습니다. 26 | 27 | ```python 28 | from rest_framework import status 29 | from rest_framework.test import APITestCase 30 | 31 | class ExampleTestCase(APITestCase): 32 | def test_url_root(self): 33 | url = reverse('index') 34 | response = self.client.get(url) 35 | self.assertTrue(status.is_success(response.status_code)) 36 | ``` 37 | HTTP status code의 올바른 사용법에 대한 자세한 내용은 [RFC 2616](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)와 [RFC 6585](https://tools.ietf.org/html/rfc6585)를 참조사헤요. 38 | 39 | ### Informational - 1xx 40 | 이 status code 클래스는 잠정적인 응답을 나타냅니다. 기본적으로 REST 프레임워크에는 1xx status code가 사용되지 않습니다. 41 | 42 | ``` 43 | HTTP_100_CONTINUE 44 | HTTP_101_SWITCHING_PROTOCOLS 45 | ``` 46 | 47 | ### Successful - 2xx 48 | 이 status code 클래스는 클라이언트 요청이 성공적으로 수신, 이해, 승인되었음을 나타냅니다. 49 | 50 | ``` 51 | HTTP_200_OK 52 | HTTP_201_CREATED 53 | HTTP_202_ACCEPTED 54 | HTTP_203_NON_AUTHORITATIVE_INFORMATION 55 | HTTP_204_NO_CONTENT 56 | HTTP_205_RESET_CONTENT 57 | HTTP_206_PARTIAL_CONTENT 58 | HTTP_207_MULTI_STATUS 59 | ``` 60 | 61 | ### Redirection - 3xx 62 | 이 status code 클래스는 요청을 수행하기 위해 사용자 에이전트가 추가 조치를 취해야 함을 나타냅니다. 63 | 64 | ``` 65 | HTTP_300_MULTIPLE_CHOICES 66 | HTTP_301_MOVED_PERMANENTLY 67 | HTTP_302_FOUND 68 | HTTP_303_SEE_OTHER 69 | HTTP_304_NOT_MODIFIED 70 | HTTP_305_USE_PROXY 71 | HTTP_306_RESERVED 72 | HTTP_307_TEMPORARY_REDIRECT 73 | ``` 74 | 75 | ### Client Error - 4xx 76 | 4xx 클래스의 status code는 클라이언트가 오류가 있는 것으로 보이는 경우를 위한 것입니다. HEAD request에 응답 할 때를 제외하고, 서버 SHOULD는 오류 상황에 대한 설명과 일시적인 것인지 지속적인 것인지를 포함한 엔티티를 포함해야합니다. 77 | 78 | ``` 79 | HTTP_400_BAD_REQUEST 80 | HTTP_401_UNAUTHORIZED 81 | HTTP_402_PAYMENT_REQUIRED 82 | HTTP_403_FORBIDDEN 83 | HTTP_404_NOT_FOUND 84 | HTTP_405_METHOD_NOT_ALLOWED 85 | HTTP_406_NOT_ACCEPTABLE 86 | HTTP_407_PROXY_AUTHENTICATION_REQUIRED 87 | HTTP_408_REQUEST_TIMEOUT 88 | HTTP_409_CONFLICT 89 | HTTP_410_GONE 90 | HTTP_411_LENGTH_REQUIRED 91 | HTTP_412_PRECONDITION_FAILED 92 | HTTP_413_REQUEST_ENTITY_TOO_LARGE 93 | HTTP_414_REQUEST_URI_TOO_LONG 94 | HTTP_415_UNSUPPORTED_MEDIA_TYPE 95 | HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE 96 | HTTP_417_EXPECTATION_FAILED 97 | HTTP_422_UNPROCESSABLE_ENTITY 98 | HTTP_423_LOCKED 99 | HTTP_424_FAILED_DEPENDENCY 100 | HTTP_428_PRECONDITION_REQUIRED 101 | HTTP_429_TOO_MANY_REQUESTS 102 | HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE 103 | HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS 104 | ``` 105 | 106 | ### Server Error - 5xx 107 | 숫자 "5"로 시작하는 response status code는 서버에 오류가 발생했거나 요청을 수행 할 수 없다는 것을 알고있는 경우를 나타냅니다. HEAD requset에 응답할 때를 제외하고, 서버 SHOULD 는 오류 상황에 대한 설명과 일시적인지 것인지 지속적인 것인지를 포함한 엔티티를 포함해야합니다. 108 | 109 | ``` 110 | HTTP_500_INTERNAL_SERVER_ERROR 111 | HTTP_501_NOT_IMPLEMENTED 112 | HTTP_502_BAD_GATEWAY 113 | HTTP_503_SERVICE_UNAVAILABLE 114 | HTTP_504_GATEWAY_TIMEOUT 115 | HTTP_505_HTTP_VERSION_NOT_SUPPORTED 116 | HTTP_507_INSUFFICIENT_STORAGE 117 | HTTP_511_NETWORK_AUTHENTICATION_REQUIRED 118 | ``` 119 | 120 | ### Helper functions 121 | 다음 helper 함수는 응답 코드의 범주를 식별하는데 사용할 수 있습니다. 122 | 123 | ``` 124 | is_informational() # 1xx 125 | is_success() # 2xx 126 | is_redirect() # 3xx 127 | is_client_error() # 4xx 128 | is_server_error() # 5xx 129 | ``` 130 | -------------------------------------------------------------------------------- /doc/Django REST Framework - 26. Testing.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Testing 2 | 3 | _**"Code without tests is broken as designed." 4 | "테스트가 없는 코드는 의도 한대로 작동하지 않는다." - Jacob Kaplan-Moss**_ 5 | 6 | REST 프레임워크는 Django의 기존 테스트 프레임워크를 확장하고, API Requests 작성에 대한 지원을 향상시키는 서포트 클래스를 포함하고 있습니다. 7 | 8 | ## APIRequestFactory 9 | Django의 기존 `RequestFactory` 클래스를 확장합니다. 10 | 11 | ### Creating test requests 12 | `APIRequestFactory` 클래스는 Django의 표준 `RequestFactory` 클래스와 거의 동일한 API를 지원합니다. 즉 표준 `.get()`, `.post()`, `.put()`, `.patch()`, `.delete()`, `.head()` 및 `.options()` 메서드를 모두 사용할 수 있습니다. 13 | 14 | ``` 15 | rom rest_framework.test import APIRequestFactory 16 | 17 | # 표준 `RequestFactory` API을 사용ㅎ여 POST request form을 만든다. 18 | factory = APIRequestFactory() 19 | request = factory.post('/notes/', {'title': 'new idea'}) 20 | ``` 21 | 22 | #### Using the `format` argument 23 | `post`,`put`,`patch`와 같은 requests를 만드는 메서드에는 content type을 사용하여 requests를 쉽게 생성 할 수 있도록 하는 argument가 포함되어 있습니다. 24 | 25 | ``` 26 | # Create a JSON POST request 27 | factory = APIRequestFactory() 28 | request = factory.post('/notes/', {'title': 'new idea'}, format='json') 29 | ``` 30 | 31 | 기본적으로 사용 가능한 형식은 `multipart`와 `json`입니다. Django의 기존 `RequestFactory`와의 호환성을 위해 기본 형식은 `multipart`입니다. 32 | 33 | 더 많은 형식에 대한 정보는 [configuration section](http://www.django-rest-framework.org/api-guide/testing/#configuration)을 참조하세요. 34 | 35 | #### Explicitly encoding the request body 36 | request 본문을 명시적으로 인코딩해야 하는 경우 `context_type` 플래그를 설정하여 request 본문을 인코딩할 수 있습니다. 37 | 38 | ``` 39 | request = factory.post('/notes/', json.dumps({'title': 'new idea'}), content_type='application/json') 40 | ``` 41 | 42 | #### PUT and PATCH with form data 43 | Django의 `RequestFactory`와 REST 프레임 워크의 `APIRequestFactory` 사이에 주목할 만한 차이점은 다중 파트 양식 데이터가 `.post()` 이외의 메소드로 인코딩된다는 것입니다. 44 | 45 | 예를 들어, `APIRequestFactory`를 사용하면 다음과 같이 `put`요청을 할 수 있습니다. 46 | 47 | ``` 48 | factory = APIRequestFactory() 49 | request = factory.put('/notes/547/', {'title': 'remember to email dave'}) 50 | ``` 51 | 52 | Django의 `RequestFactory`를 사용하면 명시적으로 데이터를 직접 인코딩해야합니다. 53 | 54 | ``` 55 | from django.test.client import encode_multipart, RequestFactory 56 | 57 | factory = RequestFactory() 58 | data = {'title': 'remember to email dave'} 59 | content = encode_multipart('BoUnDaRyStRiNg', data) 60 | content_type = 'multipart/form-data; boundary=BoUnDaRyStRiNg' 61 | request = factory.put('/notes/547/', content, content_type=content_type) 62 | ``` 63 | 64 | #### Forcing authentication 65 | `RequestFactory`를 사용하여 직접 뷰를 테스트 할 때는 인증자격 증명을 작성하지않고 직접 자격요청을 인증하는 것이 편리합니다. 66 | 67 | 강제 요청을 인증하려면 `force_authenticate()` 메소드를 사용하십시오. 68 | 69 | ``` 70 | from rest_framework.test import force_authenticate 71 | 72 | factory = APIRequestFactory() 73 | user = User.objects.get(username='olivia') 74 | view = AccountDetail.as_view() 75 | 76 | # Make an authenticated request to the view... 77 | request = factory.get('/accounts/django-superstars/') 78 | force_authenticate(request, user=user) 79 | response = view(request) 80 | ``` 81 | 82 | 이 메소드의 서명은 `force_authenticate(request, user = None, token = None)`입니다. 전화를 걸 때 사용자와 토큰 중 하나 또는 둘 모두가 설정 될 수 있습니다. 83 | 84 | 예를 들어, 토큰을 사용하여 강제로 인증하는 경우 다음과 같이 할 수 있습니다. 85 | 86 | ``` 87 | user = User.objects.get(username='olivia') 88 | request = factory.get('/accounts/django-superstars/') 89 | force_authenticate(request, user=user, token=user.token) 90 | ``` 91 | 92 | --- 93 | 94 | **Note** : `APIRequestFactory`를 사용할 때 반환되는 객체는 Django의 표준 `HttpRequest`이며, REST 프레임워크의 Request 객체는 아니며 뷰가 호출 된 후에만 ​​생성됩니다. 95 | 즉, request 객체에 직접 속성을 설정하면 항상 원하는 결과를 얻을 수 없을 수도 있습니다. 96 | 예를 들어, `.token`을 직접 설정해도 아무 효과도 없으며 세선 인증을 사용하는 경우 `.user`를 직접 설정할 수 있습니다. 97 | 98 | ``` 99 | # Request은`SessionAuthentication`이 사용 중일 때에 만 인증합니다. 100 | request = factory.get('/accounts/django-superstars/') 101 | request.user = user 102 | response = view(request) 103 | ``` 104 | 105 | --- 106 | 107 | #### Forcing CSRF validation 108 | 기본적으로 `APIRequestFactory`으로 생성 된 request에는 REST 프레임워크 뷰에 전달 될 때 CSRF 유효성 검사가 적용되지 않습니다. 109 | CSRF 유효성 검사를 명시적으로 수행해야하는 경우, 팩토리를 인스턴스화 할 때 `enforce_csrf_checks` 플래그를 설정하면됩니다. 110 | 111 | ``` 112 | factory = APIRequestFactory(enforce_csrf_checks=True) 113 | ``` 114 | 115 | --- 116 | 117 | **Note** : Django의 표준 `RequestFactory`는 이 옵션을 포함할 필요가 없다는 사실에 주목해야 합니다. Django를 사용할 때 뷰를 직접 테스트 할 때 실행되지 않는 미들웨어에서 CSRF 유효성 검사가 수행되기 때문입니다. REST 프레임워크를 사용할 때 뷰 내부에서 CSRF 유효성 검사가 수행되므로 요청 팩토리는 뷰 수준의 CSRF 검사를 비활성화해야합니다. 118 | 119 | --- 120 | 121 | ### APIClient 122 | Django의 기존 `Client`클래스를 확장합니다. 123 | 124 | #### Making requests 125 | `APIClient`클래스는 DJango의 표준 Client클래스와 동일한 요청 인터페이스를 지원합니다. 즉, `.get()`, `.post()`, `.put()`, `.patch()`, `.delete()`, `.head()`, `.options()` 메서드를 모두 사용할 수 있습니다. 126 | 127 | ``` 128 | from rest_framework.test import APIClient 129 | 130 | client = APIClient() 131 | client.post('/notes/', {'title': 'new idea'}, format='json') 132 | ``` 133 | 더 만은 정보는 [configuration section](http://www.django-rest-framework.org/api-guide/testing/#configuration)를 참조하세요. 134 | 135 | #### Authenticating 136 | 137 | ##### .login(**kwargs) 138 | `login`메소드는 Django의 `Cilent`클래스와 똑같이 작동합니다. 이렇게 하면 `SessionAuthentication`이 포함된 모든 views에 대한 요청을 인증 할 수 있습니다. 139 | 140 | ``` 141 | # Make all requests in the context of a logged in session. 142 | client = APIClient() 143 | client.login(username='lauren', password='secret') 144 | ``` 145 | 로그아웃하려면 `logout`메소드를 호출하세요. 146 | 147 | ``` 148 | # Log out 149 | client.logout() 150 | ``` 151 | `login` 메소드는 `AJAX API`와의 상호 작용을 포함하는 웹 사이트와 같이 세션 인증을 사용하는 API를 테스트하는데 적합합니다. 152 | 153 | ##### .credentials(**kwargs) 154 | `credentials`메소드는 테스트 클라이언트가 모든 후속 요청에 포함 할 헤더를 설정하는데 사용할 수 있습니다. 155 | 156 | ``` 157 | from rest_framework.authtoken.models import Token 158 | from rest_framework.test import APIClient 159 | 160 | # Include an appropriate `Authorization:` header on all requests. 161 | token = Token.objects.get(user__username='lauren') 162 | client = APIClient() 163 | client.credentials(HTTP_AUTHORIZATION='Token ' + token.key) 164 | ``` 165 | `credentials`를 다시 호출하면 기존 `credentials`을 덮어 씁니다. 인수없이 메서드를 호출하여 기존 `credentials`의 설정을 해제할 수 있습니다. 166 | 167 | ``` 168 | # Stop including any credentials 169 | client.credentials() 170 | ``` 171 | `credentials` 방법은 기본인증, OAuth1a과 OAuth2 인증 및 간단한 토큰 인증스키마와 같은 인증 헤더가 필요한 API를 테스트하는데 적합합니다. 172 | 173 | ##### .force_authenticate(user=None, token=None) 174 | 때로는 인증을 생략하고 테스트 클라이언트의 모든 요청을 인증 된 것으로 자동처리하도록 할 수 있습니다. 175 | 176 | 이는 API를 테스트하고 있지만 테스트 요청을 하기 위해 유효한 자격 증명을 작성하지 않으려는 경우 유용한 단축키입니다. 177 | 178 | ``` 179 | user = User.objects.get(username='lauren') 180 | client = APIClient() 181 | client.force_authenticate(user=user) 182 | ``` 183 | 후속 요청을 인증 해제하려면 `force_authenticate`를 호출하여 사용자/토큰을 `None`으로 설정하세요. 184 | 185 | ``` 186 | client.force_authenticate(user=None) 187 | ``` 188 | 189 | #### CSRF validation 190 | 기본적으로 CSRF 유효성 검사는 APICLient를 사용할 떄 적합하지 않습니다. CSRF 유효성 검사를 명시적으로 활성화해야하는 경우 Client를 인스턴스화 할때 `enforce_csrf_checks`플래그를 설정하면 됩니다. 191 | 192 | ``` 193 | client = APIClient(enforce_csrf_checks=True) 194 | ``` 195 | 평소처럼 CSRF 유효성검사는 세션 인증 된 views에만 적용됩니다. 즉, 클라이언트가 `login()`을 호출하려 로그인한 경우에만 CSRF 유효성 검사가 수행됩니다. 196 | 197 | --- 198 | 199 | ### RequestsClient 200 | RESR 프레임워크에는 `request`(Python 라이브러리)를 사용하여 애플리케이션과 상호 작용하는 client도 포함되어 있습니다. 다음과 같은 경우 유용하게 사용할 수 있습니다. 201 | 202 | - 주로 다른 Python 서비스의 API와의 인터페이스를 기대하고 있으며, client가 볼 수 있는 것과 동일한 수준에서 서비스를 테스트하려 할 때 203 | - 준비 또는 실제 환경에 대해 실행할 수 있는 방식으로 테스트를 작성할 때 ("Live test" 참조) 204 | 205 | 이는 requests 세션을 직접 사용하는 것과 동일한 인터페이스를 제공합니다. 206 | 207 | ``` 208 | client = RequestsClient() 209 | response = client.get('http://testserver/users/') 210 | assert response.status_code == 200 211 | ``` 212 | requests client에서는 정규화 된 URL을 전달해야 합니다. 213 | 214 | #### `RequestsClient` and working with the database 215 | `RequestsClient`클래스는 서비스 인터페이스만 상호 작용하는 테스트를 작성하려는 경우에 유용합니다. 이것은 Django 테스트 클라이언트를 사용하는 것보다 조금 더 엄격합니다. 모든 상호작용이 API를 통해 이루어져야하기 떄문입니다. 216 | `RequestsClient`를 사용하는 경우 데이터베이스 모델과 직접 상호 작용하는 대신 테스트 설정 및 결과 주장(?)을 일반 API 호출로 수행해야합니다. 217 | 예를 들어, `Customer.objects.count () == 3`를 확인하는 대신 `customers` 마지막점을 나열하고 3개의 레코드가 있는지 확인하세요. 218 | 219 | #### Headers & Authentication 220 | custom 헤더와 인증자격 증명은 `requests.Session` 인스턴스를 사용할 때와 동일한 방식으로 제공 될 수 있습니다. 221 | 222 | ``` 223 | from requests.auth import HTTPBasicAuth 224 | 225 | client.auth = HTTPBasicAuth('user', 'pass') 226 | client.headers.update({'x-test': 'true'}) 227 | ``` 228 | 229 | #### CSRF 230 | `SessionAuthentication`을 사용하는 경우 `POST`, `PUT`, `PATCH`, `DELETE` 요청에 대해 CSRF 토큰을 포함해야합니다. 231 | JavaScript 기반의 클라이언트가 사용하는 것과 동일한 흐름으로 수행 할 수 있습니다. 232 | 먼저 CRSF 토큰을 얻기 위해 `GET` 요청을 하고 다음 요청에 토큰을 제시하십시오. 233 | 234 | ``` 235 | client = RequestsClient() 236 | 237 | # Obtain a CSRF token. 238 | response = client.get('/homepage/') 239 | assert response.status_code == 200 240 | csrftoken = response.cookies['csrftoken'] 241 | 242 | # Interact with the API. 243 | response = client.post('/organisations/', json={ 244 | 'name': 'MegaCorp', 245 | 'status': 'active' 246 | }, headers={'X-CSRFToken': csrftoken}) 247 | assert response.status_code == 200 248 | ``` 249 | #### Live tests 250 | 신중하게 사용하면 `RequestsClient`와 `CoreAPIClient`가 모두 개발 환경에서 실행되거나 준비 서버 또는 프로덕션 환경에 직접 실행 될 수 있는 테스트 사례를 작성할 수 있습니다. 251 | 이럼 스타일로 몇 가지 핵심 기능 중 일부에 대한 기본 테스트를 만드는 것은 실제 서비스를 확인하는 강력한 방법입니다. 이렇게하려면 테스트가 고객 데이터에 직접 영향을 주지 않는 방식으로 실행되도록 설정 및 해제하는데 신중을 기해야합니다. 252 | 253 | --- 254 | 255 | ### CoreAPIClient 256 | `CoreAPIClient`를 사용하면 `coreapi` (Python 클라이언트 라이브러리)를 사용하여 API와 상호 작용할 수 있습니다. 257 | 258 | ``` 259 | # Fetch the API schema 260 | client = CoreAPIClient() 261 | schema = client.get('http://testserver/schema/') 262 | 263 | # Create a new organisation 264 | params = {'name': 'MegaCorp', 'status': 'active'} 265 | client.action(schema, ['organisations', 'create'], params) 266 | 267 | # Ensure that the organisation exists in the listing 268 | data = client.action(schema, ['organisations', 'list']) 269 | assert(len(data) == 1) 270 | assert(data == [{'name': 'MegaCorp', 'status': 'active'}]) 271 | ``` 272 | 273 | #### Headers & Authentication 274 | Customs 헤더와 인증은 `RequestsClient`와 비슷한 방식으로 `CoreAPIClient`와 함께 사용할 수 있습니다. 275 | 276 | ``` 277 | from requests.auth import HTTPBasicAuth 278 | 279 | client = CoreAPIClient() 280 | client.session.auth = HTTPBasicAuth('user', 'pass') 281 | client.session.headers.update({'x-test': 'true'}) 282 | ``` 283 | 284 | --- 285 | 286 | ### Test cases 287 | REST 프레임워크는 DJango 테스트 케이스 클래스를 반영하지만, Django의 기본 클라이언트 대신 `APIClient`를 사용하는 테스트 케이스 클래스를 포함합니다. 288 | 289 | - APISimpleTestCase 290 | - APITransactionTestCase 291 | - APITestCase 292 | - APILiveServerTestCase 293 | 294 | #### Example] 295 | Django 테스트케이스 클래스처럼 REST 프레임워크의 테스트 케이스 클래스 중 하나를 사용할 수 있습니다. `self.client` 속성은 `APIClient` 인스턴스입니다. 296 | 297 | ``` 298 | from django.urls import reverse 299 | from rest_framework import status 300 | from rest_framework.test import APITestCase 301 | from myproject.apps.core.models import Account 302 | 303 | class AccountTests(APITestCase): 304 | def test_create_account(self): 305 | """ 306 | Ensure we can create a new account object. 307 | """ 308 | url = reverse('account-list') 309 | data = {'name': 'DabApps'} 310 | response = self.client.post(url, data, format='json') 311 | self.assertEqual(response.status_code, status.HTTP_201_CREATED) 312 | self.assertEqual(Account.objects.count(), 1) 313 | self.assertEqual(Account.objects.get().name, 'DabApps') 314 | ``` 315 | 316 | --- 317 | 318 | ### Testing responses 319 | 320 | #### Checking the response data 321 | 테스트 응답의 유효성을 검사 할 때 완전히 렌더링 된 응답을 검사하는 것보다 응답이 생성 된 데이터를 검사하는 것이 더 편리합니다. 322 | 323 | 예를 들어, `response.data`를 검사하는 것이 더 쉽습니다. 324 | 325 | ``` 326 | response = self.client.get('/users/4/') 327 | self.assertEqual(response.data, {'id': 4, 'username': 'lauren'}) 328 | ``` 329 | 330 | `response.content`를 구문 분석한 결과를 검사하는 대신: 331 | 332 | ``` 333 | response = self.client.get('/users/4/') 334 | self.assertEqual(json.loads(response.content), {'id': 4, 'username': 'lauren'}) 335 | ``` 336 | 337 | #### Rendering responses 338 | `APIRequestFactory`를 사용하여 뷰를 직접 테스트하는 경우, 템플릿 응답의 렌더링이 Django의 내부 requests - response 에 의해 수행되기 때문에 반환되는 응답은 아직 렌더링되지 않습니다. `response.content`에 액세스하려면 먼저 응답을 렌더링해야합니다. 339 | 340 | ``` 341 | view = UserDetail.as_view() 342 | request = factory.get('/users/4') 343 | response = view(request, pk='4') 344 | response.render() # Cannot access `response.content` without this. 345 | self.assertEqual(response.content, '{"username": "lauren", "id": 4}') 346 | ``` 347 | 348 | --- 349 | 350 | ### Configuration 351 | 352 | #### Setting the default format 353 | 테스트 요청을하는 데 사용되는 기본 형식은 `TEST_REQUEST_DEFAULT_FORMAT` 설정 키를 사용하여 설정할 수 있습니다. 예를 들어, 테스트 요청을 항상 `JSON`을 사용하려면 `settings.py`파일에서 다음을 설정하세요. 354 | 355 | ``` 356 | REST_FRAMEWORK = { 357 | ... 358 | 'TEST_REQUEST_DEFAULT_FORMAT': 'json' 359 | } 360 | ``` 361 | 362 | #### Setting the available formats 363 | multipart 또는 `json` 요청 이외의 것을 사용하여 요청을 테스트해야하는 경우 `TEST_REQUEST_RENDERER_CLASSES` 설정을 설정하여 요청을 테스트 할 수 있습니다. 364 | 365 | 예를 들어, 테스트 요청에 `format = 'html'`을 추가하려면 `settings.py` 파일에 다음과 같은 내용이 추가합니다. 366 | 367 | ``` 368 | REST_FRAMEWORK = { 369 | ... 370 | 'TEST_REQUEST_RENDERER_CLASSES': ( 371 | 'rest_framework.renderers.MultiPartRenderer', 372 | 'rest_framework.renderers.JSONRenderer', 373 | 'rest_framework.renderers.TemplateHTMLRenderer' 374 | ) 375 | } 376 | ``` -------------------------------------------------------------------------------- /doc/Django REST Framework - 27. Settings.md: -------------------------------------------------------------------------------- 1 | # Django REST Framework - Settings 2 | 3 | --- 4 | 5 | _"Namespaces are one honking great idea - let's do more of those!"_ 6 | 7 | _"네임 스페이스는 훌륭한 아이디어를 제공합니다. let's do more of those!"_ 8 | 9 | _— The Zen of Python_ 10 | 11 | --- 12 | 13 | ## Settings 14 | REST 프레임워크의 모든 설정은 `REST_FRAMEWORK`라는 단일 Django 설정에 네임 스페이스를 설정합니다. 15 | 예를 들어 프로젝트의 `settings.py`파일에는 다음과 같은 내용이 포함될 수 있습니다. 16 | 17 | ```python 18 | REST_FRAMEWORK = { 19 | 'DEFAULT_RENDERER_CLASSES': ( 20 | 'rest_framework.renderers.JSONRenderer', 21 | ), 22 | 'DEFAULT_PARSER_CLASSES': ( 23 | 'rest_framework.parsers.JSONParser', 24 | ) 25 | } 26 | ``` 27 | 28 | ### Accessing settings 29 | 프로젝트에서 REST 프레임워크의 API 설정값에 액서스해야하는 경우 `api_settings`객체를 사용해야합니다. 예를 들면. 30 | 31 | ```python 32 | from rest_framework.settings import api_settings 33 | 34 | print api_settings.DEFAULT_AUTHENTICATION_CLASSES 35 | ``` 36 | `api_settings`객체는 사용자가 정의한 설정을 확인하고 그렇지 않으면 기본값을 fall back합니다. 클래스를 참조하기 위해 string import path를 사용하여 모든 설정은 문자열 리터럴 대신 참조 된 클래스를 자동으로 가져오고 반환합니다. 37 | 38 | --- 39 | 40 | ## API Reference 41 | 42 | ### API policy settings 43 | 다음 설정은 기본 API 정책을 제어하며 모든 `APIView` CBV 또는 `@api_view` FBV에 적용됩니다. 44 | 45 | #### `DEFAULT_RENDERER_CLASSES` 46 | `Response` 객체를 반환할 때 사용할 수 있는 renderer의 기본 set을 결정하는 rederer 클래스의 list 또는 tuple입니다. 47 | 48 | Default: 49 | 50 | ```python 51 | ( 52 | 'rest_framework.renderers.JSONRenderer', 53 | 'rest_framework.renderers.BrowsableAPIRenderer', 54 | ) 55 | ``` 56 | #### `DEFAULT_PARSER_CLASSES` 57 | `request.data`속성에 액서스 할 때 사용되는 parser의 기본 set을 결정하는 parser 클래스의 list 또는 tuple입니다. 58 | 59 | Default: 60 | 61 | ```python 62 | ( 63 | 'rest_framework.parsers.JSONParser', 64 | 'rest_framework.parsers.FormParser', 65 | 'rest_framework.parsers.MultiPartParser' 66 | ) 67 | ``` 68 | 69 | #### `DEFAULT_AUTHENTICATION_CLASSES` 70 | `request.user` 또는 `request.auth`등록 정보에 액서스할 때 사용되는 인증자의 기본 set을 판별하는 authentication 클래스의 list 또는 tuple입니다. 71 | 72 | Default: 73 | 74 | ```python 75 | ( 76 | 'rest_framework.authentication.SessionAuthentication', 77 | 'rest_framework.authentication.BasicAuthentication' 78 | ) 79 | ``` 80 | 81 | #### `DEFAULT_PERMISSION_CLASSES` 82 | view의 시작에 체크 된 권한의 기본 set을 결정하는 permission 클래스의 list 또는 tuple입니다. permission은 list의 모든 클래스에서 부여해야합니 다. 83 | 84 | Default: 85 | 86 | ```python 87 | ( 88 | 'rest_framework.permissions.AllowAny', 89 | ) 90 | ``` 91 | 92 | #### `DEFAULT_THROTTLE_CLASSES` 93 | view의 시작에서 점검되는 기본 throttle set을 결정하는 throttle 클래스의 list 또는 tuple입니다. 94 | 95 | Default: `()` 96 | 97 | #### `DEFAULT_CONTENT_NEGOTIATION_CLASS` 98 | 들어오는 request에 따라 rederer가 response에 대해 선택되는 방법을 결정하는 content negotiation 클래스 입니다. 99 | 100 | Default: `'rest_framework.negotiation.DefaultContentNegotiation'` 101 | 102 | --- 103 | 104 | ### Generic view settings 105 | 다음 설정은 generic CBV의 동작을 제어합니다. 106 | 107 | #### `DEFAULT_PAGINATION_SERIALIZER_CLASS` 108 | 109 | --- 110 | 111 | **이 설정은 제거되었습니다.** 112 | 113 | pagination API는 출력 형식을 결정하기 위해 serializer를 사용하지 않으므로 대신 출력 형식 제어 방법을 지정하기 위해 pagination 클래스의 `'get_paginated_response`` 메서드를 대체해야합니다. 114 | 115 | --- 116 | 117 | #### `DEFAULT_FILTER_BACKENDS` 118 | generic 필터링에 사용해야 하는 filter backend 클래스 list입니다. `None`으로 설정하면 generic 필터링이 비활성화됩니다. 119 | 120 | #### `PAGINATE_BY` 121 | 122 | --- 123 | 124 | **이 설정은 제거 되었습니다.** 125 | 126 | pagination 스타일 설정에 대한 자세한 지침은 [setting the pagination style](http://www.django-rest-framework.org/api-guide/pagination/#modifying-the-pagination-style)를 참조하세요. 127 | 128 | --- 129 | #### `PAGE_SIZE` 130 | pagination에 사용할 기본 페이지 크기입니다. `None`으로 설정하면 기본적으로 pagination이 비활성화됩니다. 131 | 132 | Default: `None` 133 | 134 | #### `PAGINATE_BY_PARAM` 135 | 136 | --- 137 | **이 설정은 제거 되었습니다.** 138 | 139 | pagination 스타일 설정에 대한 자세한 지침은 [setting the pagination style](http://www.django-rest-framework.org/api-guide/pagination/#modifying-the-pagination-style)를 참조하세요. 140 | 141 | --- 142 | #### `MAX_PAGINATE_BY` 143 | 144 | --- 145 | **이 설정은 지원 중단 예정입니다.** 146 | 147 | pagination 스타일 설정에 대한 자세한 지침은 [setting the pagination style](http://www.django-rest-framework.org/api-guide/pagination/#modifying-the-pagination-style)를 참조하세요. 148 | 149 | --- 150 | #### SEARCH_PARAM 151 | `SearchFilter`가 사용하는 검색어를 지정하는데 사용 할 수 있는 검색어 parameter의 이름입니다. 152 | 153 | Default: `search` 154 | 155 | #### ORDERING_PARAM 156 | `OrderingFilter`에 의해 반환 된 결과의 순서를 지정하는데 사용할 수 있는 쿼리 parameter의 이름입니다. 157 | 158 | Default: `ordering` 159 | 160 | --- 161 | 162 | ### Versioning settings 163 | 164 | #### DEFAULT_VERSION 165 | 버전 정보가 없는 경우 `request.version`에 사용해야 하는 값입니다. 166 | 167 | Default: `None` 168 | 169 | #### ALLOWED_VERSIONS 170 | 이 값을 설정하면 버전 체계에 의해 반환 될 수 있는 버전 set이 제한되며, 제공된 버전이 이 set에 포함되어 있지 않으면 오류가 발생합니다. 171 | 172 | Default: `none` 173 | 174 | #### VERSION_PARAM 175 | 미디어 타입 또는 URL 쿼리 parameter와 같이 모든 버젼 지정 parameter에 사용해야하는 문자열입니다. 176 | 177 | Default: `version` 178 | 179 | --- 180 | 181 | ### Authentication settings 182 | 다음 설정은 인증되지 않은 요청의 동작을 제어합니다. 183 | 184 | #### UNAUTHENTICATED_USER 185 | 인증되지 않은 요청에 대해 `request.user`를 초기화하는데 사용해야하는 클래스입니다. 186 | 187 | Default: `django.contrib.auth.models.AnonymousUser` 188 | 189 | #### UNAUTHENTICATED_TOKEN 190 | 인증되지 않은 요청에 대해 `request.auth`를 초기화하는데 사용해야 하는 클래스입니다. 191 | 192 | default: `None` 193 | 194 | -- 195 | 196 | ### Test settings 197 | 다음 설정은 APIRequestFactory 및 APIClient의 동작을 제어합니다. 198 | 199 | #### `TEST_REQUEST_DEFAULT_FORMAT` 200 | 테스트 요청을 할때 사용해야하는 기본 형식입니다. 201 | 이 값은 `TEST_REQUEST_RENDERER_CLASSES`설정의 renderer 클래스 중 하나의 형식과 일치해야합니다. 202 | 203 | Default: `'multipart'` 204 | 205 | #### `TEST_REQUEST_RENDERER_CLASSES` 206 | 테스트 요청을 작성할 때 지원되는 renderer 클래스입니다. 207 | `client.post('/users', {'username': 'jamie'}, format='json')` 이러한 renderer 클래스의 형식은 테스트 요청을 구성 할 때 사용할 수 있습니다. 208 | 209 | Default: 210 | 211 | ```python 212 | ( 213 | 'rest_framework.renderers.MultiPartRenderer', 214 | 'rest_framework.renderers.JSONRenderer' 215 | ) 216 | ``` 217 | 218 | --- 219 | 220 | ### Schema generation controls 221 | 222 | #### `SCHEMA_COERCE_PATH_PK` 223 | 이것을 설정하면 schema path parameter를 생성할 때 URL conf의 `'pk'`식별자를 실제 필드 이름으로 매핑합니다. 일반적으로 `'id'`가 됩니다. 이것은 "indentifer"가 좀 더 일반적인 개념인 반면 "primary key"는 세부 사항이므로 보다 적합한 표현을 제공합니다. 224 | 225 | Default: `True` 226 | 227 | #### `SCHEMA_COERCE_METHOD_NAMES` 228 | 이것이 설정되면 내부 viewset 메소드 이름을 schema generation에 사용 딘 외부 액션 이름에 매핑하는데 사용됩니다. 이것은 코드 베이스에서 내부적으로 사용되는 것보다 외부 표현에 더 적합한 이름을 생성할 수 있게 해줍니다. 229 | 230 | Default: `{'retrieve': 'read', 'destroy': 'delete'}` 231 | 232 | --- 233 | 234 | ### Content type controls 235 | 236 | #### `URL_FORMAT_OVERRIDE` 237 | 기본 content negotiation `Accept`을 오버라이드하는데 사용할 수 있는 URL parameter의 이름 요청 URL에서 `format=...` 쿼리 parameter를 사용하여 헤더의 동작을 허용합니다. 238 | 239 | 예: `http://example.com/organizations/?format=csv` 240 | 241 | 이 설정 값이 `None`이면 URL 형식 오버라이드가 비활성화 됩니다. 242 | 243 | Default: `'format'` 244 | 245 | #### `FORMAT_SUFFIX_KWARG` 246 | format suffix를 제공하는데 사용할 수 있는 URL conf의 parameter 이름입니다. 이 설정은 format_suffix_pattern`을 사용하여 접미사로 된 URL패턴을 포함할 때 적용됩니다. 247 | 248 | 예: `http://example.com/organizations.csv/` 249 | 250 | Default: `'format'` 251 | 252 | --- 253 | 254 | ### Date and time formatting 255 | 다음 설정은 날짜 및 시간 표현을 파싱하고 렌더링하는 방법을 제어하는데 사용됩니다. 256 | 257 | #### `DATETIME_FORMAT` 258 | `DateTimeField` Serializer 필드의 출력을 렌더링하기 위해 기본적으로 사용해야 하는 형식 문자열입니다. `None`이면 `DateTimeField` serializer 필드는 Python `datetime`객체를 반환하고, datetime 인코딩은 렌더러에 의해 결정됩니다. 259 | 260 | `None`, `'iso-8601'`또는 Python [strftime format](https://docs.python.org/3/library/time.html#time.strftime) 형식 문자열 주 하나 일 수 있습니다. 261 | 262 | Default: `'iso-8601'` 263 | 264 | #### `DATETIME_INPUT_FORMATS` 265 | `DateTimeField` serializer 필드에 대한 입력을 파싱하기위해 기본적으로 사용해야하는 형식문자열 list입니다. 266 | 문자열 `'iso-8601'`또는 python [strftime format](https://docs.python.org/3/library/time.html#time.strftime)형식 문자열을 포함하는 list일 수 있습니다. 267 | 268 | Default: `['iso-8601']` 269 | 270 | #### `DATE_FORMAT` 271 | `DateField` serializer필드의 출력을 렌더링하기 위해 기본적으로 사용해야하는 형식 문자열입니다. `None`이면 `DateField` serializer 필드는 Python `date` 객체를 반환하고 날짜 인코딩은 렌더러에 의해 결정됩니다. 272 | 273 | `None`, `'iso-8601'`또는 python [strftime format](https://docs.python.org/3/library/time.html#time.strftime)형식 문자열을 포함하는 list일 수 있습니다. 274 | 275 | Default: `['iso-8601']` 276 | 277 | #### `DATE_INPUT_FORMATS` 278 | `DateField` serializer 필드에 대한 입력을 파싱하기 위해 기본적으로 사용해야하는 형식 문자열 list입니다. 279 | 280 | 문자열 `'iso-8601'`또는 python [strftime format](https://docs.python.org/3/library/time.html#time.strftime)형식 문자열을 포함하는 list일 수 있습니다. 281 | 282 | Default: `['iso-8601']` 283 | 284 | #### `TIME_FORMAT` 285 | `TimeField` serializer 필드의 출력을 렌더링 할 때 기본저긍로 사용해야하는 형식 문자열입니다. `None` 이면 `TimeField` serializer 필드는 Python `time` 객체를 반환하고 time 인코딩은 렌더러에 의해 결정됩니다. 286 | 287 | `None`, `'iso-8601'`또는 python [strftime format](https://docs.python.org/3/library/time.html#time.strftime)형식 문자열을 포함하는 list일 수 있습니다. 288 | 289 | Default: `['iso-8601']` 290 | 291 | #### `TIME_INPUT_FORMATS` 292 | `TimeField` serializer 필드에 대한 입력을 파싱하기 위해 기본적으로 사용해야 하는 형식 문자열 list입니다. 293 | 294 | 문자열 `'iso-8601'`또는 python [strftime format](https://docs.python.org/3/library/time.html#time.strftime)형식 문자열을 포함하는 list일 수 있습니다. 295 | 296 | Default: `['iso-8601']` 297 | 298 | --- 299 | 300 | ### Encodings 301 | 302 | #### `UNICODE_JSON` 303 | `True`로 설정하면, JSON response가 response에 유니코드 문자를 허용합니다. 304 | 305 | ``` 306 | {"unicode black star":"★"} 307 | ``` 308 | `False`로 설정하면 JSON response가 다음과 같이 non-ascii 문자를 이스케이프합니다. 309 | 310 | ``` 311 | {"unicode black star":"\u2605"} 312 | ``` 313 | 314 | 두 스타일 모두 [RFC 4627]()을 준수하며 구문적으로 유효한 JSON입니다. 유니코드 스타일은 API 응답을 검사할 때보다 사용자에게 친숙한 것으로 선호됩니다. 315 | 316 | Default: `True` 317 | 318 | #### `COMPACT_JSON` 319 | `True`로 설정하면 JSON response sms `':'`과 `','`문자 다음에 공백없이 간결한 표현을 반환합니다. 320 | 321 | ``` 322 | {"is_admin":false,"email":"jane@example"} 323 | ``` 324 | `False`로 설정하면 JSON 응답이 다음과 같이 약간 더 자세한 표현을 반환합니다. 325 | 326 | ``` 327 | {"is_admin": false, "email": "jane@example"} 328 | ``` 329 | 기본 스타일은 [Heroku's API design guidelines](https://github.com/interagent/http-api-design#keep-json-minified-in-all-responses)에 따라 축소 된 응답을 반환하는 것입니다. 330 | 331 | Default: `True` 332 | 333 | #### `COERCE_DECIMAL_TO_STRING` 334 | 기존 decimal(10진) type을 지원하지 않는 API 표현에서 decimal 오브젝트를 리턴할 때, 일반적으로 값을 문자열로 리턴하는 것이 가장 좋습니다. 따라서 바이너리 부동 소수점 구현에서 발생하는 정밀도의 손실을 피할 수 있습니다. 335 | `True`로 설정하면 serializer `DecimalField` 클래스가 Decimal 객체 대신 문자열을 반환합니다. `False`로 설정하면, serializer는 Decimal 객체를 반환합니다. 이 객체는 기본 JSON 인코더가 float으로 반환합니다. 336 | 337 | Default: `True` 338 | 339 | --- 340 | 341 | ### View names and descriptions 342 | **다음 설정은 `OPTIONS` 요청에 대한 응답 및 Browsable API에서 사용되는 것과 같이 뷰 이름 및 설명을 생성하는데 사용됩니다.** 343 | 344 | #### `VIEW_NAME_FUNCTION` 345 | 뷰 이름을 생성할 때 사용해야하는 함수를 나타내는 문자열입니다. 346 | 이것은 다음 시그니처가 있는 함수이어야 합니다. 347 | 348 | ``` 349 | view_name(cls, suffix=None) 350 | ``` 351 | 352 | - `cls` : 뷰 클래스. 일반적으로 이름 함수는 `cls.__name__`에 액서스하여 설명적인 이름을 생성 할 때 클래스 이름을 검사합니다. 353 | - `suffix` : viewset에서 개별 뷰를 구별 할 때 사용되는 선택적 suffix 354 | 355 | Default: `'rest_framework.views.get_view_name'` 356 | 357 | #### `VIEW_DESCRIPTION_FUNCTION` 358 | 뷰 설명을 생성 할 때 사용해야하는 함수를 나타내는 문자열입니다. 359 | 기본 설정 값 이외의 태그 스타일을 지원하도록 이 설정을 변경할 수 있습니다. 예를 들어, 브라우저에서 볼 수 있는 API로 출력되는 뷰 문서 문자열의 `rst` 마크업을 지원하는데 사용할 수 있습니다. 360 | 이것은 다음 시그니처가 있는 함수이어야 합니다. 361 | 362 | ``` 363 | view_description(cls, html=False) 364 | ``` 365 | 366 | - `cls` : 뷰 클래스. 일반적으로 설명 함수는 `cls.__doc__`에 액서스하여 설명을 생성 할 때 클래스의 문서화 문자열을 검사합니다. 367 | 368 | - `html` : HTML 출력이 필요한지 나타내는 boolean입니다. 탐색 가능한 API에서 사용되면 `True`이고, `OPTIONS`응답을 생성하는데 사용되면 `False`입니다. 369 | 370 | Default: `'rest_framework.views.get_view_description'` 371 | 372 | ### HTML Select Field cutoffs 373 | Browsable API에서 [관계형 필드를 렌더링하기 위한 선택 필드 컷오프](http://www.django-rest-framework.org/api-guide/relations/#select-field-cutoffs)에 대한 전역 설정입니다. 374 | 375 | #### `HTML_SELECT_CUTOFF` 376 | `html_cutoff`값의 전역 설정입니다. 정수이어야 합니다. 377 | 378 | Default: 1000 379 | 380 | #### `HTML_SELECT_CUTOFF_TEXT` 381 | `html_cutoff_text`의 전역 설정을 나타내는 문자열입니다. 382 | 383 | Default: `"More than {count} items..."` 384 | 385 | --- 386 | 387 | ### Miscellaneous settings 388 | 389 | #### `EXCEPTION_HANDLER` 390 | 지정된 예외에 대한 응답을 반환할 때 사용해야하는 함수를 나타내는 문자열입니다. 이 함수가 `None`을 반환하면 500 error가 발생합니다. 391 | 이 설정은 기본 `{"detail": "Failure..."}`응답 이외의 오류 응답을 지원하도록 변경할 수 있습니다. 예를 들어 `{"errors": [{"message": "Failure...", "code": ""} ...]}`와 같은 API 응답을 제공하는데 사용할 수 있습니다. 392 | 393 | 이것은 다음 시그니처가 있는 함수이어야 합니다. 394 | 395 | ``` 396 | exception_handler(exc, context) 397 | ``` 398 | 399 | - `exc` : 예외 400 | 401 | Default: `'rest_framework.views.exception_handler'` 402 | 403 | #### `NON_FIELD_ERRORS_KEY` 404 | 특정 필드를 참조하지 않고 일반적인 오류인 serializer 오류에 사용해야하는 키를 나타내는 문자열입니다. 405 | 406 | Default: `'non_field_errors'` 407 | 408 | #### `URL_FIELD_NAME` 409 | `HyperlinkedModelSerializer`에 의해 생성 된 URL 필드에 사용해야하는 키를 나타내는 문자열입니다. 410 | 411 | Default: `'url'` 412 | 413 | #### `NUM_PROXIES` 414 | API가 실행되는 응용 프로그램 프록시 수를 지정하는데 사용할 수 있는 0 이상의 정수입니다. 이렇게 하면 throttling을 통해 클라이언트 IP 주소를 보다 정확하게 식별할 수 있습니다. `None`으로 설정하면 덜 엄격한 IP 매칭이 throttle 클래스에서 사용됩니다. 415 | 416 | Default: `None` 417 | -------------------------------------------------------------------------------- /doc/images/AdminRenderer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/doc/images/AdminRenderer.png -------------------------------------------------------------------------------- /doc/images/BrowsableAPIRenderer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/doc/images/BrowsableAPIRenderer.png -------------------------------------------------------------------------------- /doc/images/DefaultRouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/doc/images/DefaultRouter.png -------------------------------------------------------------------------------- /doc/images/SimpleRouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/doc/images/SimpleRouter.png -------------------------------------------------------------------------------- /doc/images/fieldfilter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/doc/images/fieldfilter.png -------------------------------------------------------------------------------- /doc/images/genericfiltering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/doc/images/genericfiltering.png -------------------------------------------------------------------------------- /doc/images/linkheader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/doc/images/linkheader.png -------------------------------------------------------------------------------- /doc/images/orderingfilter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/doc/images/orderingfilter.png -------------------------------------------------------------------------------- /doc/images/searchfilter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/doc/images/searchfilter.png -------------------------------------------------------------------------------- /doc/images/serializer.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/doc/images/serializer.jpeg -------------------------------------------------------------------------------- /doc/images/token1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/doc/images/token1.png -------------------------------------------------------------------------------- /doc/images/token2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/doc/images/token2.png -------------------------------------------------------------------------------- /doc/images/token3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/doc/images/token3.png -------------------------------------------------------------------------------- /doc/images/token_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/doc/images/token_delete.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django==1.10.6 2 | djangorestframework==3.6.2 3 | httpie==0.9.9 4 | Pygments==2.2.0 5 | requests==2.13.0 6 | -------------------------------------------------------------------------------- /tutorial/db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/tutorial/db.sqlite3 -------------------------------------------------------------------------------- /tutorial/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tutorial.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError: 10 | # The above import may fail for some other reason. Ensure that the 11 | # issue is really that Django is missing to avoid masking other 12 | # exceptions on Python 2. 13 | try: 14 | import django 15 | except ImportError: 16 | raise ImportError( 17 | "Couldn't import Django. Are you sure it's installed and " 18 | "available on your PYTHONPATH environment variable? Did you " 19 | "forget to activate a virtual environment?" 20 | ) 21 | raise 22 | execute_from_command_line(sys.argv) 23 | -------------------------------------------------------------------------------- /tutorial/snippets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/tutorial/snippets/__init__.py -------------------------------------------------------------------------------- /tutorial/snippets/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /tutorial/snippets/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class SnippetsConfig(AppConfig): 5 | name = 'snippets' 6 | -------------------------------------------------------------------------------- /tutorial/snippets/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.6 on 2017-03-13 17:38 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | initial = True 13 | 14 | dependencies = [ 15 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 16 | ] 17 | 18 | operations = [ 19 | migrations.CreateModel( 20 | name='Snippet', 21 | fields=[ 22 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 23 | ('created', models.DateTimeField(auto_now_add=True)), 24 | ('title', models.CharField(blank=True, default='', max_length=100)), 25 | ('code', models.TextField()), 26 | ('linenos', models.BooleanField(default=False)), 27 | ('language', models.CharField(choices=[('abap', 'ABAP'), ('abnf', 'ABNF'), ('ada', 'Ada'), ('adl', 'ADL'), ('agda', 'Agda'), ('aheui', 'Aheui'), ('ahk', 'autohotkey'), ('alloy', 'Alloy'), ('ampl', 'Ampl'), ('antlr', 'ANTLR'), ('antlr-as', 'ANTLR With ActionScript Target'), ('antlr-cpp', 'ANTLR With CPP Target'), ('antlr-csharp', 'ANTLR With C# Target'), ('antlr-java', 'ANTLR With Java Target'), ('antlr-objc', 'ANTLR With ObjectiveC Target'), ('antlr-perl', 'ANTLR With Perl Target'), ('antlr-python', 'ANTLR With Python Target'), ('antlr-ruby', 'ANTLR With Ruby Target'), ('apacheconf', 'ApacheConf'), ('apl', 'APL'), ('applescript', 'AppleScript'), ('arduino', 'Arduino'), ('as', 'ActionScript'), ('as3', 'ActionScript 3'), ('aspectj', 'AspectJ'), ('aspx-cs', 'aspx-cs'), ('aspx-vb', 'aspx-vb'), ('asy', 'Asymptote'), ('at', 'AmbientTalk'), ('autoit', 'AutoIt'), ('awk', 'Awk'), ('basemake', 'Base Makefile'), ('bash', 'Bash'), ('bat', 'Batchfile'), ('bbcode', 'BBCode'), ('bc', 'BC'), ('befunge', 'Befunge'), ('bib', 'BibTeX'), ('blitzbasic', 'BlitzBasic'), ('blitzmax', 'BlitzMax'), ('bnf', 'BNF'), ('boo', 'Boo'), ('boogie', 'Boogie'), ('brainfuck', 'Brainfuck'), ('bro', 'Bro'), ('bst', 'BST'), ('bugs', 'BUGS'), ('c', 'C'), ('c-objdump', 'c-objdump'), ('ca65', 'ca65 assembler'), ('cadl', 'cADL'), ('camkes', 'CAmkES'), ('capdl', 'CapDL'), ('capnp', "Cap'n Proto"), ('cbmbas', 'CBM BASIC V2'), ('ceylon', 'Ceylon'), ('cfc', 'Coldfusion CFC'), ('cfengine3', 'CFEngine3'), ('cfm', 'Coldfusion HTML'), ('cfs', 'cfstatement'), ('chai', 'ChaiScript'), ('chapel', 'Chapel'), ('cheetah', 'Cheetah'), ('cirru', 'Cirru'), ('clay', 'Clay'), ('clean', 'Clean'), ('clojure', 'Clojure'), ('clojurescript', 'ClojureScript'), ('cmake', 'CMake'), ('cobol', 'COBOL'), ('cobolfree', 'COBOLFree'), ('coffee-script', 'CoffeeScript'), ('common-lisp', 'Common Lisp'), ('componentpascal', 'Component Pascal'), ('console', 'Bash Session'), ('control', 'Debian Control file'), ('coq', 'Coq'), ('cpp', 'C++'), ('cpp-objdump', 'cpp-objdump'), ('cpsa', 'CPSA'), ('cr', 'Crystal'), ('crmsh', 'Crmsh'), ('croc', 'Croc'), ('cryptol', 'Cryptol'), ('csharp', 'C#'), ('csound', 'Csound Orchestra'), ('csound-document', 'Csound Document'), ('csound-score', 'Csound Score'), ('css', 'CSS'), ('css+django', 'CSS+Django/Jinja'), ('css+erb', 'CSS+Ruby'), ('css+genshitext', 'CSS+Genshi Text'), ('css+lasso', 'CSS+Lasso'), ('css+mako', 'CSS+Mako'), ('css+mozpreproc', 'CSS+mozpreproc'), ('css+myghty', 'CSS+Myghty'), ('css+php', 'CSS+PHP'), ('css+smarty', 'CSS+Smarty'), ('cucumber', 'Gherkin'), ('cuda', 'CUDA'), ('cypher', 'Cypher'), ('cython', 'Cython'), ('d', 'D'), ('d-objdump', 'd-objdump'), ('dart', 'Dart'), ('delphi', 'Delphi'), ('dg', 'dg'), ('diff', 'Diff'), ('django', 'Django/Jinja'), ('docker', 'Docker'), ('doscon', 'MSDOS Session'), ('dpatch', 'Darcs Patch'), ('dtd', 'DTD'), ('duel', 'Duel'), ('dylan', 'Dylan'), ('dylan-console', 'Dylan session'), ('dylan-lid', 'DylanLID'), ('earl-grey', 'Earl Grey'), ('easytrieve', 'Easytrieve'), ('ebnf', 'EBNF'), ('ec', 'eC'), ('ecl', 'ECL'), ('eiffel', 'Eiffel'), ('elixir', 'Elixir'), ('elm', 'Elm'), ('emacs', 'EmacsLisp'), ('erb', 'ERB'), ('erl', 'Erlang erl session'), ('erlang', 'Erlang'), ('evoque', 'Evoque'), ('extempore', 'xtlang'), ('ezhil', 'Ezhil'), ('factor', 'Factor'), ('fan', 'Fantom'), ('fancy', 'Fancy'), ('felix', 'Felix'), ('fish', 'Fish'), ('flatline', 'Flatline'), ('forth', 'Forth'), ('fortran', 'Fortran'), ('fortranfixed', 'FortranFixed'), ('foxpro', 'FoxPro'), ('fsharp', 'FSharp'), ('gap', 'GAP'), ('gas', 'GAS'), ('genshi', 'Genshi'), ('genshitext', 'Genshi Text'), ('glsl', 'GLSL'), ('gnuplot', 'Gnuplot'), ('go', 'Go'), ('golo', 'Golo'), ('gooddata-cl', 'GoodData-CL'), ('gosu', 'Gosu'), ('groff', 'Groff'), ('groovy', 'Groovy'), ('gst', 'Gosu Template'), ('haml', 'Haml'), ('handlebars', 'Handlebars'), ('haskell', 'Haskell'), ('haxeml', 'Hxml'), ('hexdump', 'Hexdump'), ('hsail', 'HSAIL'), ('html', 'HTML'), ('html+cheetah', 'HTML+Cheetah'), ('html+django', 'HTML+Django/Jinja'), ('html+evoque', 'HTML+Evoque'), ('html+genshi', 'HTML+Genshi'), ('html+handlebars', 'HTML+Handlebars'), ('html+lasso', 'HTML+Lasso'), ('html+mako', 'HTML+Mako'), ('html+myghty', 'HTML+Myghty'), ('html+ng2', 'HTML + Angular2'), ('html+php', 'HTML+PHP'), ('html+smarty', 'HTML+Smarty'), ('html+twig', 'HTML+Twig'), ('html+velocity', 'HTML+Velocity'), ('http', 'HTTP'), ('hx', 'Haxe'), ('hybris', 'Hybris'), ('hylang', 'Hy'), ('i6t', 'Inform 6 template'), ('idl', 'IDL'), ('idris', 'Idris'), ('iex', 'Elixir iex session'), ('igor', 'Igor'), ('inform6', 'Inform 6'), ('inform7', 'Inform 7'), ('ini', 'INI'), ('io', 'Io'), ('ioke', 'Ioke'), ('irc', 'IRC logs'), ('isabelle', 'Isabelle'), ('j', 'J'), ('jags', 'JAGS'), ('jasmin', 'Jasmin'), ('java', 'Java'), ('javascript+mozpreproc', 'Javascript+mozpreproc'), ('jcl', 'JCL'), ('jlcon', 'Julia console'), ('js', 'JavaScript'), ('js+cheetah', 'JavaScript+Cheetah'), ('js+django', 'JavaScript+Django/Jinja'), ('js+erb', 'JavaScript+Ruby'), ('js+genshitext', 'JavaScript+Genshi Text'), ('js+lasso', 'JavaScript+Lasso'), ('js+mako', 'JavaScript+Mako'), ('js+myghty', 'JavaScript+Myghty'), ('js+php', 'JavaScript+PHP'), ('js+smarty', 'JavaScript+Smarty'), ('jsgf', 'JSGF'), ('json', 'JSON'), ('json-object', 'JSONBareObject'), ('jsonld', 'JSON-LD'), ('jsp', 'Java Server Page'), ('julia', 'Julia'), ('juttle', 'Juttle'), ('kal', 'Kal'), ('kconfig', 'Kconfig'), ('koka', 'Koka'), ('kotlin', 'Kotlin'), ('lagda', 'Literate Agda'), ('lasso', 'Lasso'), ('lcry', 'Literate Cryptol'), ('lean', 'Lean'), ('less', 'LessCss'), ('lhs', 'Literate Haskell'), ('lidr', 'Literate Idris'), ('lighty', 'Lighttpd configuration file'), ('limbo', 'Limbo'), ('liquid', 'liquid'), ('live-script', 'LiveScript'), ('llvm', 'LLVM'), ('logos', 'Logos'), ('logtalk', 'Logtalk'), ('lsl', 'LSL'), ('lua', 'Lua'), ('make', 'Makefile'), ('mako', 'Mako'), ('maql', 'MAQL'), ('mask', 'Mask'), ('mason', 'Mason'), ('mathematica', 'Mathematica'), ('matlab', 'Matlab'), ('matlabsession', 'Matlab session'), ('md', 'markdown'), ('minid', 'MiniD'), ('modelica', 'Modelica'), ('modula2', 'Modula-2'), ('monkey', 'Monkey'), ('monte', 'Monte'), ('moocode', 'MOOCode'), ('moon', 'MoonScript'), ('mozhashpreproc', 'mozhashpreproc'), ('mozpercentpreproc', 'mozpercentpreproc'), ('mql', 'MQL'), ('mscgen', 'Mscgen'), ('mupad', 'MuPAD'), ('mxml', 'MXML'), ('myghty', 'Myghty'), ('mysql', 'MySQL'), ('nasm', 'NASM'), ('ncl', 'NCL'), ('nemerle', 'Nemerle'), ('nesc', 'nesC'), ('newlisp', 'NewLisp'), ('newspeak', 'Newspeak'), ('ng2', 'Angular2'), ('nginx', 'Nginx configuration file'), ('nim', 'Nimrod'), ('nit', 'Nit'), ('nixos', 'Nix'), ('nsis', 'NSIS'), ('numpy', 'NumPy'), ('nusmv', 'NuSMV'), ('objdump', 'objdump'), ('objdump-nasm', 'objdump-nasm'), ('objective-c', 'Objective-C'), ('objective-c++', 'Objective-C++'), ('objective-j', 'Objective-J'), ('ocaml', 'OCaml'), ('octave', 'Octave'), ('odin', 'ODIN'), ('ooc', 'Ooc'), ('opa', 'Opa'), ('openedge', 'OpenEdge ABL'), ('pacmanconf', 'PacmanConf'), ('pan', 'Pan'), ('parasail', 'ParaSail'), ('pawn', 'Pawn'), ('perl', 'Perl'), ('perl6', 'Perl6'), ('php', 'PHP'), ('pig', 'Pig'), ('pike', 'Pike'), ('pkgconfig', 'PkgConfig'), ('plpgsql', 'PL/pgSQL'), ('postgresql', 'PostgreSQL SQL dialect'), ('postscript', 'PostScript'), ('pot', 'Gettext Catalog'), ('pov', 'POVRay'), ('powershell', 'PowerShell'), ('praat', 'Praat'), ('prolog', 'Prolog'), ('properties', 'Properties'), ('protobuf', 'Protocol Buffer'), ('ps1con', 'PowerShell Session'), ('psql', 'PostgreSQL console (psql)'), ('pug', 'Pug'), ('puppet', 'Puppet'), ('py3tb', 'Python 3.0 Traceback'), ('pycon', 'Python console session'), ('pypylog', 'PyPy Log'), ('pytb', 'Python Traceback'), ('python', 'Python'), ('python3', 'Python 3'), ('qbasic', 'QBasic'), ('qml', 'QML'), ('qvto', 'QVTO'), ('racket', 'Racket'), ('ragel', 'Ragel'), ('ragel-c', 'Ragel in C Host'), ('ragel-cpp', 'Ragel in CPP Host'), ('ragel-d', 'Ragel in D Host'), ('ragel-em', 'Embedded Ragel'), ('ragel-java', 'Ragel in Java Host'), ('ragel-objc', 'Ragel in Objective C Host'), ('ragel-ruby', 'Ragel in Ruby Host'), ('raw', 'Raw token data'), ('rb', 'Ruby'), ('rbcon', 'Ruby irb session'), ('rconsole', 'RConsole'), ('rd', 'Rd'), ('rebol', 'REBOL'), ('red', 'Red'), ('redcode', 'Redcode'), ('registry', 'reg'), ('resource', 'ResourceBundle'), ('rexx', 'Rexx'), ('rhtml', 'RHTML'), ('rnc', 'Relax-NG Compact'), ('roboconf-graph', 'Roboconf Graph'), ('roboconf-instances', 'Roboconf Instances'), ('robotframework', 'RobotFramework'), ('rql', 'RQL'), ('rsl', 'RSL'), ('rst', 'reStructuredText'), ('rts', 'TrafficScript'), ('rust', 'Rust'), ('sas', 'SAS'), ('sass', 'Sass'), ('sc', 'SuperCollider'), ('scala', 'Scala'), ('scaml', 'Scaml'), ('scheme', 'Scheme'), ('scilab', 'Scilab'), ('scss', 'SCSS'), ('shen', 'Shen'), ('silver', 'Silver'), ('slim', 'Slim'), ('smali', 'Smali'), ('smalltalk', 'Smalltalk'), ('smarty', 'Smarty'), ('sml', 'Standard ML'), ('snobol', 'Snobol'), ('snowball', 'Snowball'), ('sourceslist', 'Debian Sourcelist'), ('sp', 'SourcePawn'), ('sparql', 'SPARQL'), ('spec', 'RPMSpec'), ('splus', 'S'), ('sql', 'SQL'), ('sqlite3', 'sqlite3con'), ('squidconf', 'SquidConf'), ('ssp', 'Scalate Server Page'), ('stan', 'Stan'), ('stata', 'Stata'), ('swift', 'Swift'), ('swig', 'SWIG'), ('systemverilog', 'systemverilog'), ('tads3', 'TADS 3'), ('tap', 'TAP'), ('tasm', 'TASM'), ('tcl', 'Tcl'), ('tcsh', 'Tcsh'), ('tcshcon', 'Tcsh Session'), ('tea', 'Tea'), ('termcap', 'Termcap'), ('terminfo', 'Terminfo'), ('terraform', 'Terraform'), ('tex', 'TeX'), ('text', 'Text only'), ('thrift', 'Thrift'), ('todotxt', 'Todotxt'), ('trac-wiki', 'MoinMoin/Trac Wiki markup'), ('treetop', 'Treetop'), ('ts', 'TypeScript'), ('tsql', 'Transact-SQL'), ('turtle', 'Turtle'), ('twig', 'Twig'), ('typoscript', 'TypoScript'), ('typoscriptcssdata', 'TypoScriptCssData'), ('typoscripthtmldata', 'TypoScriptHtmlData'), ('urbiscript', 'UrbiScript'), ('vala', 'Vala'), ('vb.net', 'VB.net'), ('vcl', 'VCL'), ('vclsnippets', 'VCLSnippets'), ('vctreestatus', 'VCTreeStatus'), ('velocity', 'Velocity'), ('verilog', 'verilog'), ('vgl', 'VGL'), ('vhdl', 'vhdl'), ('vim', 'VimL'), ('wdiff', 'WDiff'), ('whiley', 'Whiley'), ('x10', 'X10'), ('xml', 'XML'), ('xml+cheetah', 'XML+Cheetah'), ('xml+django', 'XML+Django/Jinja'), ('xml+erb', 'XML+Ruby'), ('xml+evoque', 'XML+Evoque'), ('xml+lasso', 'XML+Lasso'), ('xml+mako', 'XML+Mako'), ('xml+myghty', 'XML+Myghty'), ('xml+php', 'XML+PHP'), ('xml+smarty', 'XML+Smarty'), ('xml+velocity', 'XML+Velocity'), ('xquery', 'XQuery'), ('xslt', 'XSLT'), ('xtend', 'Xtend'), ('xul+mozpreproc', 'XUL+mozpreproc'), ('yaml', 'YAML'), ('yaml+jinja', 'YAML+Jinja'), ('zephir', 'Zephir')], default='python', max_length=100)), 28 | ('style', models.CharField(choices=[('abap', 'abap'), ('algol', 'algol'), ('algol_nu', 'algol_nu'), ('arduino', 'arduino'), ('autumn', 'autumn'), ('borland', 'borland'), ('bw', 'bw'), ('colorful', 'colorful'), ('default', 'default'), ('emacs', 'emacs'), ('friendly', 'friendly'), ('fruity', 'fruity'), ('igor', 'igor'), ('lovelace', 'lovelace'), ('manni', 'manni'), ('monokai', 'monokai'), ('murphy', 'murphy'), ('native', 'native'), ('paraiso-dark', 'paraiso-dark'), ('paraiso-light', 'paraiso-light'), ('pastie', 'pastie'), ('perldoc', 'perldoc'), ('rainbow_dash', 'rainbow_dash'), ('rrt', 'rrt'), ('tango', 'tango'), ('trac', 'trac'), ('vim', 'vim'), ('vs', 'vs'), ('xcode', 'xcode')], default='friendly', max_length=100)), 29 | ('highlighted', models.TextField()), 30 | ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='snippets', to=settings.AUTH_USER_MODEL)), 31 | ], 32 | options={ 33 | 'ordering': ('created',), 34 | }, 35 | ), 36 | ] 37 | -------------------------------------------------------------------------------- /tutorial/snippets/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/tutorial/snippets/migrations/__init__.py -------------------------------------------------------------------------------- /tutorial/snippets/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from pygments.lexers import get_all_lexers 3 | from pygments.styles import get_all_styles 4 | from pygments.lexers import get_lexer_by_name 5 | from pygments.formatters.html import HtmlFormatter 6 | from pygments import highlight 7 | 8 | LEXERS = [item for item in get_all_lexers() if item[1]] 9 | LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS]) 10 | STYLE_CHOICES = sorted((item, item) for item in get_all_styles()) 11 | 12 | 13 | class Snippet(models.Model): 14 | created = models.DateTimeField(auto_now_add=True) 15 | title = models.CharField(max_length=100, blank=True, default='') 16 | code = models.TextField() 17 | linenos = models.BooleanField(default=False) 18 | language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100) 19 | style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100) 20 | owner = models.ForeignKey('auth.User', related_name='snippets') 21 | highlighted = models.TextField() 22 | 23 | class Meta: 24 | ordering = ('created',) 25 | 26 | def save(self, *args, **kwargs): 27 | lexer = get_lexer_by_name(self.language) 28 | linenos = self.linenos and 'table' or False 29 | options = self.title and {'title': self.title} or {} 30 | formatter = HtmlFormatter(style=self.style, linenos=linenos, 31 | full=True, **options) 32 | self.highlighted = highlight(self.code, lexer, formatter) 33 | super(Snippet, self).save(*args, **kwargs) 34 | -------------------------------------------------------------------------------- /tutorial/snippets/permissions.py: -------------------------------------------------------------------------------- 1 | from rest_framework import permissions 2 | 3 | 4 | class IsOwnerOrReadOnly(permissions.BasePermission): 5 | def has_object_permission(self, request, view, obj): 6 | if request.method in permissions.SAFE_METHODS: 7 | return True 8 | 9 | return obj.owner == request.user 10 | -------------------------------------------------------------------------------- /tutorial/snippets/serializers.py: -------------------------------------------------------------------------------- 1 | from django.forms import widgets 2 | from rest_framework import serializers 3 | from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES 4 | 5 | from django.contrib.auth.models import User 6 | 7 | class SnippetSerializer(serializers.HyperlinkedModelSerializer): 8 | owner = serializers.ReadOnlyField(source='owner.username') 9 | highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html') 10 | 11 | class Meta: 12 | model = Snippet 13 | fields = ('url', 'highlight', 'owner', 14 | 'title', 'code', 'linenos', 'language', 'style') 15 | 16 | 17 | class UserSerializer(serializers.HyperlinkedModelSerializer): 18 | snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True) 19 | 20 | class Meta: 21 | model = User 22 | fields = ('url', 'username', 'snippets') -------------------------------------------------------------------------------- /tutorial/snippets/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /tutorial/snippets/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url, include 2 | from snippets import views 3 | from rest_framework.routers import DefaultRouter 4 | 5 | router = DefaultRouter() 6 | router.register(r'snippets', views.SnippetViewSet) 7 | router.register(r'users', views.UserViewSet) 8 | 9 | urlpatterns = [ 10 | url(r'^', include(router.urls)), 11 | url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')) 12 | ] -------------------------------------------------------------------------------- /tutorial/snippets/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User 2 | from rest_framework import permissions 3 | from rest_framework import renderers 4 | from rest_framework.decorators import api_view 5 | from rest_framework.response import Response 6 | from rest_framework.reverse import reverse 7 | 8 | from snippets.models import Snippet 9 | from snippets.permissions import IsOwnerOrReadOnly 10 | from snippets.serializers import SnippetSerializer 11 | from snippets.serializers import UserSerializer 12 | 13 | 14 | @api_view(('GET',)) 15 | def api_root(request, format=None): 16 | return Response({ 17 | 'users': reverse('user-list', request=request, format=format), 18 | 'snippets': reverse('snippet-list', request=request, format=format) 19 | }) 20 | 21 | 22 | from rest_framework import viewsets 23 | 24 | 25 | class UserViewSet(viewsets.ReadOnlyModelViewSet): 26 | queryset = User.objects.all() 27 | serializer_class = UserSerializer 28 | 29 | 30 | from rest_framework.decorators import detail_route 31 | 32 | 33 | class SnippetViewSet(viewsets.ModelViewSet): 34 | """ 35 | 이 뷰셋은 `list`와 `create`, `retrieve`, `update`, 'destroy` 기능을 자동으로 지원합니다 36 | 37 | 여기에 `highlight` 기능의 코드만 추가로 작성했습니다 38 | """ 39 | queryset = Snippet.objects.all() 40 | serializer_class = SnippetSerializer 41 | permission_classes = (permissions.IsAuthenticatedOrReadOnly, 42 | IsOwnerOrReadOnly,) 43 | 44 | @detail_route(renderer_classes=[renderers.StaticHTMLRenderer]) 45 | def highlight(self, request, *args, **kwargs): 46 | snippet = self.get_object() 47 | return Response(snippet.highlighted) 48 | 49 | def perform_create(self, serializer): 50 | serializer.save(owner=self.request.user) 51 | -------------------------------------------------------------------------------- /tutorial/tutorial/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KimDoKy/DjangoRestFramework-Tutorial/170713f1938ca6d93fcdbbf07238cee0540b73ad/tutorial/tutorial/__init__.py -------------------------------------------------------------------------------- /tutorial/tutorial/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for tutorial project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.10.6. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.10/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.10/ref/settings/ 11 | """ 12 | import json 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | ROOT_DIR = os.path.dirname(BASE_DIR) 18 | CONF_DIR = os.path.join(ROOT_DIR, '.conf') 19 | CONFFILES_URL = os.path.join(CONF_DIR, 'settings_local.json') 20 | config = json.loads(open(CONFFILES_URL).read()) 21 | 22 | SECRET_KEY = config["django"]["secret_key"] 23 | 24 | DEBUG = True 25 | 26 | ALLOWED_HOSTS = [] 27 | 28 | REST_FRAMEWORK = { 29 | 'PAGE_SIZE': 10 30 | } 31 | 32 | INSTALLED_APPS = [ 33 | 'django.contrib.admin', 34 | 'django.contrib.auth', 35 | 'django.contrib.contenttypes', 36 | 'django.contrib.sessions', 37 | 'django.contrib.messages', 38 | 'django.contrib.staticfiles', 39 | 'rest_framework', 40 | 'snippets', 41 | ] 42 | 43 | MIDDLEWARE = [ 44 | 'django.middleware.security.SecurityMiddleware', 45 | 'django.contrib.sessions.middleware.SessionMiddleware', 46 | 'django.middleware.common.CommonMiddleware', 47 | 'django.middleware.csrf.CsrfViewMiddleware', 48 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 49 | 'django.contrib.messages.middleware.MessageMiddleware', 50 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 51 | ] 52 | 53 | ROOT_URLCONF = 'tutorial.urls' 54 | 55 | TEMPLATES = [ 56 | { 57 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 58 | 'DIRS': [], 59 | 'APP_DIRS': True, 60 | 'OPTIONS': { 61 | 'context_processors': [ 62 | 'django.template.context_processors.debug', 63 | 'django.template.context_processors.request', 64 | 'django.contrib.auth.context_processors.auth', 65 | 'django.contrib.messages.context_processors.messages', 66 | ], 67 | }, 68 | }, 69 | ] 70 | 71 | WSGI_APPLICATION = 'tutorial.wsgi.application' 72 | 73 | # Database 74 | # https://docs.djangoproject.com/en/1.10/ref/settings/#databases 75 | 76 | DATABASES = { 77 | 'default': { 78 | 'ENGINE': 'django.db.backends.sqlite3', 79 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 80 | } 81 | } 82 | 83 | # Password validation 84 | # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators 85 | 86 | AUTH_PASSWORD_VALIDATORS = [ 87 | { 88 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 89 | }, 90 | { 91 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 92 | }, 93 | { 94 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 95 | }, 96 | { 97 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 98 | }, 99 | ] 100 | 101 | # Internationalization 102 | # https://docs.djangoproject.com/en/1.10/topics/i18n/ 103 | 104 | LANGUAGE_CODE = 'en-us' 105 | 106 | TIME_ZONE = 'UTC' 107 | 108 | USE_I18N = True 109 | 110 | USE_L10N = True 111 | 112 | USE_TZ = True 113 | 114 | # Static files (CSS, JavaScript, Images) 115 | # https://docs.djangoproject.com/en/1.10/howto/static-files/ 116 | 117 | STATIC_URL = '/static/' 118 | -------------------------------------------------------------------------------- /tutorial/tutorial/urls.py: -------------------------------------------------------------------------------- 1 | """tutorial URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.10/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url, include 17 | from django.contrib import admin 18 | 19 | urlpatterns = [ 20 | url(r'^admin/', admin.site.urls), 21 | url(r'^', include('snippets.urls')), 22 | ] 23 | -------------------------------------------------------------------------------- /tutorial/tutorial/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for tutorial project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tutorial.settings") 15 | 16 | application = get_wsgi_application() 17 | --------------------------------------------------------------------------------