React hooks의 useState에서 Spread 응용 메모

useState 를 통해 state 를 다룰 때 단순한 단일의 값이 아닌 배열이나 오브젝트의 형태로 처리하고 싶을 때가 있다.

값을 여럿 늘여써도 결과는 같아도 코드의 가독성이나 관리의 편의성을 생각했을 때 오브젝트로 처리해야 하는 경우가 생긴다.

이 때 ES6에서 추가된 Spread 연산자를 사용한다면 좀더 직관적이고 간편하게 이를 처리할 수 있다.

기본적인 형태는 다음과 같다.

1
2
3
4
5
6
const [state, setState] = useState({
key1: value1,
key2: value2
});
setState({ ...state, key: value });

위와 같은 문법으로 useState 를 사용할 경우 원하는 값을 해당 state object의 내부에 추가하거나 혹은 수정할 수 있다.
Spread 연산자를 이용하여 기존의 state값을 전부 복사한 뒤 직접 명시한 값을 추가(혹은 수정)하는 원리이다. Spread 연산자 없이도 물론 구현이 가능하겠지만 Spread 연산자를 사용하면 코드가 한결 간결해지니 사용하지 않을 이유가 없다.

여기서 추가로 응용을 하고자 한다면

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const [state1, setState1] = useState({});
const [state2, setState2] = useState({});
const [state3, setState3] = useState({});
const [states] = [state1, state2, state3];
const [setStates] = [setState1, setState2, setState3];
states[0]; // state1
// setState3
setStates[2]({
...states[2],
key: value
});

위와 같이 여러개의 오브젝트형 state들을 한 곳에 묶어서 관리할 수도 있다.

django media 파일

이전에 클라이언트로부터 업로드된 이미지에 접근할 수 있는 방법을 찾지 못해 정말 단순무식하게 클라이언트서버측 폴더에

파일을 업로드 시켜서 해결했었던 적이 있다.

개발 서버에서 작업할 때는 위와 같이 해결해도 전혀 문제가 되지 않았지만 실질적으로 외부접속을 테스트하려고

막상 웹서버에 올리려고 하니 당연하게도 문제가 발생할 수 밖에 없었다.

상대경로를 이용하여 클라이언트측 디렉토리에 접근하여 업로드하는 방식이니 서로 다른 서버에 올라가있는 상태로는

정상적으로 동작할 수가 없는게 당연하기 때문

결국 다시 방법을 찾은결과 django 에서 이를 위한 media 파일을 지원하고 있다는걸 알 수 있었다.

static 파일처럼 media 파일도 정적 파일이긴 하지만 media 파일은 웹에서 업로드된 파일로

언제 어떤 파일이 정적 파일로 제공되고 준비되는지 예측할 수 없다는 점이 다르다.

이 방식을 사용함으로 인해 처음 원하던대로 django 서버에서 db와 image파일들을 관리하고 프론트엔드 서버에서

접근하는 구조를 이제서야 완성할 수 있었다.

설정 방법

settings.py 파일에 다음과 같이 media 파일들이 들어갈 실제 경로와 URL을 설정해준다.

1
2
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

그리고 urls.py 파일에 url 패턴을 추가해줘야 한다.

1
2
3
4
5
6
7
8
9
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
url(r'^admin/', admin.site.urls),
...
...
...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

이제 지정한 media 디렉토리 내에 아무거나 이미지파일을 넣어보고

http://서버주소/media/이미지파일명 경로를 입력하여 들어가면 해당 이미지를 확인할 수 있을것이다.






여기서 이전에 사용했던 파일 업로드 코드에서 업로드 될 경로만 media 디렉토리로 지정해주어

원하던 백엔드서버로써의 기능을 수행하는 django 서버의 모습을 만들어주었다.

윈도우에서 Apache로 django구동 관련 메모

[정보 출처]
Windows에서 Apache2.4 + mod_wsgi 설치
django 공식 문서의 mod_wsgi 설정관련

mod_wsgi 설치

Apache 서버에서 Python 기반의 웹 어플리케이션(django)를 가동하려면 mod_wsgi이라는 플러그인을 설치해야 한다.

mod_wsgi 플러그인은 윈도우 32bit 버젼만을 지원한다.

현재 기준으로 릴리즈 사이트의 코멘트를 확인해보면 윈도우에서 사용가능한 최신 버젼은 4.4.12 버젼

apache 서버 설치 후(원글 내용대로 따라한다면 2.4버젼) 내려받은 mod_wsgi 파일의 압축을 풀면 나오는 파일 중

Apache24-win32-VC9 폴더 안에 있는 mod_wsgi-py27-VC9.so 파일을 Apache24/modules 폴더에 복사 후

이름을 간단하게 mod_wsgi.so로 변경

플러그인을 불러오도록 설정파일(httpd.conf)에

1
2
3
#httpd.conf
LoadModule wsgi_module modules/mod_wsgi.so

라고 한 줄 추가하면 설치 완료


mod_wsgi 관련 설정

1
2
3
4
5
6
7
8
9
10
11
#httpd.conf
WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py
WSGIPythonHome /path/to/venv
WSGIPythonPath /path/to/mysite.com
<Directory /path/to/mysite.com/mysite>
<Files wsgi.py>
Require all granted
</Files>
</Directory>

django 프로젝트 디렉토리를 살펴보면 settings.py 파일이 있는 디렉토리에 wsgi.py파일이 있는것을 확인할 수 있다.
WSGIScriptAlias / “이부분” 에 해당 파일의 경로를 파일명과 함께 입력하면 된다.

WSGIPythonHome 에는 python 가상환경의 경로를 입력

WSGIPythonPath 에는 django 프로젝트의 manage.py 파일이 위치해 있는 루트 디렉토리의 경로를 입력하면 된다.

이곳에 입력해야할 경로는 말 그대로 wsgi.py파일이 위치해있는 경로

즉, WSGIScriptAlias 에 입력했던 경로에서 파일명인 wsgi.py만 빼면 된다.

해당 설정을 마치고 아파치 서버를 재기동 시키면 아파치 서버를 통해 django 서버에 접속되는 모습을 확인할 수 있다.

xlsxwriter 기본 사용법 메모

xlsxwriter : python에서 excel을 다룰 수 있게 하는 모듈 중의 하나
(docs 링크)

사용 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import xlsxwriter
workbook = xlsxwriter.Workbook('skill.xlsx')
worksheet = workbook.add_worksheet()
# 직접 셀 위치를 입력
worksheet.write('A1', 'aaa')
worksheet.write('B1', 'bbb')
worksheet.write('C1', 'ccc')
worksheet.write('D1', 'ddd')
# 반복문을 통한 자동 입력
row = 1
col = 0
for a in (data):
worksheet.write(row, col, a.get('...'))
worksheet.write(row, col + 1, a.get('...'))
worksheet.write(row, col + 2, a.get('...'))
worksheet.write(row, col + 3, a.get('...'))
...
row += 1
workbook.close()

javascript로 json 오브젝트 sort

Array.prototype.sort() 라는 함수를 사용하여 json 오브젝트를 정렬 가능

기본 정렬 순서는 문자열 유니 코드 코드 포인트에 따른다.

1
2
arr.sort()
arr.sort(비교 함수)

사용시엔 위와 같은 방식으로 사용 (json은 javascript에서 배열처럼 취급하기 때문에 array의 내장 함수로 정렬)



예시 코드

1
2
3
this.r_ratings.sort(function (a,b){
return(a.USER.toLowerCase() < b.USER.toLowerCase()) ? -1 : (a.USER.toLowerCase() > b.USER.toLowerCase()) ? 1 : 0
})

개발중에 사용했던 코드를 예시로 들면

평가 함수에 사용되는 매개변수인 a, b는 각 현재 행, 다음 행을 뜻한다.

return값에 따라 정렬을 위해 취할 동작이 결정 되는데 각 각
0 : 아무 동작도 하지 않음
1 : 현재 행을 다음 행보다 아래로 정렬
-1 : 현재 행을 다음 행보다 위로 정렬

와 같은 정렬 작업을 수행한다.

에시 코드에선 각 행의 USER라는 값을 전부 소문자로 통일하여 오름차순으로 정렬되도록 비교식을 넣은 모습이다.

react-bootstrap 사용 시 style 덮어쓰는 방법

react 환경에서 bootstrap을 사용하기 위해 npm으로 react-bootstrap을 설치하여 사용하는 도중 사이즈나 정렬방식, 간격 등을 원하는대로 재설정할 필요가 생겼다.

기본적으로 bootstrap에 정의된 css를 따라가기에 style을 직접 덮어씌워야 변경이 가능한데

stack overflow 를 통해 그 방법을 찾을 수 있었다.

1
2
3
4
5
6
7
8
9
10
11
<InputGroup.Addon style={{
width: '20%',
paddingTop: '0',
paddingRight: '0',
paddingBottom: '0',
paddingLeft: '0',
}}>
<FormControl componentClass="select" placeholder="select" style={{width: '100%'}}>
<p style={{textAlign:"right"}}>

위의 코드와 같이 { { } } 로 감싸서 style props에 값을 넘기는 느낌이다.

각 항목의 명칭들이 언뜻 실제 css를 정의하는것과 비슷해보이지만 text-align 같은 속성들은

가운데의 -를 지우고 단어를 대문자로 구분하여 textAlign으로 입력해주어야 한다.

또한 각 값을 구분할때 세미콜론(;)이 아닌 반점(,)으로 구분해주어야 하며 문자열방식으로 입력해주어야 한다.

django csrf 관련 메모

CSRF 공격 관련 상세 설명글 링크

django 공식 문서의 CSRF 관련 항목


그동안 그냥 ajax 요청이 잘 수행되도록 views의 함수앞에 넣었던 데코레이터인

@csrf_exempt

django의 미들웨어가 CSRF 공격으로부터 보호해주는 기능을 적용하지 않도록 하는 데코레이터라는듯 하다.


django는 ajax로 post 요청이 날아왔을때 request.POST 내의 CSRF token이 CSRF cookie와 일치하는치 체크한다.

내가 사용한 방법은 외부의 다른 서버로부터 요청을 보냈기 때문에 이를 확인하지 않도록 @csrf_exempt 데코레이터를 넣어

일단 작업이 수행되도록 한 것.

django 프로젝트 외부 디렉토리 접근방법

Server와 Client 모두 django로 제작한다면 이 방식을 사용할 일이 없다시피 하겠지만

Client측에서 Server쪽의 파일을 직접 접근해야할 필요가 생겨 해결법을 찾을 수 밖에 없었다.

settings.py

1
2
3
4
5
6
...
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
...

settings에 기본적으로 root역할을 할 base 디렉토리 경로가 설정이 되어있는데

그것을 기준으로 바깥쪽의 경로에 접근할 수 있도록 설정할 수 있다.

1
2
3
4
5
6
7
...
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
FILES_DIR = os.path.abspath(os.path.join(BASE_DIR, '../../client/image/'))
...

위와 같이 한줄의 코드를 추가해주고 views.py에서 다음과 같이 접근할 수 있다.

views.py

1
2
3
4
5
6
7
from django.conf import settings
import os
...
file_path = os.path.join(settings.FILES_DIR, 'test_image.png')
image_data = open(file_path, "rb").read()

image파일뿐만 아니라 다른 형식의 파일도 접근 가능하다.


model을 통한 외부 upload

위의 방법은 읽기는 가능하지만 model을 통해 업로드를 시도했을 경우 참조한 경로가

프로젝트의 외부에 존재한다는 오류와 함께 업로드에 실패하게 된다.

따라서 성공적으로 업로드를 하기 위해서는 다음과 같은 방법을 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
from django.conf import settings
import os
from django.core.files.storage import FileSystemStorage
...
class Images(models.Model):
fs = FileSystemStorage(location=settings.FILES_DIR)
image = models.ImageField(upload_to='%Y/%m/%d/orig', storage=fs)
...

upload_to 에 입력할 경로에 settings.FILES_DIR + ‘ … ‘ 같은 방법으로

입력하는 것이 아니라 FileSystemStroage 를 사용하여 위와같이 경로를 입력해주면

settings.FILES_DIR 경로(settings.py에서 지정해준 외부 디렉토리 경로)의

하위 경로에 upload_to의 경로대로 파일을 저장하게 된다.



사족으로 smartfields의 database에서 레코드 제거시 연결된 파일을 추적하여 자동으로 삭제해주는 기능은 이 방식을 사용한경우 작동하지 않는 듯 하다…

  • 2019-01-25 추가
    django 내에서만 업로드된 이미지 파일을 다루는 방법
    django media 파일

smartfields

django 서버에서 이미지 등 파일을 관리할 때 유용

내장모듈인 django.db의 models의 field대신

smartfields를 이용하면 데이터베이스에서 해당 레코드가 지워졌을 때

연결된 파일을 일일히 추적해서 삭제할 필요없이 알아서 삭제해준다.

이미지 필드 사용 예시

1
2
3
4
5
# models
image = models.ImageField(upload_to='%Y/%m/%d/orig')
# smartfields
image = fields.ImageField(upload_to='%Y/%m/%d/orig')

지원되는 필드 타입도 기존에 존재하는 것이 대부분 지원되는 편이고

사용방법도 거의 동일한 느낌