당신은 멋쟁이, 우리는 장고쟁이~

0%

Status Codes


HTTP 요청에대한 상태를 표시하는 상태 코드들이 존재합니다. 숫자로된 HTTP 상태 코드들을 당신의 view 에서 사용하는것은, 언제나 명확하게 읽혀지지 않습니다. 그리고, 만약 당신이 틀린 에러 코드를 갖게되더라도, 알아채기 쉽지 않습니다.


따라서, REST framework 은 조금 더 명확한 식별자들을 각 상태 코드에 부여합니다. status 모듈안에 있는, HTTP_400_BAD_REQUEST 같이 말이죠.


숫자로 된 식별자들을 사용하는것보다, 이러한 RESTFramework 에서 제공하는 좀 더 명시적인 식별자들을 사용하는것이 더 좋은 생각이 될것 입니다.


Requests and Responses


이제부터 우리는,

진짜로 REST framework 의 주요 사항들을 볼것입니다.

몇가지 필수 사항들을 소개해 봅시다.


Request objects


REST Framework 은 일반 HttpResponse 를 확장하는 Request 객체를 소개하고,

조금 더 유연한 파싱을 제공합니다. Request 객체의 주요 기능은, request.data 속성이고,


이것은, request.POST 와 비슷하지만, Web API 를 작업할때 좀 더 유용합니다.


1
2
3
4
5
6
7
request.POST 
# only handles form data. Only works for 'POST' method
# 폼 데이터만 다루고, 오로지 POST 메서드에만 동작합니다.

request.data
# 임의의 데이터를 다룰수 있고,
# 'POST', 'PUT' 그리고 'PATCH' 메서드들을 위해 동작합니다

Response objects


REST Framework 은 Response 객체도 가지고 있습니다.


이것은, TemplateResponse 의 종류로, 렌더되지 않은 컨텐트와 content negotiation 을 사용하여,


클라이언트에게 반환할 적절한 컨텐트 종류를 결정합니다.


Content Negotiation

동일한 URI 에서 리소스의 서로 다른 버전을 수행하기 위해 사용되는 메커니즘으로,

사용자 에이전트가 사용자에게 제일 잘 맞는것이 무엇인지를 명시할수 있습니다.

예) 문서의 언어, 이미지, 포맷 혹은 콘텐츠 인코딩에 있어서 어떤것이 적절할지를 정함.


1
2
3
return Response(data)
# Renders to content type as requested by the client
# 클라이언트가 요청한 content 종류를 렌더해줌

WEB API 에 첫번째 테스트


샘플 서버를 시작하고, snippets 을 확인해 볼수 있습니다.


Django 개발 서버 구동


1
python manage.py runserver

서버를 실행하고, 다른 터미널에서 서버를 테스트 해볼수 있습니다.


Httpie 설치 및 사용


우리는, 우리가 작성한 API 를 curl 혹은 httpie 를 사용하여 테스트 할수 있습니다.


Httpie 는

파이썬으로 작성된, user-friendly 한 http client 입니다


아래 명령어를 터미널에서 실행하여, httpie 를 설치해 줍니다.


1
pip install httpie

터미널을 열어서, 서버를 실행 시키고, 다른 터미널을 열어서 아래 명령어를 실행합니다.


1
http http://127.0.0.1:8000/snippets/

아래와 같이, 이제까지 생성한 snippets 이 조회가 됩니다.



혹은, 특정 snippet 을 id 를 참조하여 얻을수 있습니다.


1
http http://127.0.0.1:8000/snippets/2


브라우저로 확인하기


위의 방식은 터미널에서 http 방식으로 해당 API 에 접근하여 Json 을 얻었지만.


위의 URL 을 브라우저에서 접속해도, 같은 json 이 표시되는것을 확인할수 있습니다.


Serializer 를 사용하는 Django Views 사용하기


우리의 Serializer 클래스를 사용하는 몇가지 API 뷰들을 어떻게 작성하는지 봅시다.


현재까지 우리는, REST framework 의 그 어떤 다른 기능도 사용하지 않을것입니다. 우리는 그저 일반 Django views 와 같은 views 만 작성해 볼겁니다.


snippets/views.py 파일을 열고, 아래 내용을 추가해 줍니다.


1
2
3
4
5
from django.http import HttpResponse, JsonResponse 
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer

우리 API 의 기본은,

존재하는 모든 snippets 들을 리스팅 하거나, 혹은 새로운 snippet 을 생성하는것입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@csrf_exempt 
def snippet_list(request):
"""
List all code snippets, or create a new snippet.
존재하는 모든 스니펫들을 나열하거나, 혹은 새러운 스니펫을 생성합니다.
"""
if request.method == "GET":
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True)
return JsonResponse(serializer.data, safe=False)

elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = SnippetSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, status=201)
return JsonResponse(serializer.errors, status=400)

우리는 이 views 에 클라이언트로부터 CRSF token 이 없는 POST 방식이 가능해야 하기 때문에,

해당 view 에 csrf_exempt 를 표시해 줍니다.


이것은 보통 원하지 않는 방식이고, REST framework view 는 사실 좀 더 이것보다 민감한것도 사용하기도 합니다. 어쨋거나, 지금은 우리의 목적을 수행 할것입니다.


더 읽어보기 »

ModelSerializer 사용하기


우리의 SnippetSerializer 클래스는 Snippet 모델에 있는 많은 정보를 복제하며 사용하고 있습니다.


Django 가 Form 클래스와 ModelForm 클래스를 제공하는 같은 방식으로,


REST FRAMEWORK 은

Serializer 클래스들과 ModelSerializer 클래스들을 가지고 있습니다.


우리의 Serializer 를 ModelSerializer 를 사용하여, 리펙토링 해봅시다.


snippets/serializers.py 파일을 열고, SnippetSerializer 클래스를 아래와 같이 고쳐줍니다.


1
2
3
4
class SnippetSerializer(serializers.ModelSerializer):
class Meta:
model = Snippet
field = ['id', 'title', 'code', 'linnos', 'language', 'style']

serializers 가 좋은 점중 하나는, serializer 인스턴스 안에 모든 필드들을 검사할수 있다는 점입니다. 이는, representation 을 프린트 해보면 됩니다. Django shell 을 python manage.py shell 을 실행하여 열고, 아래 코드들을 실행 시켜 보세요.


1
2
3
4
5
6
7
8
9
10
In [1]: from snippets.serializers import SnippetSerializer                                                                                                                

In [2]: serializer = SnippetSerializer()

In [3]: print(repr(serializer))
SnippetSerializer():
id = IntegerField(label='ID', read_only=True)
title = CharField(allow_blank=True, max_length=100, required=False)
code = CharField(style={'base_template': 'textarea.html'})
linenos = BooleanField(required=False)

ModelSerializer 클래스는 특별하고 마법같은 일은 하지 않습니다.

그저 Serializer 클래스들을 줄여주는 숏컷일 뿐이라는것을 기억하는것이 좋습니다.

아래 일들만 살짝 줄여줄뿐, 또다른 특별한 메서드는 아닙니다.

  • 자동으로 지정된 필드
  • create() 그리고 update() 메서드의 간단한 기본 구현 가능

Serializer 로 작업하기


Working with Serializers (serializer 로 작업하기)


더 진행 하기 전에, Serializer 클래스를 사용하는데에 친숙해져야 합니다. 연습을 하기 위해서, 아래 명령어를 실행하여 Django shell 에 접속해 봅니다.


1
python manage.py shell

인스턴스 생성


몇가지 모듈을 불러와 놓고, 우리가 사용해볼 몇가지 코드 snippet 을 생성해 봅시다.


1
2
3
4
5
6
7
8
9
10
from snippets.models import Snippet 
from snippets.serializers import SnippetSerializer
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser

snippet = Snippet(code='foo = "bar"\n')
snippet.save()

snippet = Snippet(code='print("hello, world")\n')
snippet.save()

이제 우리는 가지고 놀수 있는 몇가지 snippet 인스턴스들을 가지고 있습니다. 이 인스턴스중 하나를 serializing 하는것을 둘러봅니다


인스턴스 serializing


1
2
3
4
5
6
7
# serializers.py 에 작성된 SnippetSerializer 클래스를 불러오고 
# snippet 인스턴스를 인자로 넣어준다.

In [11]: serializer = SnippetSerializer(snippet)

In [12]: serializer.data
Out[12]: {'id': 2, 'title': '', 'code': 'print("hello, world")\n', 'linenos': False, 'language': 'python', 'style': 'friendly'}

여기서 우리는, 모델 인스턴스를 Python 의 기본 데이터 유형으로 전환하였습니다.


serialization (직렬화) 프로세스를 끝내기 위해서, 데이터를 json 으로 렌더해줍니다


1
2
3
4
In [13]: content = JSONRenderer().render(serializer.data)                                                                                                                 

In [14]: content
Out[14]: b'{"id":2,"title":"","code":"print(\\"hello, world\\")\\n","linenos":false,"language":"python","style":"friendly"}'

Deserializing 하기


deserialization 도 비슷합니다. json 으로 렌더되었던 content 를, BytesIO 로 전환한후에 stream 에 담아줍니다. 이 stream 을 parse 하여, Python 기본 데이터 유형으로 바꿔줍니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
In [15]: import io                                                                                                                                                        

In [16]: stream = io.BytesIO(content)

In [17]: data = JSONParser().parse(stream)

In [18]: data
Out[18]:
{'id': 2,
'title': '',
'code': 'print("hello, world")\n',
'linenos': False,
'language': 'python',
'style': 'friendly'}

그리고 난 후에, 파이썬 기본 데이터 유형을 완벽하게 채워진 객체 인스턴스로 복원 합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
In [19]: serializer = SnippetSerializer(data=data)                                                                                                                        

In [20]: serializer.is_valid()
Out[20]: True

In [21]: serializer.validated_data
Out[21]:
OrderedDict([('title', ''),
('code', 'print("hello, world")'),
('linenos', False),
('language', 'python'),
('style', 'friendly')])

In [22]: serializer.save()
Out[22]: <Snippet: Snippet object (3)>

Django 에서 form class 와 form 인스턴스를 가지고 작업하는것과,

비슷한 점이 많다는것을 눈치 채야 합니다.


공통된 부분은, serializer 를 사용하는 views 를 작성할때 더욱 명확해 질것 입니다.


또한, 모델 인스턴스들 대신에, 쿼리셋들도 직렬화 할수 있습니다. 그렇게 하기 위해서는, 간단하게 many=true 플래그를, serializer 인자에 넣어줍니다.


1
2
3
4
5
In [23]: serializer = SnippetSerializer(Snippet.objects.all(), many=True)                                                                                                 

In [24]: serializer.data
Out[24]: [OrderedDict([('id', 1), ('title', ''), ('code', 'foo = "bar"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 2), ('title', ''), ('code', 'print("hello, world")\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 3), ('title', ''), ('code', 'print("hello, world")'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])]

Serializer Class 생성


Creating a Serializer Class


우리의 web API 를 시작하기 위해서 첫번째로 필요한것은, serializing 그리고 deserializing 하여 snippet 인스턴스들을 json 같은 형태로 재구성 하는 방법을 제공해야 합니다.


Serialization 이란?

직렬화, 또는 시리얼라이제이션 (serialization) 은,

컴퓨터 과학의 데이터 스토리지 문맥에서, 데이터 구조나 객체 상태를 다른 컴퓨터 환경에 저장하고,

나중에 재구성할수 있는 포맷으로 변환하는 과정입니다.


반대로, 일련의 바이트로부터, 데이터 구조를 추출하는 일은 역직렬화 또는 디시리얼라이제이션 (deserialization) 이라고 합니다.


우리는 이것을 Django 의 forms 와 비슷하게 작동하는 serializer 클래스를 선언하여 작업할수 있습니다.


snippet/serializers.py 파일을 생성하고, 아래 내용을 추가해 줍니다.


더 읽어보기 »

Serialization 모델 생성


Creating a model to work with (작업할 모델 생성하기)


이번 튜토리얼의 목적을 위해서, 코드 스니펫을 저장하는 간단한 snippet 모델을 생성하는걸로 시작하겠습니다.


snippet/models.py 파일에서, 아래와 같이 모델을 작성해 줍니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from django.db import models 
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles

LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([item[1][0], item[0] for item in LEXERS])
STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()])

class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)

class Meta:
ordering = ['created']

get_all_lexers 는 순회 가능한 LEXER 들의 정보를 가지고 있고

get_all_styles 는 순회 가능한 style 들의 정보를 가지고 있습니다.


이 두개를 List Comprehension 을 통해, For 문으로 리스트를 만들어 줍니다


모델을 생성해 주었으니, snippet 모델에 대한 첫번재 migrations 을 생성해 줍니다


그리고 나서, 처음으로 데이터베이스와 동기화를 시켜줍니다.


1
2
python manage.py makemigrations 
python manage.py migrate

Django REST Framework


Django REST framework 튜토리얼 문서를 참조하면서. 튜토리얼을 진행해 봅니다.


Introduction (소개)


Django REST FRAMEWORK 를 사용하여, 간단한 pastebin 코드 하이라이팅 웹 API 를 만들어 보는 과정을 담고 있습니다. 진행하는동안, REST Framework 을 만드는 다양한 부분들을 소개합니다.


그리고 어떻게 모든것이 다같이 어울려져서 동작하는지에 대한 전반적인 이해도를 제공할것 입니다.


pastebin 혹은 텍스트 저장 사이트는, 온라인 컨텐트 호스팅 서비스의 종류로.

사용자들은 순수 텍스트를 저장할수 있습니다.

예를들면, 코드 리뷰를 위한 소스코드 스니펫 같은것 입니다.


Django REST FRAMEWORK Tutorial 은 생각보다 깊은 내용을 다룹니다. 빠른 오버뷰만 하시고 싶다면, quickstart 문서를 참조하면 됩니다.


더 읽어보기 »

객체지향 프로그래밍 (Object-Oriented Programming)


객체 지향 프로그래밍 (OOP) 는 프로그램 설계 방법론이자 개념의 일종으로. 특징은 다음과 같습니다.


프로그램을 수많은 ‘객체’ 라는 기본 단위로 나누고, 이 객체들의 상호작용으로 서술하는 방식으로.


객체 - 하나의 역할을 수행하는 메소드와 변수(데이터)의 묶음으로 봅니다.

즉, 개념적으로, 객체 = 메소드 + 변수 (데이터) 형태를 가집니다.


파이썬에서는 모든것이 객체로, 파이썬은 객체지향 언어의 대표적인 언어중 하나입니다.


절차적 프로그래밍


초기에 나온 프로그래밍 방식은, 절차 지향 혹은 절차적 프로그래밍으로. 명시된 순서대로 입력을 처리한다음, 결과를 내어주는 식으로 프로그램이 짜여 졌었습니다.


프로그램을 명령어들의 모음으로 인식하는것이 지배적이었으며. 프로그램의 기능에 더 치중하였고.


어떤 데이터를 취급할지에 대한 고민은 상대적으로 적게 하였습니다.


이 절차적 프로그래밍의 단점은 시간이 지나면서 부각되어 오기 시작하였는데.. 특히, 프로그램이 복잡해지면 질수록 드러나는 대표적인 단점은 아래와 같습니다.


  1. 프로그램이 복잡해 지면, 너무 많은 절차와 명령어들로 인해서 코드가 엉망이 될수가 있다
  2. 코드가 엉망이 되면, 유지보수가 힘들어 진다
  3. 프로그램 흐름을 파악하기가 힘들어 진다
  4. 네임스페이스 (이름공간) 구분이 어려워 진다
  5. 중복된 코드를 사용하게 될수 있다
  6. 함수를 통해 구조화는 가능하지만, 이는 데이터를 구조화 시킬수는 없다

이러한 단점들을 보안하기 위해서 나타난것이 바로 객체 지향 프로그래밍으로. 객체라는 작은 단위들로 쪼갠다음, 이 객체들을 조합하여 큰 문제도 해결할수 있는 방식으로 생각하여 만들어 졌습니다.


만들어진 객체는, 작은 문제들을 효과적으로 그리고 확실하게 해결할수 있는 단위들로. 한번 잘 만들어지면. 재사용할수 있다는점이 가장 큰 장점 입니다.


주요 특징


1. Encapulation (캡슐화)


변수와 함수를 하나의 단위로 묶는것을 의미. 데이터의 번들링으로. 보통 객체 지향 프로그래밍을 지원하는 언어들에서 class 라는 형태로 제공됩니다.


해당 클래스에 대한 인스턴스를 생성하고, 클래스에 포함된 변수와 메서드에 쉽게 접근할수 있습니다.


파이썬에서도, class 를 통해 인스턴스를 생성하고, 해당 클래스에 포함된 변수와 메서드에 접근할수 있습니다.


2. inheritance (상속)


상속은 자식 클래스가 부모 클래스의 특성과 기능을 물려받는 것을 의미합니다.


자식 클래스에서, 부모에게서 물려받은 기능을 약간 수정하여 다시 정의할수 있는데. 이를 override, overriding 이라고 부릅니다.


장점과 단점


장점


  • 아주 복잡한 프로그램일 경우, 절차 지향 프로그래밍 보다는 상대적으로 코드가 간결할수 있습니다
  • 상속 개념을 너무 남발하는 경우가 아니고, 간결하고 명확하게 코드를 작성할 경우, 유지 보수가 용이해 질수 있습니다
  • 네임스페이스 (이름공간) 구분이 용이해 질수 있습니다
  • 코드의 재사용성을 높이고, 중복된 코드를 피할수 있습니다

단점


  • 데이터 클래스의 상속이라는 개념은 뛰어나지만, 복잡한 특성을 지니게 해줍니다. 코드의 난이도가 어려워지는 함정이 존재합니다. 다중 상속을 할 경우, 코드 흐름을 파악하기 어려워지고, 복잡한 상속은 코드 분석을 매우 어렵게 합니다
  • 캡슐화와 객체 구조 설계로 인해서 프로그램 성능이 하락할수 있습니다. 객체들간 상호 작용을 하기 위한 호출, 계산식 중간에 포인터 연산들이 더 들어가야 하고, 상호 작용을 위해서 어느 객체의 함수인지 지정해야 하기 때문에, 절차적 프로그래밍 보다는 프로그램이 무거워 질수 있습니다
  • 이해하기가 어렵습니다. 특히 프로그래밍을 처음 접하는 상황에서는, 클래스와 객체 등, OOP 개념 이해조차 하기 힘듭니다. 클래스를 보통 붕어빵 틀로 설명을 하는데.. 학습을 어느정도 해도 이해하기 힘든 개념으로, 많은 프로그래머를 지향하는 사람들이 부딪히는 난관이 될수 있습니다.