'Programming > Python' 카테고리의 다른 글
Jupyter Notebook Add library(노트북에서 내가 쓸려는 library가 없을때 추가하는 방법) (0) | 2016.11.23 |
---|---|
*args 이해하기 (0) | 2016.05.22 |
Jupyter Notebook Add library(노트북에서 내가 쓸려는 library가 없을때 추가하는 방법) (0) | 2016.11.23 |
---|---|
*args 이해하기 (0) | 2016.05.22 |
API를 만들면서 많은 삽질이 있었지만 그중에서 가장 삽질을 많이했던 부분이 있다.
API로 image upload 테스트를 해볼라면 어떻게?
이 포스트는 이걸 나중에 까먹더라도 쉽게 찾아보기 위해 작성한다.
일단, 클라이언트랑 JWT
를 사용해서 통신을 한다는 가정하에 시나리오를 짜보자.
setUp
에서 signup
, login
을 해서 assertEqual
, aseertTrue
로 token값을 얻어낸다.test_data
를 만들어준다. 이때 image는 media
저장 경로에 있는걸 가지고 온다.HTTP_AUTHORIZATION
에 JWT
값을 넣고 API 테스트assertEqual
로 status_code랑 값 비교대략 적인 시나리오를 이렇게 진행했다.
Demo Code를 보기전에 API로 Image를 테스트 할려고 하면 SimpleUploadedFile
를 이용한다.
실제로 HTML Form에서 파일을 보낼때 request.FILES
를 찍어보면 InMemoryUploadedFile
로 넘어온다. 이렇게 HTML Form에서 보내는거 처럼 하기 위해서 SimpleUploadedFile
를 사용하면 된다.
Django ImageField Upload를 AWS S3해보자 (0) | 2016.07.15 |
---|---|
honcho start using port (0) | 2016.07.07 |
JWT 설명 및 djangorestframework-jwt 사용법 (0) | 2016.07.07 |
Django Study Summary (0) | 2016.07.02 |
Django development Setting (0) | 2016.05.24 |
이 포스팅에서는
Django
에서 image를 자동으로 S3에 올리는 과정과 삽질했던 과정을 기록으로 남겨 나중에 쉽게 찾아보기 위해 작성한다. AWS S3, CloudFront에 대한설명은 따로 안할 예정이다.
같이 공부하면서 프로젝트를 진행하는데 Image 저장이라는 난제에 부딪쳤다.
images/<year>/<month>/<day>/<username>/[username-year-month-day.extension]
형식으로 저장이 되야 한다.https
를 사용하기 때문에 https
에 있는 저장장소를 사용한다.그래서 image를 upload하면
위의 형식대로 S3에 자동으로 올라가면서 나중에 CloudFront로 쉽게 땡겨올수 있게 한다.
위 작업이 되기 위해서는 선행되어야 하는 작업이 있다.
CloudeFront
의 경우 생성시 약 10분정도 기다려야 쓸 수 있기 때문에 미리 Distributions
하고 작업을 할것을 권고한다.
일단 Django에서 imageField에 대해서 Documentation을 한번 살펴보자. Django ImageField Documentation
Django에 imageField는 FileField
를 상속받아서 만들어졌다.
imageField같은 경우에는 upload_to
라는 옵션을 이용해서 저장되는 장소를 지정할수가 있다.
uploadto를 사용하기 위해서는 MEDIAROOT, MEDIAURL이 세팅되어 있어야 한다.
아래부분에서 이 MEDIAROOT, MEDIA_URL을 AWS CloudFront주소로 세팅하는걸 알아보겠다.
이 upload_to
라는 옵션에 대한 설명은 공식문서에 아주 잘되어 있다. upload_to documentation
위와같이 폴더 지정뿐만 아니라 %Y/%m/%d
라는 값을 주면 uploads/2016/07/14
라는 폴더로 upload가 된다.
이걸 보고 난 Wow!
를 외치며 작업이 쉬워지는듯 했으나 내가 멍청해서인가 그건 또 아니였다......
그럼 맨처음 생각했던 Format에 대해서 다시한번 생각해보자.
images/<year>/<month>/<day>/<username>/[username-year-month-day.extension]
우리가 하고자 하는건 user
라는 instance
를 매번 새롭게 받아야 한다.
그래서 <username>/[username-year-month-day.extension]
이렇게 되어야 한다.
django upload_to may also be a callable, such as a function
위의 공식문서에 보면 upload_to에 function
를 쓰는 방법을 잘 설명해주고 있다.
upload_to에 function
은 two Arguments
를 받고 Unix-style path (with forward slashes)를 사용한다고 한다.
그래서 우리가 할려고 했던 대로 코드를 짜면 아래와 같다.
user_directory_path
라는 function이 우리가 생각했던 directory를 생성해주는 function이다.
set_filename_format
은 filename을 우리가 지정한대로 바꿔주는 function으로 이름 중복 방지를 위해 microsecond
를 붙였다.
그리고 os.path.splitext(filename)[1]
를 이용하면 해당파일의 확장자를 가지고 올 수가 있다.
여기까지 하면 ImageField의 세팅은 끝이다.
django에서 https
일 경우 staic file을 serving하는 방법은 내가 알기론 2가지 방법이 있다.
여기서는 2번째 방법에 대해서 알아보겠다.
2번째 방법을 하기 위해서 원래 django-storages
라는걸 사용하면 AWS S3에 static file을 쉽게 업로드 할 수가 있다.
근데 이 django-storages
가 중간에 한번 deprecated가 되었다..
그래서 github에서 찾아보면 django-storages
, django-storages-redux
등등 많은 것들이 존재하는데 여기서는 django-storages-redux
라는걸 사용해 보겠다.
공식 문서를 참고하기 바란다.
사용하기 위해서 가상환경에 2가지를 설치해줘야 한다.
pip install boto
pip install django-storages-redux
그러고 나서 설정해주어야 하는게 몇개 있다.
일단 DJANGO_SETTINGS_MODULE
를 devlopment
, production
으로 두개를 나누었다는 전제하에 설명을 진행하겠다.
그리고 production상태에서만 static file이 S3
에 upload되게 하겠다.
wsgi.py
파일이 있는 경로에 storage.py
만들기production.py
에 몇가지 설정 추가하기storage.py
에 위와 같이 추가해준다.
공식문서에 usage
부분을 보면 일단 DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
를 설정하라고 한다.
그 다음에 AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
, AWS_STORAGE_BUCKET_NAME
도 같이 설정해준다.
여기서 ACCESS_KEY
, SECRET_ACCESS_KEY
는 AWS에서 권장하기를 S3에 접근할 수 있는 I AM
계정을 하나 만들어서 진행하는걸 추천한다.
root
계정의 ACCESS_KEY
, SECRET_ACCESS_KEY
를 사용하지 말자.
그리고 우리는 CloudFront
를 사용할것이기 때문에 AWS_S3_CUSTOM_DOMAIN
, AWS_S3_CUSTOM_DOMAIN
도 같이 추가 해준다.
최종적으로 production.py
에 담겨야 하는 내용은 아래와 같다.
여기까지 했다면 다 설정을 한것이다.
[django path]/manage.py collectstatic --setings="appname.settings.production"
를 하면 S3로 업로드가 잘 작동할것이다.
ubuntu환경에 대해서 설명을 하겠다.
Django Image Upload API TDD 삽질 여행기 (0) | 2016.07.24 |
---|---|
honcho start using port (0) | 2016.07.07 |
JWT 설명 및 djangorestframework-jwt 사용법 (0) | 2016.07.07 |
Django Study Summary (0) | 2016.07.02 |
Django development Setting (0) | 2016.05.24 |
Django Image Upload API TDD 삽질 여행기 (0) | 2016.07.24 |
---|---|
Django ImageField Upload를 AWS S3해보자 (0) | 2016.07.15 |
JWT 설명 및 djangorestframework-jwt 사용법 (0) | 2016.07.07 |
Django Study Summary (0) | 2016.07.02 |
Django development Setting (0) | 2016.05.24 |
Django Image Upload API TDD 삽질 여행기 (0) | 2016.07.24 |
---|---|
Django ImageField Upload를 AWS S3해보자 (0) | 2016.07.15 |
honcho start using port (0) | 2016.07.07 |
Django Study Summary (0) | 2016.07.02 |
Django development Setting (0) | 2016.05.24 |
Django Image Upload API TDD 삽질 여행기 (0) | 2016.07.24 |
---|---|
Django ImageField Upload를 AWS S3해보자 (0) | 2016.07.15 |
honcho start using port (0) | 2016.07.07 |
JWT 설명 및 djangorestframework-jwt 사용법 (0) | 2016.07.07 |
Django development Setting (0) | 2016.05.24 |
Django Image Upload API TDD 삽질 여행기 (0) | 2016.07.24 |
---|---|
Django ImageField Upload를 AWS S3해보자 (0) | 2016.07.15 |
honcho start using port (0) | 2016.07.07 |
JWT 설명 및 djangorestframework-jwt 사용법 (0) | 2016.07.07 |
Django Study Summary (0) | 2016.07.02 |
함수에 Parameter가 여러개일 경우 함수 argument로 *args
를 사용하면 여러개인 Parameter를 대응할 수 있다.
naming은 임의로 *dog
, *cat
으로 지을수도 있지만, 관례적으로 *args
를 쓰는 편이다.
def test(*args): print(args) >>> num_list = [1, 2, 3] >>> print( test(*num_list) == test(1, 2, 3)) (1, 2, 3) (1, 2, 3) True
궁금중을 정리해보자
test(*num_list) == test(1, 2, 3)
가 어떻게 True
를 반환하는 것인가?*num_list
라고 앞에 *
를 붙였나?그럼 이 2가지 궁금증을 한꺼번에 풀 수 있는 예제를 들어보고자 한다.
일단 test2라는 함수를 만들고 그 함수의 Argument로 a, b, c를 받고 출력하는 간단한 함수를 만들어보면 아래와 같다.
def test2(a, b, c): print(a, b, c)
이 test2라는 함수를 사용하기 위해서는 test2(1, 2, 3)
와 같이 사용할 수 있다.
여기까지는 다른 웬만한 프로그래밍 언어랑 별반 차이가 없어 보인다.
하지만 여기서 Python의 Magic을 부려보자.
그 매직이란게 어떤거냐면 위에서 선언한 num_list
라는 Parameter를 하나만 전달해서 에러없이 test2
를 호출하는 것이다.
어떻게 이게 가능할까?
파이썬에서 Packing, UnPacking이라는 개념을 사용하면 된다.
차근차근 살펴보자
num_list
을 가지고 test2
를 호출할려고 하면 일단 아래와 같이 호출 할 수 있다.
>>> num_list = [1, 2, 3] >>> test2(num_list[0], num_list[1], num_list[2]) print(1, 2, 3)
위와 같이 호출하면 문제없이 호출이 될 것이다.
하지만 위의 예제코드는 pythonic하지 않다.
pythonic하게 Refactoring를 해보면 아래와 같다.
>>> test2(*num_list) print(1, 2, 3)
위와같이 호출하니깐 문제없이 잘 될것이다.
앞에 *
가 붙는게 맨 처음을 test
함수를 호출할때랑 같다.
이 과정을 설명해보자면
test2(*num_list)
로 호출하면 num_list가 unpacking되어서 a=1
, b=2
, c=3
으로 전달되어서 에러 없이 잘 실행되는 것이다.
그럼 *
를 앞에 안붙이고 그냥 test2(num_list)
를 하면 어떻게 될까?
>>> test2(num_list)
TypeError: test2() missing 2 required positional arguments: 'b' and 'c'
당연한 이야기 지만 2개의 필수 Arguments를 전달 안했다고 에러가 난다.
인제 함수를 호출할때 왜 *num_list
라고 쓰는지 이해가 될 것이다.
그럼 인제 맨처음에 생겼던 궁금증을 정리해보자
test(*num_list) == test(1, 2, 3)
가 어떻게 True
를 반환하는 것인가?
test(*num_list
라고 호출할때 *num_list
로 인해 unpacking
이 되어서 전달*args
로 인해 다시 packing
되어서 출력되기 때문에 둘다 출력결과가 같으므로 True
num_list를 그냥 넘기는게 아니라 왜 *num_list
라고 앞에 *
를 붙였나?
unpacking
해서 넘길려고결론적으로 호출할때 unpacking 실행될때 packing이라고 보면 된다.
Jupyter Notebook Add library(노트북에서 내가 쓸려는 library가 없을때 추가하는 방법) (0) | 2016.11.23 |
---|---|
Python textwrapper fill (0) | 2016.08.02 |